使用 jest 模拟 react-router-dom 钩子不起作用
Posted
技术标签:
【中文标题】使用 jest 模拟 react-router-dom 钩子不起作用【英文标题】:Mocking react-router-dom hooks using jest is not working 【发布时间】:2020-03-11 23:49:03 【问题描述】:我正在使用 Enzyme 的浅层方法来测试一个组件,该组件使用 useParams
钩子从 URL 参数中获取 ID。
我正在尝试模拟 useParams
钩子,以便它不会调用实际方法,但它不起作用。我仍然得到TypeError: Cannot read property 'match' of undefined
,所以它调用实际的useParams
,而不是我的模拟。
我的组件:
import React from 'react';
import useParams from 'react-router-dom';
export default () =>
const id = useParams();
return <div>id</div>;
;
测试:
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import Header from './header';
import shallow from 'enzyme';
Enzyme.configure( adapter: new Adapter() );
describe('<Header />', () =>
jest.mock('react-router-dom', () => (
useParams: jest.fn().mockReturnValue( id: '123' ),
));
it('renders', () =>
const wrapper = shallow(<Header />);
expect(wrapper).toBeTruthy();
);
);
谢谢!
【问题讨论】:
【参考方案1】:这对我来说可以模拟 useParams 并更改同一文件中每个单元测试的值:
import React from "react";
import render from "@testing-library/react";
import Router from "react-router-dom";
import Component from "./Component";
jest.mock("react-router-dom", () => (
...jest.requireActual("react-router-dom"),
useParams: jest.fn(),
));
const createWrapper = () =>
return render(<Cases />);
;
describe("Component Page", () =>
describe("Rendering", () =>
it("should render cases container", () =>
jest.spyOn(Router, 'useParams').mockReturnValue( id: '1234' )
const wrapper = createWrapper();
expect(wrapper).toMatchSnapshot();
);
it("should render details container", () =>
jest.spyOn(Router, 'useParams').mockReturnValue( id: '5678' )
const wrapper = createWrapper();
expect(wrapper).toMatchSnapshot();
);
);
);
只需在 describe() 外部将 useParams
声明为 jest.fn()
,然后在每个单元测试中使用 jest.spyOn
更改其值
【讨论】:
【参考方案2】:我不知道为什么,在 react-router 库的文档中也找不到它,但是在测试和实现中将 react-router-dom
更改为 react-router
对我有用。
所以它变成了这样:
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import Header from './header';
import shallow from 'enzyme';
Enzyme.configure( adapter: new Adapter() );
describe('<Header />', () =>
jest.mock('react-router', () => (
useParams: jest.fn().mockReturnValue( id: '123' ),
));
it('renders', () =>
const wrapper = shallow(<Header />);
expect(wrapper).toBeTruthy();
);
);
【讨论】:
感谢@ivan,如果有人知道其背后的逻辑,请在此处发布。 好吧,我想我找到了:react-router-dom
没有定义钩子。钩子在react-router
包中定义。因此,如果你想模拟反应路由器钩子,你需要模拟那个包。见:github.com/ReactTraining/react-router/blob/master/packages/…
即使我从 react-router 导入这些钩子并模拟 react-router 包,它仍然给他们同样的错误 Cannot read property 'match' of undefined【参考方案3】:
我尝试了这个模拟,但它对我不起作用。错误:无法读取未定义的属性“匹配”。似乎该组件不在路由器内部,因此它无法使用参数模拟匹配。它对我有用:
import MemoryRouter, Route from 'react-router-dom';
const RenderWithRouter = ( children ) => (
<MemoryRouter initialEntries=['uri/Ineed']>
<Route path="route/Ineed/:paramId">children</Route>
</MemoryRouter>
);
const tf = new TestFramework();
describe('<MyComponent />', () =>
tf.init( title: 'Some test' , props =>
shallow(
<RenderWithRouter>
<MyComponent ...props />
</RenderWithRouter>
)
);
it('Some description', () =>
const wrapper = tf.render().html();
expect(wrapper).toContain('something');
);
);
【讨论】:
【参考方案4】:我遇到过类似的问题,我是这样解决的:
import Route, Router from "react-router-dom";
import createMemoryHistory from "history";
const renderWithRouter = (component) =>
const history = createMemoryHistory(
initialEntries: ["/part1/idValue1/part2/idValue2/part3"],
);
const Wrapper = ( children ) => (
<Router history=history>
<Route path="/part1/:id1/part2/:id2/part3">children</Route>
</Router>
);
return
...render(component, wrapper: Wrapper ),
history,
;
;
describe("test", () =>
it("test desc", async () =>
const getByText = renderWithRouter(<MyComponent/>);
expect(getByText("idValue1")).toBeTruthy();
);
);
【讨论】:
我忘了说,我正在使用 react-testing-library 但我希望路由器部分至少是相似的 这正是我所需要的。谢谢!【参考方案5】:我遇到了同样的问题。我像这样嘲笑 useParams:
jest.mock('react-router-dom', () =>
return
useParams: () => (
id: '123'
)
)
【讨论】:
【参考方案6】:对我来说,嘲笑 react-router-dom 解决问题:
jest.mock('react-router-dom', () => (
useParams: jest.fn().mockReturnValue( nifUuid: 'nif123' ),
useHistory: jest.fn()
));
【讨论】:
【参考方案7】:我遇到了同样的问题。 从“@testing-library/react”调用“清理”函数对我有帮助:
import cleanup from '@testing-library/react';
afterEach(() =>
cleanup();
);
【讨论】:
一般来说,如果您的解决方案与您的解决方案不完全相同,那么提供帮助您找到此解决方案的步骤可能对其他人非常有用,除此之外,很好的干净答案。以上是关于使用 jest 模拟 react-router-dom 钩子不起作用的主要内容,如果未能解决你的问题,请参考以下文章
使用 jest.mock('axios') 时如何模拟拦截器?