我正在尝试通过测试来验证有状态组件的状态在componentDidMount中是否已适当更改,但由于react-router而遇到了问题.
我正在使用Enzyme,所以我使用mount来评估生命周期方法,例如componentDidMount.通常情况下,这很好……
it("changes state after mount", () => {
const newValue = "new value";
const testPropertyRetriever = () => newValue;
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>
);
// componentDidMount should have executed and changed the state's myProperty value
// from "initial value" to "new value"
expect(wrapper.instance().state.myProperty).toEqual(newValue);
});
…但是有问题的组件是有问题的,因为mount会让几个孩子深入,在这种情况下,其中一个后代使用react-router的< Link>.因此,运行上述测试会导致错误:TypeError:无法读取未定义和失败上下文类型的属性’history’:上下文`router`在`Link`中被标记为必需,但其值为`undefined`.
react-router docs建议将需要上下文的组件(例如,使用react-router的< Link>)与< MemoryRouter>进行测试渲染.或者< StaticRouter>,但这不起作用,因为这会使被测组件成为子而不是ReactWrapper的根,这使得(据我所知)无法检索被测组件的状态. (鉴于以上例子……
// ...
const wrapper = mount(
<MemoryRouter>
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>
</MemoryRouter>
);
expect(wrapper.childAt(0).instance().state.myProperty).toEqual(newValue);
…测试失败并出现错误ReactWrapper :: instance()只能在根目录上调用.
我很快就知道酶的mount采用了一个选项参数,允许将上下文传递给渲染器,这就是路由器需要的反应.所以我尝试删除路由器包含并提供上下文(基于this answer)…
//...
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>,
{ router: { isActive: true } }
);
expect(wrapper.instance().state.myProperty).toEqual(newValue);
…但是这导致了我开始时关于上下文类型的相同错误.要么我没有正确地传递上下文,我不知道如何将上下文传递给需要它的后代,或者没有办法(使用这些工具)这样做.
从这里开始,我一直在寻找有关如何存储上下文或模拟其中一个组件的详细信息,但是没有设法将这些拼图有效地组合在一起以成功编写和运行此测试.
当component具有依赖于满足react-router模块的上下文的后代时,如何验证componentDidMount更改的组件状态?
解决方法:
提供给mount功能的路由器定义不完整.
const MountOptions = {
context: {
router: {
history: {
createHref: (a, b) => {
},
push: () => {
},
replace: () => {
}
}
}
}, childContextTypes: {
router: PropTypes.object
}
};
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>,
MountOptions
);