使用 Jest 测试来自 react-router v4 的链接

Posted

技术标签:

【中文标题】使用 Jest 测试来自 react-router v4 的链接【英文标题】:Using Jest to test a Link from react-router v4 【发布时间】:2017-10-01 23:05:45 【问题描述】:

我正在使用 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`.

【问题讨论】:

【参考方案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 是做什么的?

以上是关于使用 Jest 测试来自 react-router v4 的链接的主要内容,如果未能解决你的问题,请参考以下文章

用 Jest 和 Enzyme 测试 React Router

使用 Jest 测试时未定义全局节点配置变量

在 Jest 测试中使用 Webpack 的 DefinePlugin 变量

使用 Vue.js 和 Jest 进行 URL 重定向测试

Vue Typescript 组件 Jest 测试不会在 html 中呈现值

使用 axios 执行经过身份验证的请求时,Jest 返回“网络错误”