使用React,react-router,jest和enzyme测试状态更改

时间:2017-06-22 22:10:59

标签: javascript unit-testing reactjs react-router enzyme

我试图通过测试验证状态组件的状态是否在componentDidMount中得到了适当的更改,但是由于react-router打了一堵墙。

我使用的是酶,因此我使用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&#39; s <Link>。因此,运行上述测试会导致错误:TypeError: Cannot read property 'history' of undefinedFailed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.

react-router docs建议围绕需要上下文的组件的测试呈现(例如,使用react-router&#39; s <Link>)与<MemoryRouter>或{{1}但是,这不会起作用,因为这会使被测组件成为子项而不是ReactWrapper的根,这使得(据我所知)无法检索被测组件的状态。 (鉴于上面的例子......

<StaticRouter>

...测试失败,错误为// ... 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采用了一个选项参数,允许将上下文传递给渲染器,这就是路由器需要的反应。所以我尝试删除路由器包含并提供上下文(基于this answer)...

mount

...但是这导致了与我开始的上下文类型相同的错误。要么我没有正确地传递上下文,我也不知道如何将上下文传递给需要它的后代,或者没有方法(与这些工具)。

从这里开始,我一直在寻找有关如何隐藏上下文或模拟其中一个组件的详细信息,但是我们还没有设法有效地整理拼图,以便成功地编写和运行此测试。

//... const wrapper = mount( <StatefulPage myProperty="initial value" propertyRetriever={testPropertyRetriever} />, { router: { isActive: true } } ); expect(wrapper.instance().state.myProperty).toEqual(newValue); 具有依赖于满足反应路由器模块的上下文的后代时,如何验证组件的状态是否已更改?

1 个答案:

答案 0 :(得分:5)

提供给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
);