Jusqu'à présent, dans les tests unitaires, les paramètres de correspondance du routeur de réaction étaient récupérés comme accessoires du composant. Donc, tester un composant en tenant compte d'une correspondance spécifique, avec des paramètres d'URL spécifiques, était facile: nous devions simplement préciser les accessoires de correspondance du routeur comme nous le souhaitons lors du rendu du composant en test (j'utilise la bibliothèque d'enzymes à cet effet).
J'apprécie vraiment les nouveaux hooks pour récupérer des trucs de routage, mais je n'ai pas trouvé d'exemples sur la façon de simuler une correspondance de routeur de réaction dans les tests unitaires, avec de nouveaux hooks de routeur de réaction?
6 Réponses :
J'ai fini par résoudre ce problème en me moquant des crochets dans mes tests en utilisant jest.mock:
// TeamPage.test.js jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), // use actual for all non-hook parts useParams: () => ({ companyId: 'company-id1', teamId: 'team-id1', }), useRouteMatch: () => ({ url: '/company/company-id1/team/team-id1' }), }));
J'utilise jest.requireActual
pour utiliser les parties réelles de jest.requireActual
-router-dom pour tout sauf les hooks qui m'intéressent de se moquer.
Fonctionne comme un charme, et ce modèle sera utile dans de nombreux cas dans mon projet pour se moquer des points précis des modules externes sans tout casser :)
Je n'ai jamais jest.requireActual
parler de jest.requireActual
cela aide grandement!
et si je dois passer un identifiant de société différent dans le même fichier de test
J'ai regardé les tests pour les hooks dans le repo MemoryRouter
react-router
et il semble que vous deviez envelopper votre composant dans un MemoryRouter
et une Route
. J'ai fini par faire quelque chose comme ça pour faire fonctionner mes tests:
import {Route, MemoryRouter} from 'react-router-dom'; ... const renderWithRouter = ({children}) => ( render( <MemoryRouter initialEntries={['blogs/1']}> <Route path='blogs/:blogId'> {children} </Route> </MemoryRouter> ) )
J'espère que ça t'as aidé!
Le problème est de se moquer des nouveaux hooks react-router-dom
. Emballer votre composant dans un MemoryRouter est certainement ce que vous voulez faire pour tout composant testé qui se trouve dans un routeur. Il existe de nombreux modèles pour créer un wrapper réutilisable tel que testing-library.com/docs/example-react-router
Cette réponse doit être acceptée, moins intrusive, plus correcte
J'essaie de savoir si la fonction push
dans useHistory
est appelée en faisant cela mais je ne peux pas obtenir les appels de fonction simulés ...
const mockHistoryPush = jest.fn(); jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useHistory: () => ({ push: mockHistoryPush, }), })); fireEvent.click(getByRole('button')); expect(mockHistoryPush).toHaveBeenCalledWith('/help');
Il dit que mockHistoryPush
n'est pas appelé lorsque le bouton a onClick={() => history.push('/help')}
jest se moque de hisser le module mockHistoryPush
avant toute autre chose, ainsi votre mockHistoryPush
ne sera pas vu au moment de l'exécution. Au lieu de cela, dans votre test, faites quelque chose comme import * as ReactRouterDom from 'react-router-dom'; jest.spyOn(ReactRouterDom, 'useHistory').returnValue({ push: mockHistoryPush, })
@JensBodal Je viens d'essayer et j'ai obtenu un "TypeError: Impossible de définir la propriété useHistory de [objet objet] qui n'a qu'un getter", se mettra à jour si je trouve une solution
Des nouvelles à ce sujet @JasonRogers? : '(
J'ai le même problème actuellement. Semble impossible de se moquer / tester cette situation.
L'histoire moqueuse.push est expliquée ici: stackoverflow.com/questions/58524183/...
Dans votre composant, utilisez des crochets comme ci-dessous
import routeData from 'react-router'; const mockLocation = { pathname: '/welcome', hash: '', search: '', state: '' } beforeEach(() => { jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation) });
Dans votre test, espionnez l'objet reactRouter comme ci-dessous
import {useLocation} from 'react-router'; const location = useLocation()
gentil, l'aide ci-dessus en utilisant spyOn Merci @suchin
Merci! Ça marche! comment avez-vous routeData
? Je ne le trouve pas dans la documentation de react-router.
Merci une petite correction de syntaxe: beforeEach(() => { jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation) });
Si vous utilisez l' enzyme
bibliothèque, je trouve un moyen de résoudre beaucoup moins bavard le problème ( en utilisant cette section du react-router-dom
docs ):
import React from 'react' import { shallow } from 'enzyme' import { MemoryRouter } from 'react-router-dom' import Navbar from './Navbar' it('renders Navbar component', () => { expect( shallow( <MemoryRouter> <Navbar /> </MemoryRouter> ) ).toMatchSnapshot() })
Si vous utilisez la react-testing-library
pour les tests, vous pouvez faire fonctionner cette simulation.
jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useLocation: () => ({ state: { email: 'school@edu.ng' } }), })); export const withReduxNRouter = ( ui, { store = createStore(rootReducer, {}) } = {}, { route = '/', history = createMemoryHistory({ initialEntries: [ route ] }), } = {} ) => { return { ...render( <Provider store={store}> <Router history={history}>{ui}</Router> </Provider> ), history, store, }; };
Vous auriez dû vous moquer de react-router-dom
avant qu'il ne soit utilisé pour rendre votre composant. J'explore des moyens de rendre cela réutilisable
Je testais une application ionique de base qui utilisait le hook useLocation. Cela a parfaitement fonctionné. Merci.
si vous avez utilisé CRA pour créer votre projet, vous pouvez simplement mettre le bloc jest.mock dans setupTests.js (ts)
Bonjour @chidimo, avez-vous trouvé un moyen de rendre cela réutilisable?
Je pense que je l'ai fait. J'ai fait un post que vous pouvez trouver ici smashingmagazine.com/2020/07/react-apps-testing-library