Files
atomic-design-poc/apps/ssp/src/app/registratie/application/aanvragen.store.spec.ts
T
ehoandClaude Sonnet 5 dd11eafe50 refactor: strip WP-/RB- ticket refs from apps and libs (RD-18)
204 WP-NN/RB-NN comments named a closed ticket instead of the code they
sit next to. git blame already records history and stays correct when
code moves; the comment does not. This sweep removes the reference and
keeps the sentence, across 95 files in apps/ and libs/ plus the
behaviour-spec generator's header text.

Eleven references stay: five story files justify an a11y disable per
the README's rule, and one line in a11y.mdx documents that convention.
Two sentences needed a rewrite, not a deletion, so the reference's
meaning survives its removal. behaviour-spec.mdx is regenerated, not
hand-edited.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 21:23:07 +02:00

78 lines
2.9 KiB
TypeScript

import { TestBed } from '@angular/core/testing';
import { describe, it, expect, vi } from 'vitest';
import { SUBMIT_FAILED } from '@shared/application/submit';
import { AanvragenAdapter } from '@registratie/infrastructure/aanvragen.adapter';
import { AanvragenStore } from './aanvragen.store';
const summary = (id: string) => ({
id,
type: 'registratie',
status: { tag: 'Concept', stepIndex: 0, stepCount: 3 },
documentIds: [],
createdAt: '2026-07-23T10:00:00Z',
updatedAt: '2026-07-23T10:00:00Z',
});
function setup(adapter: Partial<AanvragenAdapter>): AanvragenStore {
TestBed.configureTestingModule({
providers: [{ provide: AanvragenAdapter, useValue: adapter }],
});
// The store's own constructor kicks off `load()` (dashboard revisit refresh) —
// give every test a `list` so that initial call has something to resolve.
return TestBed.inject(AanvragenStore);
}
describe('AanvragenStore', () => {
it('loads and parses the list', async () => {
const store = setup({ list: () => Promise.resolve([summary('a'), summary('b')]) });
await store.load();
const s = store.aanvragen();
expect(s.tag).toBe('Success');
expect(s.tag === 'Success' && s.value.map((a) => a.id)).toEqual(['a', 'b']);
});
it('cancels optimistically and confirms via the DELETE endpoint', async () => {
const cancel = vi.fn().mockResolvedValue(undefined);
const store = setup({
list: () => Promise.resolve([summary('a'), summary('b')]),
cancel,
});
await store.load();
await store.cancel('a');
expect(cancel).toHaveBeenCalledWith('a');
const s = store.aanvragen();
expect(s.tag === 'Success' && s.value.map((a) => a.id)).toEqual(['b']);
expect(store.lastError()).toBeNull();
});
// A failed cancel must not be silent — the row rolls back AND the store
// surfaces the error the page renders. Before this fix it only rolled back
// (bare `catch { this.state.set(before) }`), so `lastError()` stayed null forever.
it('rolls back the removal and surfaces the error when the cancel fails', async () => {
const cancel = vi.fn().mockRejectedValue(new Error('boom'));
const store = setup({ list: () => Promise.resolve([summary('a')]), cancel });
await store.load();
await store.cancel('a');
const s = store.aanvragen();
expect(s.tag === 'Success' && s.value.map((a) => a.id)).toEqual(['a']); // reappears
expect(store.lastError()).toBe(SUBMIT_FAILED);
});
it('clears a stale error on the next cancel attempt', async () => {
const cancel = vi
.fn()
.mockRejectedValueOnce(new Error('boom'))
.mockResolvedValueOnce(undefined);
const store = setup({ list: () => Promise.resolve([summary('a'), summary('b')]), cancel });
await store.load();
await store.cancel('a');
expect(store.lastError()).toBe(SUBMIT_FAILED);
await store.cancel('b');
expect(store.lastError()).toBeNull();
});
});