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

Mat*_*att 3 javascript unit-testing reactjs react-router 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);
});
Run Code Online (Sandbox Code Playgroud)

...但是有问题的组件是有问题的,因为mount深层渲染了几个孩子,在这种情况下,其中一个后代使用react-router <Link>.因此,运行上述测试会导致错误:TypeError: Cannot read property 'history' of undefinedFailed context type: The context `router` is marked as required in `Link`, but its value is `undefined`.

反应路由器文档推荐周围的一个测试渲染,需要上下文的组件(例如,使用反应-路由器<Link>)与任一<MemoryRouter><StaticRouter>,但是这是行不通的,因为这使得该组件测试的,而不是根目录的孩子ReactWrapper,它使我无法(据我所知)检索被测组件的状态.(鉴于以上例子......

// ...
const wrapper = mount(
  <MemoryRouter>
    <StatefulPage
      myProperty="initial value"
      propertyRetriever={testPropertyRetriever}
    />
  </MemoryRouter>
);

expect(wrapper.childAt(0).instance().state.myProperty).toEqual(newValue);
Run Code Online (Sandbox Code Playgroud)

...测试失败并出现错误ReactWrapper::instance() can only be called on the root).

我很快就知道酶的mount选择参数允许将上下文传递给渲染器,这就是路由器需要的反应.所以我尝试删除路由器包含并提供上下文(基于此答案)...

//...
const wrapper = mount(
  <StatefulPage
    myProperty="initial value"
    propertyRetriever={testPropertyRetriever}
  />,
  { router: { isActive: true } }
);

expect(wrapper.instance().state.myProperty).toEqual(newValue);
Run Code Online (Sandbox Code Playgroud)

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

从这里开始,我一直在寻找有关如何存储上下文或模拟其中一个组件的详细信息,但是没有设法将这些拼图有效地组合在一起以成功编写和运行此测试.

如何将组件的状态更改componentDidMount为何时具有依赖于满足react-router模块的上下文的后代?

Jef*_*ver 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
);
Run Code Online (Sandbox Code Playgroud)