使用 React、react-router、jest 和 enzyme 测试状态变化
Testing a state change with React, react-router, jest, and enzyme
我正在尝试通过测试验证有状态组件的状态在 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
呈现一对 children 深,在这种情况下,其中一个后代使用 react-router 的 <Link>
。因此,运行ning 上述测试结果出现错误:TypeError: Cannot read property 'history' of undefined
和 Failed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.
react-router docs 建议使用 <MemoryRouter>
或 <StaticRouter>
,但这行不通,因为这使得被测组件成为 child 而不是 ReactWrapper 的根,这使得(据我所知)无法检索组件的状态测试。 (鉴于上面的例子...
// ...
const wrapper = mount(
<MemoryRouter>
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>
</MemoryRouter>
);
expect(wrapper.childAt(0).instance().state.myProperty).toEqual(newValue);
...测试失败并出现错误 ReactWrapper::instance() can only be called on the root
).
我很快了解到酶的 mount
采用一个选项参数,允许将上下文传递到渲染中,这正是 react-router 所需要的。所以我尝试删除路由器遏制并提供上下文(基于 )...
//...
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>,
{ router: { isActive: true } }
);
expect(wrapper.instance().state.myProperty).toEqual(newValue);
...但这会导致与我开始时相同的关于上下文类型的错误。要么我没有正确传递上下文,要么我不知道 如何 将上下文传递给需要它的后代,要么没有办法(使用这些工具) 这样做。
从这里开始,我一直在寻找有关如何存根上下文或模拟其中一个组件的详细信息,但未能有效地将拼图拼凑到足以成功编写和 运行本次测试。
当组件的后代依赖于满足 react-router 模块的上下文时,如何验证由 componentDidMount
更改的组件状态?
提供给挂载函数的路由器定义不完整。
const MountOptions = {
context: {
router: {
history: {
createHref: (a, b) => {
},
push: () => {
},
replace: () => {
}
}
}
}, childContextTypes: {
router: PropTypes.object
}
};
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>,
MountOptions
);
我正在尝试通过测试验证有状态组件的状态在 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
呈现一对 children 深,在这种情况下,其中一个后代使用 react-router 的 <Link>
。因此,运行ning 上述测试结果出现错误:TypeError: Cannot read property 'history' of undefined
和 Failed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.
react-router docs 建议使用 <MemoryRouter>
或 <StaticRouter>
,但这行不通,因为这使得被测组件成为 child 而不是 ReactWrapper 的根,这使得(据我所知)无法检索组件的状态测试。 (鉴于上面的例子...
// ...
const wrapper = mount(
<MemoryRouter>
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>
</MemoryRouter>
);
expect(wrapper.childAt(0).instance().state.myProperty).toEqual(newValue);
...测试失败并出现错误 ReactWrapper::instance() can only be called on the root
).
我很快了解到酶的 mount
采用一个选项参数,允许将上下文传递到渲染中,这正是 react-router 所需要的。所以我尝试删除路由器遏制并提供上下文(基于
//...
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>,
{ router: { isActive: true } }
);
expect(wrapper.instance().state.myProperty).toEqual(newValue);
...但这会导致与我开始时相同的关于上下文类型的错误。要么我没有正确传递上下文,要么我不知道 如何 将上下文传递给需要它的后代,要么没有办法(使用这些工具) 这样做。
从这里开始,我一直在寻找有关如何存根上下文或模拟其中一个组件的详细信息,但未能有效地将拼图拼凑到足以成功编写和 运行本次测试。
当组件的后代依赖于满足 react-router 模块的上下文时,如何验证由 componentDidMount
更改的组件状态?
提供给挂载函数的路由器定义不完整。
const MountOptions = {
context: {
router: {
history: {
createHref: (a, b) => {
},
push: () => {
},
replace: () => {
}
}
}
}, childContextTypes: {
router: PropTypes.object
}
};
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>,
MountOptions
);