【问题标题】:Using Jest to test a Link from react-router v4使用 Jest 测试来自 react-router v4 的链接
【发布时间】:2018-02-25 14:33:12
【问题描述】:

我正在使用 jest 来测试带有来自 react-router v4 的 <Link> 的组件。

我收到警告,<Link /> 需要来自 react-router <Router /> 组件的上下文。

如何在我的测试中模拟或提供路由器上下文? (基本上我该如何解决这个警告?)

Link.test.js

import React from 'react';
import renderer from 'react-test-renderer';
import { Link } from 'react-router-dom';

test('Link matches snapshot', () => {
  const component = renderer.create(
    <Link to="#" />
  );

  let tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

测试运行时的警告:

Warning: Failed context type: The context `router` is marked 
as required in `Link`, but its value is `undefined`.

【问题讨论】:

    标签: react-router jestjs react-router-v4


    【解决方案1】:

    您可以使用 StaticRouter 将您的组件包装在测试中,以将路由器上下文放入您的组件中:

    import React from 'react';
    import renderer from 'react-test-renderer';
    import { Link } from 'react-router-dom';
    import { StaticRouter } from 'react-router'
    
    test('Link matches snapshot', () => {
      const component = renderer.create(
        <StaticRouter location="someLocation" context={context}>
          <Link to="#" />
        </StaticRouter>
      );
    
      let tree = component.toJSON();
      expect(tree).toMatchSnapshot();
    });
    

    看看反应路由器docs about testing

    【讨论】:

    • 最大的问题是:componet 引用了StaticRouter,所以你无法获取要测试的组件实例。你无法访问它的props & state 这样的。
    • 您可能需要在const component = ...上方添加const context = {};
    【解决方案2】:

    我遇到了同样的问题,使用StaticRouter 仍然需要context,它需要更多配置才能在我的测试中使用,所以我最终使用了MemoryRouter,它运行良好且没有任何问题。

    import React from 'react';
    import renderer from 'react-test-renderer';
    import { MemoryRouter } from 'react-router-dom';
    
    // SampleComponent imports Link internally
    import SampleComponent from '../SampleComponent';
    
    describe('SampleComponent', () => {
      test('should render', () => {
        const component = renderer
          .create(
            <MemoryRouter>
              <SampleComponent />
            </MemoryRouter>
          )
          .toJSON();
    
        expect(component).toMatchSnapshot();
      });
    });
    

    【讨论】:

      【解决方案3】:

      我的测试是这样的:

      import * as React from 'react'
      import DataBaseAccout from '../database-account/database-account.component'
      import { mount } from 'enzyme'
      import { expect } from 'chai'
      import { createStore } from 'redux'
      import reducers from '../../../reducer/reducer'
      import { MemoryRouter } from 'react-router'
      
      let store = createStore(reducers)
      
      describe('mount database-account', () => {
        let wrapper
        beforeEach(() => {
          wrapper = mount(
            < MemoryRouter >
              <DataBaseAccout store={store} />
            </MemoryRouter >
          )
        })
      
        afterEach(() => {
          wrapper.unmount()
          wrapper = null
        })
      })
      但我不知道为什么 MemoryRouter 可以解决这个问题。

      【讨论】:

      • 有问题,wrapper 引用MemoryRouter 组件,即不能操作DataBaseAccout 组件,例如wrapper.props()wrapper.state() 将不起作用。
      【解决方案4】:

      以上解决方案有一个共同的默认事实:

      无法访问您组件的实例!因为MemoryRouterStaticRouter 组件包装了您的组件。

      所以解决这个问题最好的办法就是mock一个router context,代码如下:

      import { configure, mount } from 'enzyme';
      import Adapter from 'enzyme-adapter-react-16';
      
      describe('YourComponent', () => {
        test('test component with react router', () => {
          // mock react-router context to avoid violation error
          const context = {
            childContextTypes: {
              router: () => void 0,
            },
            context: {
              router: {
                history: createMemoryHistory(),
                route: {
                  location: {
                    hash: '',
                    pathname: '',
                    search: '',
                    state: '',
                  },
                  match: { params: {}, isExact: false, path: '', url: '' },
                }
              }
            }
          };
          // mount component with router context and get component's instance
          const wrapper = mount(<YourComponent/>, context);
          // access your component as you wish
          console.log(wrapper.props(), wrapper.state())
        });
        beforeAll(() => {
          configure({ adapter: new Adapter() });
        });
      });
      

      【讨论】:

      • createMemoryHistory 是做什么的?
      猜你喜欢
      • 2017-11-10
      • 1970-01-01
      • 2015-10-12
      • 1970-01-01
      • 2017-11-26
      • 1970-01-01
      • 2019-05-06
      • 2018-09-05
      相关资源
      最近更新 更多