Testing av React-apper
This page was AI-translated by PageTurner (beta). Not officially endorsed by the project. Found an error? Report issue →
På Facebook bruker vi Jest for å teste React-applikasjoner.
Oppsett
Hvis du har en eksisterende applikasjon må du installere noen pakker for at alt skal fungere optimalt. Vi bruker babel-jest-pakken og react-babel-preset for å transformere koden vår i testmiljøet. Se også bruk av babel.
Kjør
- npm
- Yarn
- pnpm
- Bun
npm install --save-dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
yarn add --dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
pnpm add --save-dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
bun add --dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
Din package.json bør se omtrent slik ut (hvor <current-version> er den nyeste versjonen for pakken). Legg til skriptene og Jest-konfigurasjonsoppføringene:
{
"dependencies": {
"react": "<current-version>",
"react-dom": "<current-version>"
},
"devDependencies": {
"@babel/preset-env": "<current-version>",
"@babel/preset-react": "<current-version>",
"babel-jest": "<current-version>",
"jest": "<current-version>",
"react-test-renderer": "<current-version>"
},
"scripts": {
"test": "jest"
}
}
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};
Og du er klar til å starte!
Snapshot-testing
La oss lage en snapshot-test for en Link-komponent som viser hyperlenker:
import {useState} from 'react';
const STATUS = {
HOVERED: 'hovered',
NORMAL: 'normal',
};
export default function Link({page, children}) {
const [status, setStatus] = useState(STATUS.NORMAL);
const onMouseEnter = () => {
setStatus(STATUS.HOVERED);
};
const onMouseLeave = () => {
setStatus(STATUS.NORMAL);
};
return (
<a
className={status}
href={page || '#'}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{children}
</a>
);
}
Eksemplene bruker funksjonskomponenter, men klassekomponenter kan testes på samme måte. Se React: Funksjons- og klassekomponenter. Påminnelse: For klassekomponenter forventer vi at Jest brukes for å teste props, ikke metoder direkte.
La oss nå bruke Reacts testrenderer og Jests snapshot-funksjon for å interagere med komponenten, fange den renderte outputen og opprette en snapshot-fil:
import renderer from 'react-test-renderer';
import Link from '../Link';
it('changes the class when hovered', () => {
const component = renderer.create(
<Link page="http://www.facebook.com">Facebook</Link>,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
// manually trigger the callback
renderer.act(() => {
tree.props.onMouseEnter();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
// manually trigger the callback
renderer.act(() => {
tree.props.onMouseLeave();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
Når du kjører yarn test eller jest, vil dette produsere en output-fil som dette:
exports[`changes the class when hovered 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;
exports[`changes the class when hovered 2`] = `
<a
className="hovered"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;
exports[`changes the class when hovered 3`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;
Neste gang du kjører testene, vil den renderte outputen bli sammenlignet med forrige snapshot. Snapshotten bør committes sammen med kodeendringer. Når en snapshot-test feiler, må du undersøke om endringen er forventet eller utilsiktet. Hvis endringen er forventet, kan du kjøre Jest med jest -u for å overskrive det eksisterende snapshotet.
Koden for dette eksempelet er tilgjengelig på examples/snapshot.
Snapshot-testing med Mocks, Enzyme og React 16+
Det er et viktig poeng å merke seg ved snapshot-testing med Enzyme og React 16+. Hvis du lager en mock av en modul på denne måten:
jest.mock('../SomeDirectory/SomeComponent', () => 'SomeComponent');
Da vil du se advarsler i konsollen:
Warning: <SomeComponent /> is using uppercase HTML. Always use lowercase HTML tags in React.
# Or:
Warning: The tag <SomeComponent> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
React 16 utløser disse advarslene på grunn av hvordan den sjekker elementtyper, og den mockede modulen består ikke disse sjekkene. Alternativene dine er:
-
Render som tekst. Du vil ikke se propsene som sendes til mock-komponenten i snapshotet, men dette er en enkel løsning:
jest.mock('./SomeComponent', () => () => 'SomeComponent'); -
Render som et tilpasset element. DOM-"egendefinerte elementer" blir ikke sjekket og vil ikke utløse advarsler. De skrives med små bokstaver og har bindestrek i navnet.
jest.mock('./Widget', () => () => <mock-widget />); -
Bruk
react-test-renderer. Testrendereren bryr seg ikke om elementtyper og godtar f.eks.SomeComponentuten problemer. Du kan sjekke snapshots med testrendereren, og validere komponentatferd separat med Enzyme. -
Slå av alle advarsler (bør gjøres i Jest-oppsettfilen din):
jest.mock('fbjs/lib/warning', () => require('fbjs/lib/emptyFunction'));Dette bør normalt ikke være førstevalget ditt siden nyttige advarsler kan gå tapt. Men i noen tilfeller, f.eks. ved testing av react-native-komponenter, renderer vi react-native-tagger i DOM-en og mange advarsler er irrelevante. Et annet alternativ er å overstyre console.warn og dempe spesifikke advarsler.
DOM-testing
Hvis du ønsker å validere og manipulere renderte komponenter kan du bruke @testing-library/react, Enzyme eller Reacts TestUtils. Følgende eksempel bruker @testing-library/react.
@testing-library/react
- npm
- Yarn
- pnpm
- Bun
npm install --save-dev @testing-library/react
yarn add --dev @testing-library/react
pnpm add --save-dev @testing-library/react
bun add --dev @testing-library/react
La oss implementere en avkrysningsboks som bytter mellom to etiketter:
import {useState} from 'react';
export default function CheckboxWithLabel({labelOn, labelOff}) {
const [isChecked, setIsChecked] = useState(false);
const onChange = () => {
setIsChecked(!isChecked);
};
return (
<label>
<input type="checkbox" checked={isChecked} onChange={onChange} />
{isChecked ? labelOn : labelOff}
</label>
);
}
import {cleanup, fireEvent, render} from '@testing-library/react';
import CheckboxWithLabel from '../CheckboxWithLabel';
// Note: running cleanup afterEach is done automatically for you in @testing-library/react@9.0.0 or higher
// unmount and cleanup DOM after the test is finished.
afterEach(cleanup);
it('CheckboxWithLabel changes the text after click', () => {
const {queryByLabelText, getByLabelText} = render(
<CheckboxWithLabel labelOn="On" labelOff="Off" />,
);
expect(queryByLabelText(/off/i)).toBeTruthy();
fireEvent.click(getByLabelText(/off/i));
expect(queryByLabelText(/on/i)).toBeTruthy();
});
Eksempelkoden er tilgjengelig på examples/react-testing-library.
Egendefinerte transformatorer
Hvis du trenger mer avansert funksjonalitet, kan du også bygge din egen transformator. Istedenfor å bruke babel-jest, her er et eksempel med @babel/core:
'use strict';
const {transform} = require('@babel/core');
const jestPreset = require('babel-preset-jest');
module.exports = {
process(src, filename) {
const result = transform(src, {
filename,
presets: [jestPreset],
});
return result || src;
},
};
Husk å installere @babel/core og babel-preset-jest-pakker for at dette eksemplet skal fungere.
For å få dette til å fungere med Jest må du oppdatere Jest-konfigurasjonen din med: "transform": {"\\.js$": "path/to/custom-transformer.js"}.
Hvis du ønsker å bygge en transformator med Babel-støtte, kan du også bruke babel-jest til å komponere en og sende inn dine egendefinerte konfigurasjonsalternativer:
const babelJest = require('babel-jest');
module.exports = babelJest.createTransformer({
presets: ['my-custom-preset'],
});
Se dedikerte dokumenter for flere detaljer.