我正在尝试为具有路由器 Hook 的 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);
});
});
连我都 stub useLocation
我收到错误TypeError: Cannot read property 'location' of undefined
at useLocation (node_modules\react-router\modules\hooks.js:28:10)
我正在尝试测试 ShowStatus
组件根据查询参数使用正确的 Prop 呈现。任何建议/帮助表示赞赏。
更新:
我注意到即使我是从
react-router-dom
进口的在生产和测试代码中。我正在看到一个来自 react-router
的产品.
最佳答案
使用 MemoryRouter组件包装你的组件比 stub 更好 useLocation
钩。
keeps the history of your “URL” in memory (does not read or write to the address bar). Useful in tests and non-browser environments like React Native.
我们可以通过 initialEntries 为您测试的组件提供“URL” Prop 。
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",
关于reactjs - 像 'useLocation' 这样的 react 路由器钩子(Hook)的 stub 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59829930/