18/11/2025
Test af React-applikationer: En Dybdegående Guide med Jest og React Testing Library
At opnå solid testdækning er afgørende for at opbygge tillid til din webapplikation. I React-økosystemet er Jest og React Testing Library (RTL) to uundværlige værktøjer, der arbejder tæt sammen for at sikre kvalitet og pålidelighed. Disse værktøjer er ofte inkluderet som standard i projekter bootstrappet med Create React App, hvilket gør det nemt at komme i gang med testning fra starten. Denne artikel vil guide dig gennem processen med at opsætte et testmiljø, skrive effektive tests for både statiske UI-elementer og asynkron funktionalitet, samt hvordan du håndterer API-kald gennem mocking. Vi vil bruge et praktisk eksempel, "Doggy Directory", til at demonstrere disse koncepter.

Hvorfor er Testning Vigtigt?
Testning er ikke blot en god praksis; det er en nødvendighed for at levere stabile og fejlfri applikationer. Gennem test kan du:
- Opdage fejl tidligt: Identificer og ret fejl i udviklingsfasen, hvilket sparer tid og ressourcer på lang sigt.
- Forbedre kodekvaliteten: Tvinger dig til at tænke over din kodestruktur og grænseflader.
- Øge tilliden: Giv dig selv og dit team selvtillid til at foretage ændringer og refaktoreringer uden frygt for at introducere regressioner.
- Fremme bedre design: Opmuntrer til at skrive mere modulær og testbar kode.
Værktøjerne: Jest og React Testing Library
Jest er en populær JavaScript-testrunner, der giver en omfattende pakke af funktioner til at skrive og køre tests. Den er kendt for sin hastighed, brugervenlighed og indbyggede funktioner som mocking og snapshot-testning. Jest kører tests i et Node.js-miljø, hvilket sikrer hurtig feedback og eliminerer browser-specifikke problemer.
React Testing Library, derimod, fokuserer på at teste React-komponenter på en måde, der afspejler, hvordan brugerne interagerer med dem. I stedet for at teste komponenternes interne implementeringsdetaljer, opfordrer RTL til at skrive tests baseret på DOM-struktur og brugeradfærd. Dette resulterer i mere robuste tests, der er mindre tilbøjelige til at gå i stykker, når komponenternes interne logik ændres.
Begge værktøjer er tæt integreret med Create React App (CRA). Når du opretter et nyt React-projekt med `npx create-react-app my-app`, får du automatisk Jest og React Testing Library sat op og klar til brug.
Opsætning af Projektet
Lad os starte med at klone et eksempelprojekt og sætte vores testmiljø op. Projektet, "Doggy Directory", bruger Dog API til at vise billeder af hunderacer.
Åbn din terminal og kør følgende kommandoer:
git clone https://github.com/do-community/doggy-directory cd doggy-directory npm install Når installationen er færdig, kan du starte applikationen lokalt med:
npm start Applikationen vil åbne i din browser på http://localhost:3000/. Nu er det tid til at køre testene. I en ny terminalfane skal du navigere til projektmappen og køre:
npm test Dette starter Jest i watch mode. I denne tilstand genkører Jest automatisk testene, hver gang du gemmer en fil, hvilket giver hurtig feedback på dine ændringer.
Test af Landing Page
Jest leder som standard efter testfiler med filendelsen .test.js eller .spec.js, eller filer inde i mapper navngivet __tests__. Lad os se på den grundlæggende testfil i src/App.test.js:
import { render, screen } from '@testing-library/react' ; import App from './App' ; test ( 'renders the landing page', ( ) => { render ( < App / > ) ; } Denne test sikrer blot, at applikationen kan renderes uden fejl. Lad os udvide den til at tjekke specifikke UI-elementer på landingssiden:
import { render, screen } from '@testing-library/react' ; import App from './App' ; test ( 'renders the landing page', ( ) => { render ( < App / > ) ; expect ( screen . getByRole ( "heading" ) ) . toHaveTextContent ( / Doggy Directory / ) ; expect ( screen . getByRole ( "combobox" ) ) . toHaveDisplayValue ( "Select a breed" ) ; expect ( screen . getByRole ( "button", { name: "Search" } ) ) . toBeDisabled ( ) ; expect ( screen . getByRole ( "img" ) ) . toBeInTheDocument ( ) ; } Lad os nedbryde disse assertions:
screen.getByRole("heading"): Finder et element med `heading` rollen (typisk et H1, H2 osv.)..toHaveTextContent(/Doggy Directory/): Tjekker, om elementet indeholder teksten "Doggy Directory".screen.getByRole("combobox"): Finder et dropdown-menuelement..toHaveDisplayValue("Select a breed"): Tjekker, om dropdown'en viser standardteksten "Select a breed".screen.getByRole("button", { name: "Search" }): Finder knappen med teksten "Search"..toBeDisabled(): Tjekker, om knappen er deaktiveret.screen.getByRole("img"): Finder et billed-element..toBeInTheDocument(): Tjekker, om billedet er til stede i DOM'en.
Når du gemmer src/App.test.js, vil du se, at testen passerer i din terminal:
PASS src/App.test.js ✓ renders the landing page (172 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Mocking af Fetch-metoden
Mange React-applikationer interagerer med eksterne API'er. For at teste disse interaktioner på en pålidelig måde, uden at være afhængig af den faktiske API, bruger vi mocking. Jest giver os mulighed for at erstatte den globale fetch-metode med en mock-funktion.
Først opretter vi en mock-fil i src/mocks/mockFetch.js, der simulerer API-svar:
// src/mocks/mockFetch.js const breedsListResponse = { message: { boxer: [], cattledog: [], dalmatian: [], husky: [], } }; const dogImagesResponse = { message: [ "https://images.dog.ceo/breeds/cattledog-australian/IMG_1042.jpg", "https://images.dog.ceo/breeds/cattledog-australian/IMG_5177.jpg" ] }; export default async function mockFetch(url) { switch (url) { case "https://dog.ceo/api/breeds/list/all": return { ok: true, status: 200, json: async () => breedsListResponse, }; case "https://dog.ceo/api/breed/husky/images": case "https://dog.ceo/api/breed/cattledog/images": return { ok: true, status: 200, json: async () => dogImagesResponse, }; default: throw new Error(`Unhandled request: ${url}`); } } Nu importerer og bruger vi denne mock i vores testfil:
// src/App.test.js import { render, screen } from '@testing-library/react' ; import mockFetch from "./mocks/mockFetch" ; import App from './App' ; beforeEach(() => { jest.spyOn(window, "fetch").mockImplementation(mockFetch); }); afterEach(() => { jest.restoreAllMocks(); }); test ( 'renders the landing page', ( ) => { render ( < App / > ) ; // ... (tidligere assertions) } jest.spyOn(window, "fetch").mockImplementation(mockFetch); erstatter den faktiske fetch-metode med vores mock. beforeEach sikrer, at denne mock er aktiv før hver test, og afterEach rydder op efter hver test.
Håndtering af `act`-advarslen
Når du mock'er API-kald, der opdaterer state, kan du støde på en act-advarsel. Dette sker, fordi state-opdateringen sker efter, at testen er afsluttet. For at løse dette skal vi bruge async/await og findBy*-queries fra React Testing Library.
Opdater din eksisterende test:
// src/App.test.js test ( 'renders the landing page', async ( ) => { render ( < App / > ) ; expect ( screen . getByRole ( "heading" ) ) . toHaveTextContent ( / Doggy Directory / ) ; expect ( screen . getByRole ( "combobox" ) ) . toHaveDisplayValue ( "Select a breed" ) ; // Brug findByRole for at vente på at optionen bliver tilgængelig expect ( await screen . findByRole ( "option", { name: "husky" } ) ) . toBeInTheDocument ( ) ; expect ( screen . getByRole ( "button", { name: "Search" } ) ) . toBeDisabled ( ) ; expect ( screen . getByRole ( "img" ) ) . toBeInTheDocument ( ) ; } await screen.findByRole(...) venter på, at et element med den specificerede rolle (her en option med navnet "husky") bliver tilgængelig i DOM'en. Dette sikrer, at testen kører, efter at de asynkrone operationer er fuldført, og eliminerer act-advarslen.

Test af Søgefunktionalitet
Lad os nu skrive en ny test for at verificere søgefunktionen og visningen af hundebilleder. Vi skal bruge user-event til at simulere brugerinteraktioner som at vælge en race og klikke på knappen.
Først skal vi importere user-event og waitForElementToBeRemoved:
// src/App.test.js import { render, screen, waitForElementToBeRemoved } from '@testing-library/react' ; import userEvent from '@testing-library/user-event' ; // ... (andre imports) Tilføj en ny testblok:
// src/App.test.js test ( "should be able to search and display dog image results", async ( ) => { render ( < App / > ) ; // 1. Vælg en race const select = screen . getByRole ( "combobox" ) ; expect ( await screen . findByRole ( "option", { name: "cattledog" } ) ) . toBeInTheDocument ( ) ; userEvent . selectOptions ( select, "cattledog" ) ; expect ( select ) . toHaveValue ( "cattledog" ) ; // 2. Klik på søgeknappen og vent på data const searchBtn = screen . getByRole ( "button", { name: "Search" } ) ; expect ( searchBtn ) . not . toBeDisabled ( ) ; userEvent . click ( searchBtn ) ; // Vent på at loading-indikatoren forsvinder await waitForElementToBeRemoved ( ( ) => screen . queryByText ( / Loading / i ) ) ; // 3. Verificer de viste billeder og resultatantal const dogImages = screen . getAllByRole ( "img" ) ; expect ( dogImages ) . toHaveLength ( 2 ) ; expect ( screen . getByText ( / 2 Results / i ) ) . toBeInTheDocument ( ) ; expect ( dogImages [ 0 ] ) . toHaveAccessibleName ( "cattledog 1 of 2" ) ; expect ( dogImages [ 1 ] ) . toHaveAccessibleName ( "cattledog 2 of 2" ) ; } Denne test simulerer følgende brugerflow:
- Vælger "cattledog" fra dropdown-menuen.
- Klikker på "Search"-knappen.
- Venter på, at en "Loading"-indikator forsvinder, hvilket indikerer, at data er hentet.
- Verificerer, at to billeder vises.
- Tjekker, at resultatantallet er korrekt.
- Bekræfter, at billedernes alternative tekster er korrekte.
Når du gemmer filen, vil du nu se to beståede tests:
PASS src/App.test.js ✓ renders the landing page (273 ms) ✓ should be able to search and display dog image results (123 ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Sammenfatning og Bedste Praksis
Jest og React Testing Library er et kraftfuldt par til at teste React-applikationer. Ved at fokusere på brugerinteraktioner med RTL og udnytte Jests mocking-kapaciteter, kan du opbygge robuste og pålidelige tests.
Nøglepunkter:
- Brug
getBy*,queryBy*, ogfindBy*: Vælg den korrekte query-metode baseret på, om elementet forventes at være til stede med det samme, potentielt ikke er til stede, eller er til stede efter en asynkron operation. - Simuler brugerinteraktioner med
user-event: Dette giver mere realistiske simuleringer end blot at udløse DOM-events direkte. - Mock API-kald: Brug
jest.spyOnogmockImplementation(eller mere avancerede værktøjer som Mock Service Worker) for at kontrollere API-responser. - Håndter asynkron kode med
async/awaitogwaitFor*: Sikr, at dine tests venter på, at asynkrone operationer er fuldført. - Overvej snapshot-testning: Til UI-komponenter kan snapshot-testning være nyttigt til at fange utilsigtede ændringer i renderingen.
Ved at følge disse principper kan du forbedre kvaliteten af dine React-applikationer betydeligt og opnå større tillid til din kodebase.
Ofte Stillede Spørgsmål (FAQ)
Bruger Create React App Jest?
Ja, Create React App bruger Jest som standard testrunner. Det er konfigureret og klar til brug ud af boksen.
Hvornår skal jeg bruge findBy* queries?
Brug findBy* queries, når du tester asynkron kode, hvor et element forventes at dukke op i DOM'en efter en vis forsinkelse, f.eks. efter et API-kald er fuldført.
Hvad er formålet med user-event?
user-event simulerer brugerinteraktioner som klik, tastaturinput og valg i dropdowns på en mere realistisk måde end direkte DOM-manipulation, hvilket fører til mere robuste tests.
Hvordan mock'er jeg globale API'er som fetch?
Du kan bruge jest.spyOn(window, 'fetch').mockImplementation(mockFunction) til at erstatte den globale fetch-metode med din egen mock-funktion, der returnerer foruddefinerede svar.
Er det nødvendigt at mock'e API'er?
Det er stærkt anbefalet, især i produktionsklar kode. Mocking sikrer, at dine tests er deterministiske, hurtige og uafhængige af eksterne services' tilgængelighed og respons.
Hvis du vil læse andre artikler, der ligner Test af React Apps med Jest og RTL, kan du besøge kategorien Teknologi.
