[英]Testing a state change with React, react-router, jest, and enzyme
I'm trying to verify with a test that a stateful component's state is appropriately changed in componentDidMount
, but hit a wall due to react-router. 我正在尝试通过测试来验证有状态组件的状态在componentDidMount
是否已适当更改,但由于react-router而遇到了问题。
I'm using Enzyme, so I use mount
in order to evaluate lifecycle methods such as componentDidMount
. 我正在使用Enzyme,所以我使用mount
来评估生命周期方法,例如componentDidMount
。 Typically, this works just fine... 通常情况下,这很好......
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);
});
...but the component in question is problematic because mount
renders a couple children deep, and in this case one of those descendants uses react-router's <Link>
. ...但是有问题的组件是有问题的,因为mount
会让几个孩子深入,在这种情况下,其中一个后代使用react-router的<Link>
。 So, running the above test results in errors: TypeError: Cannot read property 'history' of undefined
and Failed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.
因此,运行上述测试会导致错误: TypeError: Cannot read property 'history' of undefined
和Failed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.
TypeError: Cannot read property 'history' of undefined
Failed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.
The react-router docs recommend surrounding a test render of a component that requires context (for example, uses react-router's <Link>
) with either <MemoryRouter>
or <StaticRouter>
, but that won't work because that makes the component under test a child instead of the root of the ReactWrapper, which makes it impossible (as far as I know) to retrieve the state of the component under test. react-router文档建议将需要上下文的组件(例如,使用react-router的<Link>
)与<MemoryRouter>
或<StaticRouter>
进行测试渲染,但这不起作用,因为这会使组件处于测试一个子而不是ReactWrapper的根,这使得我不可能(据我所知)检索被测组件的状态。 (Given the example above... (鉴于以上例子......
// ...
const wrapper = mount(
<MemoryRouter>
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>
</MemoryRouter>
);
expect(wrapper.childAt(0).instance().state.myProperty).toEqual(newValue);
...the test fails with error ReactWrapper::instance() can only be called on the root
). ...测试失败并出现错误ReactWrapper::instance() can only be called on the root
。
I soon learned that enzyme's mount
takes an options argument that allows for context to be passed into the render, which is what react-router needs. 我很快就知道酶的mount
采用了一个选项参数,允许将上下文传递给渲染器,这就是路由器需要的反应。 So I tried removing the router containment and providing context (based on this answer )... 所以我尝试删除路由器包含并提供上下文(基于此答案 )...
//...
const wrapper = mount(
<StatefulPage
myProperty="initial value"
propertyRetriever={testPropertyRetriever}
/>,
{ router: { isActive: true } }
);
expect(wrapper.instance().state.myProperty).toEqual(newValue);
...but that results in the same errors about context type that I began with. ...但是这导致了我开始时关于上下文类型的相同错误。 Either I'm not passing context in correctly, I don't know how to get the context carried down to the descendant that needs it, or there isn't a way (with these tools) to do so. 要么我没有正确地传递上下文,我不知道如何将上下文传递给需要它的后代,或者没有办法(使用这些工具)这样做。
From here, I've been looking all over for details of how I might stub the context or mock one of the components, but haven't managed to put together the puzzle pieces effectively enough to successfully write and run this test. 从这里开始,我一直在寻找有关如何存储上下文或模拟其中一个组件的详细信息,但是没有设法将这些拼图有效地组合在一起以成功编写和运行此测试。
How can I validate a component's state as changed by componentDidMount
when it has descendants that depend on a context that satisfies react-router modules? 当componentDidMount
具有依赖于满足react-router模块的上下文的后代时,如何验证componentDidMount更改的componentDidMount
状态?
The router definition provided to the mount function was incomplete. 提供给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
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.