import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { errorMessage, PREVIEW_FAILED, LetterPreviewAdapter } from './letter-preview.adapter'; // Minimal Response stand-in — errorMessage only calls `.json()`. Avoids stubbing // globalThis.fetch to reach this trust boundary (TE-002). const fakeResponse = (body: unknown): Response => ({ json: () => Promise.resolve(body) }) as unknown as Response; describe('errorMessage (TE-002 trust boundary)', () => { it('surfaces the ProblemDetails detail when present', async () => { expect(await errorMessage(fakeResponse({ detail: 'Geen toegang.', status: 403 }))).toBe( 'Geen toegang.', ); }); it('falls back to PREVIEW_FAILED when the body has no detail', async () => { expect(await errorMessage(fakeResponse({ status: 500 }))).toBe(PREVIEW_FAILED); }); it('falls back to PREVIEW_FAILED when the body is not JSON', async () => { const res = { json: () => Promise.reject(new Error('not json')) } as unknown as Response; expect(await errorMessage(res)).toBe(PREVIEW_FAILED); }); }); // isDevMode() reads the `ngDevMode` global the Angular CLI defines away in a // production build. There is no ambient type for it in app code, so this is // accessed through an untyped bag rather than a `declare const`. const globals = globalThis as Record; const originalNgDevMode = globals['ngDevMode']; const setDevMode = (on: boolean) => { globals['ngDevMode'] = on; }; describe('LetterPreviewAdapter.preview (BIO-012)', () => { const okResponse = () => ({ ok: true, blob: () => Promise.resolve(new Blob()) }) as unknown as Response; afterEach(() => { globals['ngDevMode'] = originalNgDevMode; vi.unstubAllGlobals(); history.pushState({}, '', '/'); sessionStorage.clear(); }); it('sends no X-Role/X-Subject headers outside isDevMode()', async () => { setDevMode(false); history.pushState({}, '', '/?subject=111222333'); const fetchSpy = vi.fn().mockResolvedValue(okResponse()); vi.stubGlobal('fetch', fetchSpy); await new LetterPreviewAdapter().preview(); expect(fetchSpy.mock.calls[0][1].headers).toEqual({}); }); it('sends X-Role (and X-Subject when known) under isDevMode()', async () => { setDevMode(true); history.pushState({}, '', '/?subject=111222333'); const fetchSpy = vi.fn().mockResolvedValue(okResponse()); vi.stubGlobal('fetch', fetchSpy); await new LetterPreviewAdapter().preview(); const headers = fetchSpy.mock.calls[0][1].headers as Record; expect(headers['X-Role']).toBeDefined(); expect(headers['X-Subject']).toBe('111222333'); }); });