Skip to content

Testen ​

Hoe de tests van dcr-components werken, en wat je doet als er een faalt

Alle tests van dcr-components draaien met één commando en één configuratie (libs/dcr-components/vitest.config.ts). Ze lopen ook in elke PR-build. De Tests-tab van de build toont ze in vier runs, uit diezelfde ene testrun (vitest.reporter.ts):

RunWat
Unithet project unit
Browserhet project browser
Stories (render en play)elke story: ze rendert en haar play-functie slaagt
Toegankelijkheid (axe)elke story: axe, met per overtreding de regel en elementen

Lokaal schrijft dezelfde run ze naar libs/dcr-components/test-output/test-runs/.

bash
npx nx test dcr-components

EΓ©n project draaien kan met --project, bv. npx nx test dcr-components --project=storybook. Eenmalig per machine is Chromium voor Playwright nodig: npx playwright install chromium.

De drie projecten ​

ProjectBestandenOmgevingWaarvoor
unit*.spec.tsjsdomlogica en rendering die geen echte browser nodig hebben
browser*.browser.spec.tsChromiumwat jsdom niet kan: ElementInternals en formulieren, focus, layout
storybookelke storyChromiumelke story rendert, haar play-functie slaagt en axe vindt geen toegankelijkheidsfouten

Een story is dus een test: ook zonder play-functie controleert het storybook-project dat ze foutloos rendert en toegankelijk is.

Play-functies ​

  • Wacht op een toestand met waitFor(() => expect(…)), niet met een vaste pauze (setTimeout). Gebruik de standaardtimeout; een timeout korter dan het poll-interval (50 ms) faalt willekeurig.
  • Laat de story in een geldige eindtoestand achter: de toegankelijkheidscontrole loopt na de play-functie (een knop zonder label na de test faalt dus).
  • Een story die een element gebruikt, importeert dat element zelf. Zonder import werkt ze enkel als een andere story het toevallig al laadde.

Toegankelijkheid (a11y) ​

Een axe-overtreding laat de testrun falen (a11y.test: 'error' in .storybook/preview.ts), ook lokaal: de run eindigt met een lijst van de stories met axe-fouten. De story-test zelf blijft groen, zodat een story één keer per oorzaak in de Tests-tab staat: een fout van render of play onder Stories, een axe-fout onder Toegankelijkheid. Een story met een axe-fout krijgt ook gewoon haar screenshot.

Een eigen --reporter op de command line vervangt de reporters van de configuratie, en daarmee de axe-controle: gebruik npx nx test dcr-components of npx vitest run zonder --reporter.

  • Los de oorzaak op in de component als het een fout van de component is (een knop zonder naam, een rol die niet mag).
  • Los ze op in de story als enkel het voorbeeld onvolledig is (een icon-button zonder aria-label, een list-item zonder lijst rond).
  • Kan het echt nog niet, zet dan op die ene story parameters: { a11y: { test: 'todo' } } met een // TODO a11y: die zegt waarom. Schakel nooit een regel globaal uit. Onder Toegankelijkheid staat zo'n story als niet uitgevoerd, met haar overtredingen erbij.
  • color-contrast loopt mee, in het lichte thema. Tekst van een uitgeschakeld element is vrijgesteld (WCAG 1.4.3), maar axe weet enkel dat iets uitgeschakeld is via disabled op een formulierelement of aria-disabled="true" op de tekst of een voorouder ervan. Staat de tekst niet in de uitgeschakelde control (een label of beschrijving ernaast), zet aria-disabled dan op het element rond de tekst. Op een generiek element (div, span) dient dat enkel axe: een screenreader kondigt het daar niet aan, dat doet de control zelf (disabled, of aria-disabled op een element met een rol).
  • De controle wacht tot lopende animaties klaar zijn (afterEach in .storybook/preview.ts), anders meet axe tekst die nog aan het infaden is. Web Animations (element.animate(), CSS-animaties en -transities) vindt ze zelf. Beweging via requestAnimationFrame of timers telt mee als de component ze meldt aan de motion tracker (beginMotion() in _shared/motion/motion-tracker.ts), zoals de jelly-controller en de gestaffelde reveal van dcr-radial-menu doen. Een nieuwe animatie die niet via Web Animations of de jelly-controller loopt, meldt zich daar dus ook.

Visuele regressie ​

In de build neemt het storybook-project in dezelfde run een screenshot van elke story: na de play-functie, het wachten op animaties en de axe-controle (afterEach in .storybook/vitest.setup.ts). Een tweede render is er niet voor nodig. De screenshot toont het hele story-venster (1200 Γ— 900), dus ook menu's en tooltips die buiten hun element vallen.

