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