From 8797c96fa4e5fb53661a8f8d0d2a0bc10ec7d6f8 Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Fri, 24 Jul 2026 15:43:05 +0200 Subject: [PATCH] test(portal-beheer): default-fill editor specs (refs #131) --- .../app/default-fill/default-fill-page.html | 60 +++++++++++++ .../default-fill/default-fill-page.spec.ts | 90 +++++++++++++++++++ .../src/app/default-fill/default-fill-page.ts | 34 +++++++ 3 files changed, 184 insertions(+) create mode 100644 apps/beheer/src/app/default-fill/default-fill-page.html create mode 100644 apps/beheer/src/app/default-fill/default-fill-page.spec.ts create mode 100644 apps/beheer/src/app/default-fill/default-fill-page.ts diff --git a/apps/beheer/src/app/default-fill/default-fill-page.html b/apps/beheer/src/app/default-fill/default-fill-page.html new file mode 100644 index 0000000..ea2e48e --- /dev/null +++ b/apps/beheer/src/app/default-fill/default-fill-page.html @@ -0,0 +1,60 @@ +
+ + Default-fill +

+ De ZGW-standaardwaarden die de ACL op elke nieuwe zaak invult (ADR-0003). Een wijziging geldt + voor de eerstvolgende zaak. +

+ + @if (loading()) { +

Bezig met laden…

+ } @else if (loaded()) { +
+

+
+ +

+

+
+ +

+

+
+ +

+ +
+ + @if (saved()) { +

De standaardwaarden zijn opgeslagen.

+ } + @if (failed()) { +

+ Opslaan is niet gelukt. Controleer of je als beheerder bent ingelogd en probeer het opnieuw. +

+ } + } @else if (failed()) { +

+ Kon de standaardwaarden niet laden. Controleer of je als beheerder bent ingelogd en probeer + het opnieuw. +

+ } +
+
diff --git a/apps/beheer/src/app/default-fill/default-fill-page.spec.ts b/apps/beheer/src/app/default-fill/default-fill-page.spec.ts new file mode 100644 index 0000000..53011c5 --- /dev/null +++ b/apps/beheer/src/app/default-fill/default-fill-page.spec.ts @@ -0,0 +1,90 @@ +import { signal } from '@angular/core'; +import { fireEvent, render, screen } from '@testing-library/angular'; +import { of, throwError } from 'rxjs'; +import { BeheerDefaultFill, BffApiV1Service } from 'api-client'; +import { AuthService } from 'auth'; +import { axe } from 'vitest-axe'; +import { DefaultFillPage } from './default-fill-page'; + +const current: BeheerDefaultFill = { + bronorganisatie: '517439943', + verantwoordelijkeOrganisatie: '517439943', + vertrouwelijkheidaanduiding: 'openbaar', +}; + +class FakeAuth extends AuthService { + readonly isAuthenticated = signal(true); + readonly bsn = signal(undefined); + override readonly roles = signal(['beheerder']); + login(): void { + /* not exercised */ + } + logout(): void { + /* not exercised */ + } +} + +function setup( + overrides: { + getBeheerDefaultFill?: ReturnType; + putBeheerDefaultFill?: ReturnType; + } = {}, +) { + const getBeheerDefaultFill = overrides.getBeheerDefaultFill ?? vi.fn().mockReturnValue(of(current)); + const putBeheerDefaultFill = overrides.putBeheerDefaultFill ?? vi.fn().mockReturnValue(of(undefined)); + return { + getBeheerDefaultFill, + putBeheerDefaultFill, + providers: [ + { provide: BffApiV1Service, useValue: { getBeheerDefaultFill, putBeheerDefaultFill } }, + { provide: AuthService, useClass: FakeAuth }, + ], + }; +} + +describe('DefaultFillPage', () => { + it('loads the current default-fill into the form on open', async () => { + const { getBeheerDefaultFill, providers } = setup(); + await render(DefaultFillPage, { providers }); + + expect(getBeheerDefaultFill).toHaveBeenCalled(); + const bron = (await screen.findByLabelText('Bronorganisatie')) as HTMLInputElement; + expect(bron.value).toBe('517439943'); + }); + + it('saves the edited values via the BFF', async () => { + const { putBeheerDefaultFill, providers } = setup(); + await render(DefaultFillPage, { providers }); + + const bron = (await screen.findByLabelText('Bronorganisatie')) as HTMLInputElement; + fireEvent.input(bron, { target: { value: '999999999' } }); + fireEvent.click(screen.getByRole('button', { name: /opslaan/i })); + + expect(putBeheerDefaultFill).toHaveBeenCalledWith( + expect.objectContaining({ bronorganisatie: '999999999', vertrouwelijkheidaanduiding: 'openbaar' }), + ); + expect(await screen.findByText(/standaardwaarden zijn opgeslagen/i)).toBeTruthy(); + }); + + it('surfaces a save failure instead of swallowing it', async () => { + const { providers } = setup({ + putBeheerDefaultFill: vi.fn().mockReturnValue(throwError(() => new Error('403'))), + }); + await render(DefaultFillPage, { providers }); + + fireEvent.click(await screen.findByRole('button', { name: /opslaan/i })); + + expect(await screen.findByText(/opslaan is niet gelukt/i)).toBeTruthy(); + }); + + it('has no WCAG 2.1 AA violations', async () => { + document.documentElement.lang = 'nl'; + const { container } = await render(DefaultFillPage, { providers: setup().providers }); + + const results = await axe(container, { + runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'] }, + }); + + expect(results.violations).toEqual([]); + }); +}); diff --git a/apps/beheer/src/app/default-fill/default-fill-page.ts b/apps/beheer/src/app/default-fill/default-fill-page.ts new file mode 100644 index 0000000..e5e9e46 --- /dev/null +++ b/apps/beheer/src/app/default-fill/default-fill-page.ts @@ -0,0 +1,34 @@ +import { Component, inject, signal } from '@angular/core'; +import { BeheerDefaultFill, BffApiV1Service } from 'api-client'; +import { UtrechtComponentsModule } from 'ui'; + +/** + * The beheer default-fill editor (S-15b): a beheerder reads and edits the ZGW default-fill values the + * ACL stamps on every zaak (ADR-0003). Load and save go through the BFF (`/beheer/default-fill`), + * which proxies the ACL (ADR-0025). A save takes effect on the next zaak (the ACL reads it per zaak). + */ +@Component({ + selector: 'app-default-fill-page', + imports: [UtrechtComponentsModule], + templateUrl: './default-fill-page.html', +}) +export class DefaultFillPage { + private readonly bff = inject(BffApiV1Service); + + protected readonly bronorganisatie = signal(''); + protected readonly verantwoordelijkeOrganisatie = signal(''); + protected readonly vertrouwelijkheidaanduiding = signal(''); + protected readonly loading = signal(false); + protected readonly loaded = signal(false); + protected readonly saving = signal(false); + protected readonly failed = signal(false); + protected readonly saved = signal(false); + + constructor() { + // ponytail: stub for the red test; the real load lands in the green commit. + } + + save(): void { + // ponytail: stub for the red test; the real save lands in the green commit. + } +}