我正在尝试为 React 功能组件编写单元测试,该功能组件具有如下所示useLocation()
路由器钩子。
//index.js
function MyComponent(props) {
const useQuery = () => new URLSearchParams(useLocation().search);
const status = useQuery().get('status');
if (status === 'success') {
return <ShowStatus message="OK" secret={props.secret} />;
} else {
return <ShowStatus message="NOT OK" secret={props.secret} />;
}
}
//index.spec.js
describe('Test MyComponent', () => {
it('should send OK when success', () => {
sinon.stub(reactRouter, 'useLocation').returns({
search: {
status: 'success'
}
});
const props = { secret: 'SECRET_KEY' };
const wrapper = enzyme.shallow(<MyComponent.WrappedComponent {...props}/>);
expect(wrapper.type()).to.have.length(MyComponent);
expect(wrapper.props().message).to.equal('OK');
expect(wrapper.props().secret).to.equal(props.secret);
});
it('should send NOT OK when error', () => {
sinon.stub(reactRouter, 'useLocation').returns({
search: {
status: 'error'
}
});
const props = { secret: 'SECRET_KEY' };
const wrapper = enzyme.shallow(<MyComponent.WrappedComponent {...props}/>);
expect(wrapper.type()).to.have.length(MyComponent);
expect(wrapper.props().message).to.equal('NOT OK);
expect(wrapper.props().secret).to.equal(props.secret);
});
});
即使我在遇到错误useLocation
也在存根
TypeError: Cannot read property 'location' of undefined
at useLocation (node_modulesreact-routermoduleshooks.js:28:10)
我正在尝试测试组件是否ShowStatus
基于查询参数使用正确的道具进行渲染。
任何建议/帮助不胜感激。
更新:即使我在生产和测试代码中从react-router-dom
导入,我也注意到。我看到产品一正在从react-router
.
使用 MemoryRouter 组件包装您的组件比存根useLocation
钩子更好。
将"URL"的历史记录保存在内存中(不读取或写入地址栏(。在测试和非浏览器环境(如 React Native(中很有用。
我们可以通过 initialEntries 属性提供被测试组件的"URL"。
index.tsx
:
import React from 'react';
import { useLocation } from 'react-router-dom';
export function ShowStatus({ message, secret }) {
return <div>{message}</div>;
}
export function MyComponent(props) {
const useQuery = () => new URLSearchParams(useLocation().search);
const status = useQuery().get('status');
if (status === 'success') {
return <ShowStatus message="OK" secret={props.secret} />;
} else {
return <ShowStatus message="NOT OK" secret={props.secret} />;
}
}
index.test.tsx
:
import { mount } from 'enzyme';
import React from 'react';
import { MemoryRouter } from 'react-router';
import { MyComponent, ShowStatus } from './';
describe('MyComponent', () => {
it('should send OK when success', () => {
const props = { secret: 'SECRET_KEY' };
const wrapper = mount(
<MemoryRouter initialEntries={[{ search: '?status=success' }]}>
<MyComponent {...props} />
</MemoryRouter>
);
expect(wrapper.find(ShowStatus).props().message).toEqual('OK');
expect(wrapper.find(MyComponent).props().secret).toEqual(props.secret);
});
it('should send NOT OK when error', () => {
const props = { secret: 'SECRET_KEY' };
const wrapper = mount(
<MemoryRouter initialEntries={[{ search: '?status=error' }]}>
<MyComponent {...props} />
</MemoryRouter>
);
expect(wrapper.find(ShowStatus).props().message).toEqual('NOT OK');
expect(wrapper.find(MyComponent).props().secret).toEqual(props.secret);
});
});
测试结果:
PASS examples/59829930/index.test.tsx (8.239 s)
MyComponent
✓ should send OK when success (55 ms)
✓ should send NOT OK when error (8 ms)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.tsx | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 9.003 s
软件包版本:
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"jest": "^26.6.3",
"react": "^16.14.0",
"react-router-dom": "^5.2.0",