Typescriptを使用して反応ルーターv5.1.2でUseHistoryフックを使用していますか?単体テストを実行すると、問題が発生します。
TypeError:未定義のプロパティ 'history'を読み取れません。
_import { mount } from 'enzyme';
import React from 'react';
import {Action} from 'history';
import * as router from 'react-router';
import { QuestionContainer } from './QuestionsContainer';
describe('My questions container', () => {
beforeEach(() => {
const historyHistory= {
replace: jest.fn(),
length: 0,
location: {
pathname: '',
search: '',
state: '',
hash: ''
},
action: 'REPLACE' as Action,
Push: jest.fn(),
go: jest.fn(),
goBack: jest.fn(),
goForward: jest.fn(),
block: jest.fn(),
listen: jest.fn(),
createHref: jest.fn()
};//fake object
jest.spyOn(router, 'useHistory').mockImplementation(() =>historyHistory);// try to mock hook
});
test('should match with snapshot', () => {
const tree = mount(<QuestionContainer />);
expect(tree).toMatchSnapshot();
});
});
_
また、jest.mock('react-router', () =>({ useHistory: jest.fn() }));
を使用しようとしましたが、それでも機能しません。
useHistory
を使用するreact機能コンポーネントを浅くするときにも同じことが必要でした。
私のテストファイルで次のモックで解決しました:
jest.mock('react-router-dom', () => ({
useHistory: () => ({
Push: jest.fn(),
}),
}));
これは私のために働きました:
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
Push: jest.fn()
})
}));
Github反応ルーターリポジトリで、useHistoryフックがシングルトンコンテキストを使用していることを発見しました。だからそれを修正
import { MemoryRouter } from 'react-router-dom';
const tree = mount(<MemoryRouter><QuestionContainer {...props} /> </MemoryRouter>);
以下は、実際のテストコードから抜粋したより詳細な例です(上記のコードの実装が困難だったため)。
Component.js
import { useHistory } from 'react-router-dom';
...
const Component = () => {
...
const history = useHistory();
...
return (
<>
<a className="selector" onClick={() => history.Push('/whatever')}>Click me</a>
...
</>
)
});
Component.test.js
import { Router } from 'react-router-dom';
import { act } from '@testing-library/react-hooks';
import { mount } from 'enzyme';
import Component from './Component';
it('...', () => {
const historyMock = { Push: jest.fn(), location: {}, listen: jest.fn() };
...
const wrapper = mount(
<Router history={historyMock}>
<Component isLoading={false} />
</Router>,
).find('.selector').at(1);
const { onClick } = wrapper.props();
act(() => {
onClick();
});
expect(historyMock.Push.mock.calls[0][0]).toEqual('/whatever');
});