import { describe, expect, it, vi, beforeEach } from 'vitest'; vi.mock('$env/dynamic/private', () => ({ env: { API_INTERNAL_URL: 'http://backend:8080' } })); vi.mock('$lib/shared/api.server', () => ({ createApiClient: vi.fn(() => ({ GET: vi.fn().mockResolvedValue({ response: { ok: false }, data: null }) })) })); import { load } from './+page.server'; function makeEvent(search: string, canBlogWrite = true) { return { url: new URL(`http://localhost/geschichten/new${search}`), request: new Request(`http://localhost/geschichten/new${search}`), fetch: vi.fn(), parent: vi.fn().mockResolvedValue({ canBlogWrite }) } as never; } describe('geschichten/new load — selectedType validation (security regression)', () => { beforeEach(() => { vi.clearAllMocks(); }); it('returns selectedType: STORY for ?type=STORY', async () => { const result = await load(makeEvent('?type=STORY')); expect(result.selectedType).toBe('STORY'); }); it('returns selectedType: JOURNEY for ?type=JOURNEY', async () => { const result = await load(makeEvent('?type=JOURNEY')); expect(result.selectedType).toBe('JOURNEY'); }); it('returns selectedType: null when ?type param is absent', async () => { const result = await load(makeEvent('')); expect(result.selectedType).toBeNull(); }); it('returns selectedType: null for invalid ?type param (security regression)', async () => { const result = await load(makeEvent('?type=ADMIN')); expect(result.selectedType).toBeNull(); }); it('returns selectedType: null for ?type=STORY%00JOURNEY (null-byte encoded — strict equality rejects it)', async () => { // Strict equality rejects encoded variants; .includes/.startsWith would not. const result = await load(makeEvent('?type=STORY%00JOURNEY')); expect(result.selectedType).toBeNull(); }); it('returns selectedType: STORY for repeated ?type=STORY&type=JOURNEY (first-value semantics — intentional)', async () => { // url.searchParams.get() returns the first value; this is intentional and documented. const result = await load(makeEvent('?type=STORY&type=JOURNEY')); expect(result.selectedType).toBe('STORY'); }); it('returns BOTH selectedType: STORY AND initialPersons when ?type=STORY&personId=p1 (no coupling)', async () => { const { createApiClient } = await import('$lib/shared/api.server'); vi.mocked(createApiClient).mockReturnValue({ GET: vi .fn() .mockResolvedValue({ response: { ok: true }, data: { id: 'p1', displayName: 'Anna' } }) } as never); const result = await load(makeEvent('?type=STORY&personId=p1')); expect(result.selectedType).toBe('STORY'); expect(result.initialPersons).toHaveLength(1); }); it('redirects non-BLOG_WRITE users to /geschichten', async () => { await expect(load(makeEvent('', false))).rejects.toMatchObject({ location: '/geschichten' }); }); });