React Router v4重定向单元测试

Luc*_*gon 22 unit-testing reactjs react-router

如何在反应路由器v4中对组件进行单元测试?我没有成功尝试使用jest和酶对重定向进行单元测试.

我的组件:

 const AppContainer = ({ location }) =>
  (isUserAuthenticated()
    ? <AppWithData />
    : <Redirect
        to={{
          pathname: "/login",
          state: { from: location }
        }}
      />);
Run Code Online (Sandbox Code Playgroud)

我尝试测试它:

    function setup() {
  const enzymeWrapper = mount(
    <MemoryRouter initialEntries={["/"]}>
      <AppContainer />
    </MemoryRouter>
  );

  return {
    enzymeWrapper
  };
}

jest.mock("lib/authAPI", () => ({
  isUserAuthenticated: jest.fn(() => false)
}));

describe("AppContainer component", () => {
  it("renders redirect", () => {
    const { enzymeWrapper } = setup();

    expect(enzymeWrapper.find("<Redirect></Redirect>")).toBe(true);
  });
});
Run Code Online (Sandbox Code Playgroud)

Luc*_*gon 21

回答我自己的问题.基本上我正在对我的组件做一个浅层渲染,并验证如果经过身份验证是渲染重定向组件,那么另一个是App.这里的代码:

function setup() {
  const enzymeWrapper = shallow(<AuthenticatedApp />);

  return {
    enzymeWrapper
  };
}

describe("AuthenticatedApp component", () => {
  it("renders Redirect when user NOT autheticated", () => {
    authApi.isUserAuthenticated = jest.fn(() => false);
    const { enzymeWrapper } = setup();

    expect(enzymeWrapper.find(Redirect)).toHaveLength(1);
  });

  it("renders AppWithData when user autheticated", () => {
    authApi.isUserAuthenticated = jest.fn(() => true);
    const { enzymeWrapper } = setup();

    expect(enzymeWrapper.find(AppWithData)).toHaveLength(1);
  });
});
Run Code Online (Sandbox Code Playgroud)


Mic*_*rry 10

这些答案都没有对我有用,并且进行了相当多的挖掘,所以我认为我会在这里汲取经验.

PrivateRoute.js

export const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={(props) => (
    auth.isAuthenticated
      ? <Component {...props} />
      : <Redirect to={{
        pathname: '/',
        state: { from: props.location }
      }} />
  )} />
)
Run Code Online (Sandbox Code Playgroud)

PrivateRoute.spec.js

这个测试对我没有任何问题,它PrivateComponentauth.isAuthenticated评估时为真.

it('renders the component when the user is authorised', () => {
  auth.login()
  expect(auth.isAuthenticated).toBe(true)
  const privateRoute = mount(
    <MemoryRouter initialEntries={['/privateComponent']}>
      <PrivateRoute path='/privateComponent' component={PrivateComponent} />
    </MemoryRouter>
  )
  expect(privateRoute.find('PrivateComponent').length).toEqual(1)
})
Run Code Online (Sandbox Code Playgroud)

这是给我很多问题的测试.起初我正在检查Redirect组件.

我试着做一些像

expect(privateRoute.find('Redirect').length).toEqual(1)
Run Code Online (Sandbox Code Playgroud)

但这不行,无论我做了什么,它都找不到Redirect组件.最后,我最终检查了历史记录,但在网上找不到任何可靠的文档,最后查看了React Router代码库.

MemoryRouter.js(第30行)中,我看到它渲染了一个Router组件.我注意到它也传递了它history作为道具,Router所以我想我可以从那里抓住它.

我最终抓住了Router使用的历史道具privateRoute.find('Router').prop('history'),然后终于给了我证据表明实际上发生了重定向,到了正确的位置,并没有减少.

it('renders a redirect when the user is not authorised', () => {
  auth.logout()
  expect(auth.isAuthenticated).toBe(false)
  const privateRoute = mount(
    <MemoryRouter initialEntries={['/privateComponent']}>
      <PrivateRoute path='/privateComponent' component={PrivateComponent} />
    </MemoryRouter>
  )
  expect(privateRoute.find('PrivateComponent').length).toEqual(0)
  expect(
    privateRoute.find('Router').prop('history').location.pathname
  ).toEqual('/')
})
Run Code Online (Sandbox Code Playgroud)

通过此测试,您将测试PrivateRoute组件的实际功能,并确保它能够正常运行.

文档还有很多不足之处.例如,我需要花费一些时间来找出initialEntries作为道具MemoryRouter,你需要这个,所以它实际上击中了路线并执行条件,我花了太长时间试图覆盖两个分支只是意识到这是什么需要.

希望这有助于某人.


cge*_*nco 5

这是我测试实际 URL 更改而不仅仅是Redirect页面上存在组件的最小示例:

RedirectApp.js

import React from "react";
import { Route, Switch, Redirect } from "react-router-dom";

const RedirectApp = props => {
  return (
    <Switch>
      <Redirect from="/all-courses" to="/courses" />
    </Switch>
  );
};

export default RedirectApp;
Run Code Online (Sandbox Code Playgroud)

RedirectApp.test.js

import React from "react";
import { MemoryRouter, Route } from "react-router-dom";
import { mount } from "enzyme";
import RedirectApp from "./RedirectApp";

it("redirects /all-courses to /courses", () => {
  const wrapper = mount(
    <MemoryRouter initialEntries={[`/all-courses`]}>
      <Route component={RedirectApp} />
    </MemoryRouter>
  );

  expect(wrapper.find(RedirectApp).props().location.pathname).toBe("/courses");
});
Run Code Online (Sandbox Code Playgroud)

通过包裹RedirectApp在 a 中RouteMemoryRouterreact-routerprops ( match, location, and history)注入RedirectApp.

enzyme让你抓住这些props()location道具包括pathname重定向后,所以重定向的位置可以匹配。

这种方法有点笨拙,但具有测试重定向是否会到达正确位置而不仅仅是Redirect存在的优点。

另外,您也可以export default withRouter(RedirectApp)RedirectApp.js自动获取到react-router的道具注入。