使用 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】:
以上解决方案有一个共同的默认事实:
无法访问您组件的实例!因为MemoryRouter
或StaticRouter
组件包装了您的组件。
所以解决这个问题最好的办法就是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 测试中使用 Webpack 的 DefinePlugin 变量