Reactjs 如何使用“BrowserRouter”或“MemoryRouter”监视“history”?
最简单的例子:Reactjs 如何使用“BrowserRouter”或“MemoryRouter”监视“history”?,reactjs,react-router-dom,Reactjs,React Router Dom,最简单的例子: react-router-dom@^5.1.0: version "5.1.2" react@^16.12.0: version "16.12.0" "@testing-library/react@^11.1.2": version "11.1.2" history@^5.0.0: version "5.0.0" 好的,正如所料 现在,在history.pu
react-router-dom@^5.1.0:
version "5.1.2"
react@^16.12.0:
version "16.12.0"
"@testing-library/react@^11.1.2":
version "11.1.2"
history@^5.0.0:
version "5.0.0"
好的,正如所料
现在,在history.push
call之后,它变成:
{ pathname: '/',
search: '',
hash: '',
state: null,
key: 'f2blf5di' } { pathname: '/',
search: '',
hash: '',
state: null,
key: 'f2blf5di' }
因此,location
对象完全改变,但是history.location
仍然具有相同的对象结构
使用MemoryRouter
或BrowserRouter
修复了这个问题,但我仍然需要监视历史记录。push
调用as以确保只发生了X次推送
我需要执行此检查,因为在一个组件中,由于某些useffect
多次运行并执行多个历史记录,可能会发生一些错误。使用完全相同的参数推送。导致用户必须点击浏览器后退按钮(X+1)次才能回到原来的位置
也尝试了此操作,但是history.goBack()
根本不会更改位置
{ pathname: '/abc',
search: '',
hash: '',
state: null,
key: 'tz0v0qgf' } { action: 'PUSH',
location:
{ pathname: '/abc',
search: '',
hash: '',
state: null,
key: 'tz0v0qgf' } }
归根结底,我认为这不是单元测试的工作。应该是e2e测试。不过现在,这对我来说已经足够了
{ pathname: '/abc',
search: '',
hash: '',
state: null,
key: 'tz0v0qgf' } { action: 'PUSH',
location:
{ pathname: '/abc',
search: '',
hash: '',
state: null,
key: 'tz0v0qgf' } }
import React, {useEffect} from 'react';
import {render, act, screen, fireEvent} from '@testing-library/react';
import {BrowserRouter, useHistory, useLocation} from 'react-router-dom';
import window from 'global/window';
test('Sample', async () => {
const Component = () => {
const location = useLocation();
const history = useHistory();
useEffect(() => {
const timeoutId = setTimeout(() => {
history.push('/abc?foo=fooValue');
history.push('/abc?foo=fooValue');
history.push('/abc?foo=fooValue');
}, 100);
return () => clearTimeout(timeoutId);
}, []);
return (
<div>
<div>{history.location.search}</div>
<div>{location.search}</div>
{__DEV__ && <button onClick={() => history.goBack()}>back</button>}
</div>
);
};
render(
<BrowserRouter>
<Component />
</BrowserRouter>
);
expect(window.location.pathname).toEqual('/');
expect(window.location.search).toEqual('');
await act(() => new Promise(resolve => setTimeout(resolve, 200)));
fireEvent.click(screen.getByRole('button', {name: 'back'}));
expect(window.location.pathname).toEqual('/abc');
expect(window.location.search).toEqual('?foo=fooValue');
fireEvent.click(screen.getByRole('button', {name: 'back'}));
fireEvent.click(screen.getByRole('button', {name: 'back'}));
fireEvent.click(screen.getByRole('button', {name: 'back'}));
fireEvent.click(screen.getByRole('button', {name: 'back'}));
fireEvent.click(screen.getByRole('button', {name: 'back'}));
expect(window.location.pathname).toEqual('/');
expect(window.location.search).toEqual('');
});
const memoryRouterRef: {current: any} = React.createRef<any>();
render(
<MemoryRouter ref={memoryRouterRef}>
...
</MemoryRouter>
);
...do some stuff...
expect(memoryRouterRef.current.history.location.pathname).toEqual(...);
expect(memoryRouterRef.current.history.location.search).toEqual(...);
expect(memoryRouterRef.current.history.length).toEqual(...);
memoryRouterRef.current.history.goBack(); // This works now!!
// We can now check the pathname / search to make sure user can use the browser back button properly
expect(memoryRouterRef.current.history.location.pathname).toEqual(...);
expect(memoryRouterRef.current.history.location.search).toEqual(...);