you withrouter violation utils unit test should shallow route react outside not invariant unit-testing reactjs react-router

unit testing - withrouter - React Router v4 prueba de unidad de redireccionamiento



testing react router 4 (3)

¿Cómo hago una prueba unitaria del componente en el enrutador de reacción v4? Estoy intentando, sin éxito, probar un componente simple con una redirección usando broma y enzima.

Mi componente:

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

Mi intento de probarlo:

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


Este es mi ejemplo mínimo de prueba de que la URL real cambia en lugar de que exista un componente de Redirect en la página:

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

Al ajustar RedirectApp en una Route , MemoryRouter inyecta las MemoryRouter react-router ( match , location e history ) en RedirectApp .

enzyme permite tomar estos props() , y el apoyo de location incluye el pathname después de la redirección, de modo que la ubicación redirigida puede coincidir.

Este método es un poco intrincado, pero tiene la ventaja de probar que una redirección va al lugar correcto y no solo que existe una Redirect .

Alternativamente, puede export default withRouter(RedirectApp) en RedirectApp.js para que se inyecten automáticamente los accesorios de react-router .


Ninguna de estas respuestas funcionó para mí y me tomó un poco de tiempo de investigación, así que pensé que sería mi experiencia aquí.

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

Esta prueba funcionó para mí sin ningún tipo de problema, representó el auth.isAuthenticated cuando se auth.isAuthenticated como verdadero.

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

Esta fue la prueba que me dio muchos problemas. Al principio estaba comprobando el componente de Redirect .

Traté de hacer algo como

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

Pero eso no funcionaría, no importa lo que hice, simplemente no pudo encontrar el componente de Redirect . Al final, terminé revisando el historial, pero no pude encontrar ninguna documentación confiable en línea y terminé mirando el código base de React Router.

En MemoryRouter.js (línea 30) vi que representaba un componente de Router . Noté que también estaba pasando su history como apoyo para Router así que pensé que sería capaz de agarrarlo desde allí.

Terminé tomando el prop de historial desde Router usando privateRoute.find(''Router'').prop(''history'') que finalmente me dio evidencia de que realmente había ocurrido un redireccionamiento, a la ubicación correcta, nada menos.

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

Con esta prueba, está probando la funcionalidad real del componente PrivateRoute y asegurándose de que vaya a donde está diciendo que va.

La documentación deja mucho que desear. Por ejemplo, me tomó un poco de tiempo de investigación para encontrar información acerca de initialEntries como apoyo para MemoryRouter , necesitas esto para que realmente llegue a la ruta y ejecute el condicional. Pasé demasiado tiempo intentando cubrir ambas ramas solo para darme cuenta de esto. Era lo que se necesitaba.

Espero que esto ayude a alguien.


Respondiendo a mi propia pregunta. Básicamente, estoy haciendo una representación superficial de mi componente y verificando que si está autenticado está renderizando el componente de redireccionamiento, de lo contrario, la aplicación. Aquí el código:

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