首页 > 解决方案 > 像“useLocation”这样的反应路由器钩子的存根不起作用

问题描述

我正在尝试为具有useLocation()如下路由器挂钩的 React 功能组件编写单元测试。

//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_modules\react-router\modules\hooks.js:28:10)

我正在尝试测试ShowStatus组件是否根据查询参数使用正确的道具渲染。

任何建议/帮助表示赞赏。

更新: 我注意到即使我从react-router-dom产品和测试代码中导入。我看到产品从react-router.

标签: reactjsreact-hooksreact-routerenzyme

解决方案


使用MemoryRouter组件包装你的组件比 stubuseLocation钩子更好。

将您的“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",

推荐阅读