tools/story-review/src/compare.mjs vergelijkt die screenshots met de baseline: de screenshots van de laatste groene build op develop. Een push naar develop wordt zelf de nieuwe baseline.

  • Wijzigt, verschijnt of verdwijnt een story in een PR, dan eindigt de build als gedeeltelijk geslaagd met een waarschuwing per story, en krijgt de PR de status dcr/visual-regression failed: de PR wacht tot iemand de wijziging beoordeelt.
  • De tab Visueel bij de build toont links de baseline, rechts de nieuwe screenshot. Verschil tonen (d) kleurt de gewijzigde pixels groen. Hetzelfde rapport staat als index.html in het artifact visual-report.
  • Is de wijziging gewild, kies dan Accepteren (a) of Alles accepteren in de tab Visueel van de laatste build van de PR. De status wordt succeeded en de volgende builds van de PR tonen die stories als geaccepteerd, zolang hun screenshot niet opnieuw wijzigt. Is het een regressie, los ze dan op en push opnieuw.
  • De tab Toegankelijkheid toont per story wat axe vond: regel, impact, elementen en een link naar uitleg.
  • Instabiel wil zeggen dat de story niet stilstond: twee screenshots na elkaar verschilden nog na 3 seconden. Het rapport toont dan de laatste twee screenshots met wat er bewoog in het groen, en het verloop van de screenshots (A B C: bleef veranderen, A B A B: wisselt tussen twee beelden). Dezelfde informatie staat in de build-log.

Storybook-preview ​

Elke PR-build zet zijn Storybook online op https://docs.kabas.be/previews/die-core/<commit>/, met <commit> de commit die naar de PR gepusht werd. De PR krijgt de status dcr/storybook-preview met die link, en in de tabs Visueel en Kwaliteit linkt Storybook naar die preview, in de kop en per story: zo bekijk en bedien je de stories zonder de branch lokaal op te halen. Elke build op develop overschrijft https://docs.kabas.be/previews/die-core/develop/: daar linkt de componentfiche in de hub naar.

De previews van een PR verdwijnen met de PR: de build op develop ruimt die van de gemergde PR op, en die van PR's die de laatste 14 dagen afgebroken werden.

TurboSnap ​

In een PR-build draait het storybook-project (render, play, axe Γ©n screenshot) enkel de story-bestanden die de PR kan veranderen. tools/story-review/src/affected-stories.mjs volgt elk gewijzigd bestand door de modulegraaf van de Storybook-build (preview-stats.json) naar de stories die het importeren, ook onrechtstreeks. Een wijziging aan dcr-button test zo de stories van de knoppen en van elk component dat een knop gebruikt; een wijziging aan enkel een story test enkel die story.

  • Alles draait bij een wijziging die niet in de graaf zit maar elke story kan raken: dependencies (package-lock.json), .storybook/, de Vitest- en Vite-config, cds-tokens, statische bestanden (public/), een Sass-partial of een ander bestand van de lib dat de graaf niet kent. De build-log toont waarom.
  • Niets draait bij enkel tests, documentatie of bestanden buiten de lib (pipelines, andere libs).
  • Unit- en browsertests draaien altijd volledig, en op develop draaien alle stories. De coverage van een PR-build telt daardoor enkel de geteste stories mee.
  • Het rapport meldt stories die niet draaiden niet als verdwenen.

Een story die nooit stilstaat (een Rive-animatie, iets dat van het netwerk komt) sluit je uit, met een comment die zegt waarom:

ts
parameters: { visual: { disableSnapshot: true } },

Is maar een deel onvoorspelbaar, zet dan data-visual="ignore" op dat deel: het blijft plaats innemen, maar het wordt niet vergeleken.

Lokaal kan je twee eigen runs vergelijken, bv. voor en na een wijziging. Vergelijk niet met de baseline van de build: een andere machine rendert net andere pixels.

bash
cd libs/dcr-components
VISUAL_SNAPSHOTS=test-output/visual/voor npx vitest run --project=storybook
VISUAL_SNAPSHOTS=test-output/visual/na npx vitest run --project=storybook
node ../../tools/story-review/bin/story-review.mjs compare --current test-output/visual/na --baseline test-output/visual/voor --report test-output/visual/rapport

Coverage ​

In CI draait de suite met coverage over de drie projecten samen, de stories inbegrepen. De build toont per bestand en per regel welke code de tests raken, in de tab Code Coverage; de resultaten per test staan in de tab Tests. Lokaal:

bash
npx nx test dcr-components --coverage

Het rapport staat dan in libs/dcr-components/test-output/vitest/coverage/index.html.

Lukt een test lokaal niet? ​

  • Zie je "Vite unexpectedly reloaded a test"? Een dependency wordt pas tijdens de run ontdekt. Voeg ze toe aan optimizeDeps.include in .storybook/main.ts.
  • Ontbreekt het thema of zijn de stijlen leeg? De tests bouwen cds-tokens zelf als de dist ontbreekt; bij een verouderde dist: npx nx build cds-tokens.