使用 React 测试库提交后测试重定向

IT技术 reactjs unit-testing jestjs react-router-v4 react-testing-library
2021-05-23 19:25:52

我正在尝试测试登录组件。具体来说,它会在成功登录时重定向。手动测试时它工作正常。但在我的测试中,它从不进行重定向,因此找不到“注销”链接:

test('successfully logs the in the user', async () => {
  const fakeUserResponse = {success: true, token: 'fake_user_token'}
  jest.spyOn(window, 'fetch').mockImplementationOnce(() => {
    return Promise.resolve({
      json: () => Promise.resolve(fakeUserResponse),
    })
  })
  const { getByText, getByLabelText, findByTestId } = render(<Router><Login /></Router>)

  fireEvent.change(getByLabelText(/email/i), {target: {value: 'dan@example.com'}})
  fireEvent.change(getByLabelText(/password/i), {target: {value: 'password1234'}})
  fireEvent.click(getByText(/submit/i))

  await waitForElement(() => getByText(/logout/i));
})

我正在使用react-router版本 4 进行重定向,如下所示:

{state.resolved ? <Redirect to="/" /> : null}

我会以错误的方式解决这个问题吗?

3个回答

您可以模拟Redirect组件的实现以显示一些包含路径的文本,而不是重定向到它:

jest.mock('react-router-dom', () => {
  return {
    Redirect: jest.fn(({ to }) => `Redirected to ${to}`),
  };
});

并期望您的组件以正确的路径显示文本:

expect(screen.getByText('Redirected to /')).toBeInTheDocument();

所以我最终这样做了:

const { getByText, getByLabelText, } = render(
  <Router>
    <Login/>
    <Switch>
      <Route path="/">
        <div>logged out</div>
      </Route>
    </Switch>
  </Router>
)

fireEvent.change(getByLabelText(/email/i), {target: {value: 'dan@example.com'}})
fireEvent.change(getByLabelText(/password/i), {target: {value: 'password1234'}})
fireEvent.click(getByText(/submit/i))

await waitForElement(() => getByText(/logged out/i))

我个人模拟history.replaceRedirect组件使用功能

const history = createBrowserHistory();
history.replace = jest.fn();

render(
  <Router history={history} >
    <Component />
  </Router>
);

// trigger redirect

expect(history.replace).toHaveBeenCalledWith(expect.objectContaining({
  "pathname": "/SamplePath",
  "search": "?SampleSearch",
  "state": { "Sample": "State" }
}));

这允许您检查的不仅仅是正确的路径。请确保您正在使用Router而不是BrowserRouter在您的测试中。后者不接受历史props。