web-dev-qa-db-fra.com

React Router v4 Redirect unit test

Comment puis-je tester le composant dans Reactor Routeur v4? J'essaie sans succès de tester un composant simple avec une redirection à l'aide de plaisanterie et d'enzyme.

Ma composante:

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

Ma tentative de le tester:

    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);
  });
});
21
Luca Marangon

Répondre à ma propre question. Fondamentalement, je fais un rendu superficiel de mon composant et vérifie que s'il est authentifié, le composant de redirection est rendu, sinon celui de l'application. Voici le code:

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);
  });
});
20
Luca Marangon

Aucune de ces réponses n'a fonctionné pour moi et n'a pris un peu de fouille, alors j'ai pensé que j'allais intégrer mon expérience ici.

PrivateRoute.js

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

PrivateRoute.spec.js

Ce test a fonctionné pour moi sans aucun problème, il a rendu le PrivateComponent lorsque auth.isAuthenticated Évalué à vrai.

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)
})

C'était le test qui m'a donné beaucoup de problèmes. Au début, je cherchais le composant Redirect.

J'ai essayé de faire quelque chose comme

expect(privateRoute.find('Redirect').length).toEqual(1)

Mais cela ne fonctionnerait pas, quoi que je fasse, il ne pouvait tout simplement pas trouver le composant Redirect. En fin de compte, j'ai fini par vérifier l'historique, mais je n'ai trouvé aucune documentation fiable en ligne et j'ai fini par regarder la base de code du routeur React.

Dans MemoryRouter.js (ligne 30) j'ai vu qu'il rendait un composant Router . J'ai remarqué qu'il passait également son history comme accessoire à Router alors j'ai pensé que je serais en mesure de l'attraper à partir de là.

J'ai fini par attraper l'accessoire d'historique de Router en utilisant privateRoute.find('Router').prop('history') qui m'a finalement donné la preuve qu'une redirection s'était effectivement produite, au bon endroit, pas moins.

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('/')
})

Avec ce test, vous testez la fonctionnalité réelle du composant PrivateRoute et vous assurez qu'il va là où il est dit.

La documentation laisse beaucoup à désirer. Par exemple, il m'a fallu un peu de fouille pour découvrir initialEntries comme accessoire pour MemoryRouter, vous en avez besoin pour qu'il atteigne réellement la route et exécute le conditionnel, j'ai dépensé aussi essayant longtemps de couvrir les deux branches pour se rendre compte que c'était ce qu'il fallait.

J'espère que cela aide quelqu'un.

10
Michael Curry

Voici mon exemple minimal de test que l'URL réelle change au lieu de simplement qu'un composant Redirect existe sur la page:

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;

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");
});

En enveloppant RedirectApp dans un Route, MemoryRouter injecte les accessoires react-router (match, location et history) dans RedirectApp.

enzyme vous permet de récupérer ces props(), et le location prop inclut le pathname après la redirection, afin que l'emplacement redirigé puisse être mis en correspondance.

Cette méthode est un peu hacky, mais a l'avantage de tester qu'une redirection va à l'endroit correct et pas seulement qu'un Redirect existe.

Alternativement, vous pouvez export default withRouter(RedirectApp) dans RedirectApp.js Pour obtenir automatiquement les accessoires react-router Injectés.

3
cgenco