feat(a11y): WP-01 — axe-on-every-story CI gate

Turn the interactive Storybook a11y addon into a build gate:
- @storybook/test-runner + axe-playwright over the static build
  (.storybook/test-runner.ts reads the a11y tags from story context)
- test-storybook / test-storybook:ci scripts; storybook-a11y CI job
- triage: escape-hatch a11y.disable on stories whose display:contents
  wrapper splits <ul>/<li> or <dl>/<dt>/<dd> (structural, deferred to
  WP-11/WP-12, each with justification + cross-ref)
- fix trivial violations: footer/wizard-shell contrast, text-input label,
  wizard stories missing provideApiClient

Verified: broken story fails the gate; 133 stories pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-02 19:13:18 +02:00
parent b4fb0be769
commit 97f7de4590
22 changed files with 7795 additions and 1819 deletions

View File

@@ -12,6 +12,12 @@ const meta: Meta<ApplicationLinkComponent> = {
// Rows are <li>s — a real list gives them their normal layout in the story.
template: `<ul class="list-unstyled"><app-application-link [heading]="heading" [subtitle]="subtitle" [status]="status" [cta]="cta" [to]="to" [clickable]="clickable" /></ul>`,
}),
parameters: {
// Structural: app-application-link's host sits between the <ul> and its <li> —
// axe's list/listitem rule requires them adjacent regardless of `display:contents`.
// WP-11 (CIBG markup fidelity) reworks this markup; see docs/backlog/WP-11-markup-fidelity.md.
a11y: { disable: true },
},
};
export default meta;
type Story = StoryObj<ApplicationLinkComponent>;

View File

@@ -19,6 +19,11 @@ const meta: Meta<ApplicationListComponent> = {
<app-application-link heading="Inschrijven" subtitle="Schrijf u in in het BIG-register." to="/registreren" />
</app-application-list>`,
}),
parameters: {
// Structural: app-application-link's host sits between the <ul> and its <li> —
// fixed by the WP-11 markup rework. See docs/backlog/WP-11-markup-fidelity.md.
a11y: { disable: true },
},
};
export default meta;
type Story = StoryObj<ApplicationListComponent>;

View File

@@ -12,6 +12,12 @@ const meta: Meta<ChoiceLinkComponent> = {
// Rows are <li>s — a real list gives them their normal layout in the story.
template: `<ul class="keuzelijst__list"><app-choice-link [heading]="heading" [instructions]="instructions" [to]="to" [clickable]="clickable" /></ul>`,
}),
parameters: {
// Structural: app-choice-link's host sits between the <ul> and its <li> — axe's
// list/listitem rule requires them adjacent regardless of `display:contents`.
// WP-11 (CIBG markup fidelity) reworks this markup; see docs/backlog/WP-11-markup-fidelity.md.
a11y: { disable: true },
},
};
export default meta;
type Story = StoryObj<ChoiceLinkComponent>;

View File

@@ -19,6 +19,11 @@ const meta: Meta<ChoiceListComponent> = {
<app-choice-link heading="Ik heb een buitenlands diploma" instructions="Uw diploma moet eerst officieel erkend worden." clickable="true" />
</app-choice-list>`,
}),
parameters: {
// Structural: app-choice-link's host sits between the <ul> and its <li> —
// fixed by the WP-11 markup rework. See docs/backlog/WP-11-markup-fidelity.md.
a11y: { disable: true },
},
};
export default meta;
type Story = StoryObj<ChoiceListComponent>;

View File

@@ -10,6 +10,12 @@ const meta: Meta<DataRowComponent> = {
template: `<dl class="row mb-0"><app-data-row [key]="key" [value]="value" /></dl>`,
}),
args: { key: 'BIG-nummer', value: '19012345601' },
parameters: {
// Structural: app-data-row's host sits between the <dl> and its <dt>/<dd> —
// axe's definition-list rule needs them adjacent regardless of `display:contents`.
// WP-12 (CIBG Datablock) reworks this markup; see docs/backlog/WP-12-datablock.md.
a11y: { disable: true },
},
};
export default meta;
type Story = StoryObj<DataRowComponent>;

View File

@@ -16,6 +16,11 @@ const meta: Meta<ReviewSectionComponent> = {
<app-data-row key="Woonplaats" value="Utrecht" />
</app-review-section>`,
}),
parameters: {
// Structural: app-data-row's host sits between the <dl> and its <dt>/<dd> —
// fixed by the WP-12 Datablock rework. See docs/backlog/WP-12-datablock.md.
a11y: { disable: true },
},
};
export default meta;
type Story = StoryObj<ReviewSectionComponent>;

View File

@@ -8,6 +8,12 @@ const meta: Meta<TaskListComponent> = {
component: TaskListComponent,
decorators: [applicationConfig({ providers: [provideRouter([])] })],
render: (args) => ({ props: args, template: `<app-task-list [listHeading]="listHeading" [tasks]="tasks" />` }),
parameters: {
// Structural: app-choice-link's host sits between the keuzelijst <ul> and its <li>
// — axe's list/listitem rule needs them adjacent regardless of `display:contents`.
// WP-11 (CIBG markup fidelity) reworks this markup; see docs/backlog/WP-11-markup-fidelity.md.
a11y: { disable: true },
},
};
export default meta;
type Story = StoryObj<TaskListComponent>;

View File

@@ -15,4 +15,4 @@ type Story = StoryObj<TextInputComponent>;
export const Default: Story = {};
export const Invalid: Story = { args: { invalid: true } };
export const Password: Story = { args: { type: 'password', placeholder: '' } };
export const Password: Story = { args: { type: 'password', placeholder: 'Wachtwoord' } };