fix(tests): add missing Sentry mock event fields across 14 spec files; fix test:coverage semicolon
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m25s
CI / OCR Service Tests (pull_request) Successful in 21s
CI / Backend Unit Tests (pull_request) Successful in 3m23s
CI / fail2ban Regex (pull_request) Successful in 41s
CI / Semgrep Security Scan (pull_request) Successful in 20s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m2s

`@sentry/sveltekit` wraps load functions and reads `event.request.method` and
`event.url.pathname`. Mock events that omitted `request` or `url` threw
`TypeError: Cannot read properties of undefined` on every invocation, silently
masking 86 test failures on main.

Two root causes fixed:
- Added `request: new Request(...)` (and `url: new URL(...)` where absent) to
  all mock event objects in 14 `*.server.spec.ts` files
- Changed `;` to `&&` in the `test:coverage` npm script so a failing server
  run propagates its exit code instead of being swallowed by the client run

All 576 server-project tests now pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-19 10:27:11 +02:00
parent 741b2231f2
commit 07415a5b2b
15 changed files with 282 additions and 46 deletions

View File

@@ -16,7 +16,7 @@
"lint:boundary-demo": "eslint src/lib/tag/__fixtures__/",
"test:unit": "vitest",
"test": "npm run test:unit -- --run",
"test:coverage": "vitest run --coverage --project=server; vitest run -c vitest.client-coverage.config.ts --coverage",
"test:coverage": "vitest run --coverage --project=server && vitest run -c vitest.client-coverage.config.ts --coverage",
"test:e2e": "playwright test",
"test:e2e:headed": "playwright test --headed",
"test:e2e:ui": "playwright test --ui",

View File

@@ -19,14 +19,22 @@ describe('admin/groups layout load', () => {
{ id: 'g1', name: 'Admins', permissions: ['ADMIN'] },
{ id: 'g2', name: 'Editors', permissions: ['WRITE_ALL'] }
]);
const result = await load({ fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/groups'),
url: new URL('http://localhost/admin/groups')
});
expect(result.groups).toHaveLength(2);
expect(result.groups[0].name).toBe('Admins');
});
it('returns an empty array when the API returns nothing', async () => {
mockApi([]);
const result = await load({ fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/groups'),
url: new URL('http://localhost/admin/groups')
});
expect(result.groups).toEqual([]);
});
@@ -35,7 +43,11 @@ describe('admin/groups layout load', () => {
vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
typeof createApiClient
>);
await load({ fetch: vi.fn() as unknown as typeof fetch });
await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/groups'),
url: new URL('http://localhost/admin/groups')
});
expect(mockGet).toHaveBeenCalledWith('/api/groups');
});
});

View File

@@ -26,26 +26,46 @@ beforeEach(() => vi.clearAllMocks());
describe('admin layout load — permission check', () => {
it('throws 403 when user has no admin permission', async () => {
await expect(
load({ fetch: vi.fn() as unknown as typeof fetch, locals: { user: noPermUser } })
load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin'),
url: new URL('http://localhost/admin'),
locals: { user: noPermUser }
})
).rejects.toMatchObject({ status: 403 });
});
it('throws 403 when user is undefined', async () => {
await expect(
load({ fetch: vi.fn() as unknown as typeof fetch, locals: { user: undefined } })
load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin'),
url: new URL('http://localhost/admin'),
locals: { user: undefined }
})
).rejects.toMatchObject({ status: 403 });
});
it('throws 403 when user has no groups', async () => {
await expect(
load({ fetch: vi.fn() as unknown as typeof fetch, locals: { user: { groups: [] } } })
load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin'),
url: new URL('http://localhost/admin'),
locals: { user: { groups: [] } }
})
).rejects.toMatchObject({ status: 403 });
});
it('allows access for a user with ADMIN_TAG only', async () => {
mockApi([], [], []);
await expect(
load({ fetch: vi.fn() as unknown as typeof fetch, locals: { user: tagAdminUser } })
load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin'),
url: new URL('http://localhost/admin'),
locals: { user: tagAdminUser }
})
).resolves.toBeDefined();
});
@@ -63,6 +83,8 @@ describe('admin layout load — permission check', () => {
const result = await load({
fetch: mockFetch as unknown as typeof fetch,
request: new Request('http://localhost/admin'),
url: new URL('http://localhost/admin'),
locals: { user: adminUser }
});

View File

@@ -15,7 +15,12 @@ describe('admin/ocr/[personId] — load', () => {
data: { runs: [], personNames: { [personId]: 'Anna Müller' } }
});
const result = (await load({ params: { personId }, fetch } as never))!;
const result = (await load({
params: { personId },
fetch,
request: new Request('http://localhost/admin/ocr/123'),
url: new URL('http://localhost/admin/ocr/123')
} as never))!;
expect(result.history.personNames?.[personId]).toBe('Anna Müller');
});
@@ -27,7 +32,12 @@ describe('admin/ocr/[personId] — load', () => {
});
await expect(
load({ params: { personId: 'unknown-id' }, fetch } as never)
load({
params: { personId: 'unknown-id' },
fetch,
request: new Request('http://localhost/admin/ocr/unknown-id'),
url: new URL('http://localhost/admin/ocr/unknown-id')
} as never)
).rejects.toMatchObject({ status: 404 });
});
});

View File

@@ -14,7 +14,11 @@ describe('admin/ocr/global — load', () => {
data: { runs: [{ id: 'run1' }], personNames: {} }
});
const result = (await load({ fetch } as never))!;
const result = (await load({
fetch,
request: new Request('http://localhost/admin/ocr/global'),
url: new URL('http://localhost/admin/ocr/global')
} as never))!;
expect(result.history.runs).toHaveLength(1);
});
@@ -22,6 +26,12 @@ describe('admin/ocr/global — load', () => {
it('throws error when API call fails', async () => {
mockApi.GET.mockResolvedValue({ response: { ok: false, status: 500 }, error: {} });
await expect(load({ fetch } as never)).rejects.toMatchObject({ status: 500 });
await expect(
load({
fetch,
request: new Request('http://localhost/admin/ocr/global'),
url: new URL('http://localhost/admin/ocr/global')
} as never)
).rejects.toMatchObject({ status: 500 });
});
});

View File

@@ -14,7 +14,11 @@ describe('admin/ocr — load', () => {
data: { availableBlocks: 10, ocrServiceAvailable: true, senderModels: [] }
});
const result = (await load({ fetch } as never))!;
const result = (await load({
fetch,
request: new Request('http://localhost/admin/ocr'),
url: new URL('http://localhost/admin/ocr')
} as never))!;
expect(result.trainingInfo.availableBlocks).toBe(10);
expect(result.trainingInfo.ocrServiceAvailable).toBe(true);
@@ -23,6 +27,12 @@ describe('admin/ocr — load', () => {
it('throws 503 when OCR API call fails', async () => {
mockApi.GET.mockResolvedValue({ response: { ok: false, status: 503 }, error: {} });
await expect(load({ fetch } as never)).rejects.toMatchObject({ status: 503 });
await expect(
load({
fetch,
request: new Request('http://localhost/admin/ocr'),
url: new URL('http://localhost/admin/ocr')
} as never)
).rejects.toMatchObject({ status: 503 });
});
});

View File

@@ -21,6 +21,7 @@ describe('tags/[id] — load function', () => {
const result = await load({
params: { id: 't1' },
parent: async () => ({ tags: [{ id: 't1', name: 'Test', documentCount: 0 }] }),
request: new Request('http://localhost/admin/tags/t1'),
url
} as never);
expect((result as { mergeSuccess: boolean }).mergeSuccess).toBe(true);
@@ -31,6 +32,7 @@ describe('tags/[id] — load function', () => {
const result = await load({
params: { id: 't1' },
parent: async () => ({ tags: [{ id: 't1', name: 'Test', documentCount: 0 }] }),
request: new Request('http://localhost/admin/tags/t1'),
url
} as never);
expect((result as { mergeSuccess: boolean }).mergeSuccess).toBe(false);

View File

@@ -44,14 +44,22 @@ const sampleTree = [
describe('admin/tags layout load', () => {
it('returns the tree list', async () => {
mockTreeApi(sampleTree);
const result = await load({ fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/tags'),
url: new URL('http://localhost/admin/tags')
});
expect(result.tree).toHaveLength(2);
expect(result.tree[0].name).toBe('Familie');
});
it('returns an empty tree when the API returns nothing', async () => {
mockTreeApi([]);
const result = await load({ fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/tags'),
url: new URL('http://localhost/admin/tags')
});
expect(result.tree).toEqual([]);
});
@@ -60,13 +68,21 @@ describe('admin/tags layout load', () => {
vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
typeof createApiClient
>);
await load({ fetch: vi.fn() as unknown as typeof fetch });
await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/tags'),
url: new URL('http://localhost/admin/tags')
});
expect(mockGet).toHaveBeenCalledWith('/api/tags/tree');
});
it('flattens the tree into a flat tags array', async () => {
mockTreeApi(sampleTree);
const result = await load({ fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/tags'),
url: new URL('http://localhost/admin/tags')
});
// Both parent and child should be in the flat array
expect(result.tags).toHaveLength(3);
expect(result.tags.map((t) => t.name)).toContain('Eltern');
@@ -74,14 +90,22 @@ describe('admin/tags layout load', () => {
it('preserves parentId on child tags in the flat array', async () => {
mockTreeApi(sampleTree);
const result = await load({ fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/tags'),
url: new URL('http://localhost/admin/tags')
});
const child = result.tags.find((t) => t.name === 'Eltern');
expect(child?.parentId).toBe('parent1');
});
it('sets parentId to undefined on root tags in the flat array', async () => {
mockTreeApi(sampleTree);
const result = await load({ fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
fetch: vi.fn() as unknown as typeof fetch,
request: new Request('http://localhost/admin/tags'),
url: new URL('http://localhost/admin/tags')
});
const root = result.tags.find((t) => t.name === 'Familie');
expect(root?.parentId).toBeUndefined();
});

View File

@@ -29,7 +29,11 @@ beforeEach(() => {
describe('aktivitaeten/load — core', () => {
it('requests only unread notifications for Für-dich', async () => {
mockSuccess();
await load({ fetch, url: buildUrl() } as never);
await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl()
} as never);
expect(mockApi.GET).toHaveBeenCalledWith('/api/notifications', {
params: { query: { read: false, page: 0, size: 20 } }
});
@@ -45,7 +49,11 @@ describe('aktivitaeten/load — core', () => {
return Promise.resolve({ response: { ok: true }, data: { content: unread } });
});
const result = await load({ fetch, url: buildUrl() } as never);
const result = await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl()
} as never);
expect(result.activityFeed).toEqual(feed);
expect(result.unreadNotifications).toEqual(unread);
@@ -61,7 +69,11 @@ describe('aktivitaeten/load — core', () => {
return Promise.resolve({ response: { ok: true }, data: { content: [] } });
});
const result = await load({ fetch, url: buildUrl() } as never);
const result = await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl()
} as never);
expect(result.loadError).toBe('activity');
expect(result.activityFeed).toEqual([]);
@@ -69,11 +81,19 @@ describe('aktivitaeten/load — core', () => {
it('parses the filter query param, falling back to "alle" for invalid values', async () => {
mockApi.GET.mockResolvedValue({ response: { ok: true }, data: [] });
const validResult = await load({ fetch, url: buildUrl('?filter=fuer-dich') } as never);
const validResult = await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl('?filter=fuer-dich')
} as never);
expect(validResult.filter).toBe('fuer-dich');
mockApi.GET.mockResolvedValue({ response: { ok: true }, data: [] });
const invalidResult = await load({ fetch, url: buildUrl('?filter=bogus') } as never);
const invalidResult = await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl('?filter=bogus')
} as never);
expect(invalidResult.filter).toBe('alle');
});
});
@@ -81,7 +101,11 @@ describe('aktivitaeten/load — core', () => {
describe('aktivitaeten/load — kinds param per filter', () => {
it('omits kinds for filter=alle (server defaults to ROLLUP_ELIGIBLE)', async () => {
mockSuccess();
await load({ fetch, url: buildUrl() } as never);
await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl()
} as never);
expect(mockApi.GET).toHaveBeenCalledWith('/api/dashboard/activity', {
params: { query: { limit: 40 } }
});
@@ -89,7 +113,11 @@ describe('aktivitaeten/load — kinds param per filter', () => {
it('omits kinds for filter=fuer-dich (client-side filtering on youMentioned/youParticipated)', async () => {
mockSuccess();
await load({ fetch, url: buildUrl('?filter=fuer-dich') } as never);
await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl('?filter=fuer-dich')
} as never);
expect(mockApi.GET).toHaveBeenCalledWith('/api/dashboard/activity', {
params: { query: { limit: 40 } }
});
@@ -97,7 +125,11 @@ describe('aktivitaeten/load — kinds param per filter', () => {
it('sends kinds=FILE_UPLOADED for filter=hochgeladen', async () => {
mockSuccess();
await load({ fetch, url: buildUrl('?filter=hochgeladen') } as never);
await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl('?filter=hochgeladen')
} as never);
expect(mockApi.GET).toHaveBeenCalledWith('/api/dashboard/activity', {
params: { query: { limit: 40, kinds: ['FILE_UPLOADED'] } }
});
@@ -105,7 +137,11 @@ describe('aktivitaeten/load — kinds param per filter', () => {
it('sends TEXT_SAVED, BLOCK_REVIEWED, ANNOTATION_CREATED for filter=transkription', async () => {
mockSuccess();
await load({ fetch, url: buildUrl('?filter=transkription') } as never);
await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl('?filter=transkription')
} as never);
expect(mockApi.GET).toHaveBeenCalledWith('/api/dashboard/activity', {
params: {
query: {
@@ -120,7 +156,11 @@ describe('aktivitaeten/load — kinds param per filter', () => {
it('sends COMMENT_ADDED, MENTION_CREATED for filter=kommentare', async () => {
mockSuccess();
await load({ fetch, url: buildUrl('?filter=kommentare') } as never);
await load({
fetch,
request: new Request('http://localhost/aktivitaeten'),
url: buildUrl('?filter=kommentare')
} as never);
expect(mockApi.GET).toHaveBeenCalledWith('/api/dashboard/activity', {
params: {
query: {

View File

@@ -40,6 +40,7 @@ describe('korrespondenz load — no senderId', () => {
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/briefwechsel'),
fetch: vi.fn() as unknown as typeof fetch,
locals: { user: readUser }
});
@@ -69,6 +70,7 @@ describe('korrespondenz load — senderId set, no receiverId', () => {
const result = await load({
url: makeUrl({ senderId: 'p1' }),
request: new Request('http://localhost/briefwechsel'),
fetch: vi.fn() as unknown as typeof fetch,
locals: { user: readUser }
});
@@ -108,6 +110,7 @@ describe('korrespondenz load — senderId and receiverId set', () => {
const result = await load({
url: makeUrl({ senderId: 'p1', receiverId: 'p2' }),
request: new Request('http://localhost/briefwechsel'),
fetch: vi.fn() as unknown as typeof fetch,
locals: { user: readUser }
});
@@ -137,6 +140,7 @@ describe('korrespondenz load — canWrite', () => {
const result = await load({
url: makeUrl({ senderId: 'p1' }),
request: new Request('http://localhost/briefwechsel'),
fetch: vi.fn() as unknown as typeof fetch,
locals: { user: writeUser }
});
@@ -160,6 +164,7 @@ describe('korrespondenz load — canWrite', () => {
const result = await load({
url: makeUrl({ senderId: 'p1' }),
request: new Request('http://localhost/briefwechsel'),
fetch: vi.fn() as unknown as typeof fetch,
locals: { user: readUser }
});
@@ -188,6 +193,7 @@ describe('korrespondenz load — backend error', () => {
await expect(
load({
url: makeUrl({ senderId: 'p1' }),
request: new Request('http://localhost/briefwechsel'),
fetch: vi.fn() as unknown as typeof fetch,
locals: { user: readUser }
})

View File

@@ -23,7 +23,9 @@ describe('document detail load — happy path', () => {
const result = await load({
params: { id: '123' },
fetch: mockFetch as unknown as typeof fetch
fetch: mockFetch as unknown as typeof fetch,
request: new Request('http://localhost/documents/123'),
url: new URL('http://localhost/documents/123')
});
expect(result.document.title).toBe('Testbrief');
@@ -44,7 +46,12 @@ describe('document detail load — error paths', () => {
const mockFetch = vi.fn();
await expect(
load({ params: { id: 'missing' }, fetch: mockFetch as unknown as typeof fetch })
load({
params: { id: 'missing' },
fetch: mockFetch as unknown as typeof fetch,
request: new Request('http://localhost/documents/123'),
url: new URL('http://localhost/documents/123')
})
).rejects.toMatchObject({ status: 404 });
});
@@ -59,7 +66,12 @@ describe('document detail load — error paths', () => {
const mockFetch = vi.fn();
await expect(
load({ params: { id: 'secret' }, fetch: mockFetch as unknown as typeof fetch })
load({
params: { id: 'secret' },
fetch: mockFetch as unknown as typeof fetch,
request: new Request('http://localhost/documents/123'),
url: new URL('http://localhost/documents/123')
})
).rejects.toMatchObject({ status: 403 });
});
@@ -74,7 +86,12 @@ describe('document detail load — error paths', () => {
const mockFetch = vi.fn();
await expect(
load({ params: { id: 'any' }, fetch: mockFetch as unknown as typeof fetch })
load({
params: { id: 'any' },
fetch: mockFetch as unknown as typeof fetch,
request: new Request('http://localhost/documents/123'),
url: new URL('http://localhost/documents/123')
})
).rejects.toMatchObject({ location: '/login' });
});
});

View File

@@ -6,7 +6,11 @@ describe('/documents/bulk-edit +page.server.ts', () => {
const locals = { user: { groups: [{ permissions: ['READ_ALL'] }] } };
try {
// @ts-expect-error — partial event shape sufficient for this guard
await load({ locals });
await load({
locals,
request: new Request('http://localhost/documents/bulk-edit'),
url: new URL('http://localhost/documents/bulk-edit')
});
throw new Error('expected redirect to be thrown');
} catch (e) {
const err = e as { status?: number; location?: string };
@@ -19,7 +23,11 @@ describe('/documents/bulk-edit +page.server.ts', () => {
const locals = { user: { groups: [] } };
try {
// @ts-expect-error — partial event shape sufficient for this guard
await load({ locals });
await load({
locals,
request: new Request('http://localhost/documents/bulk-edit'),
url: new URL('http://localhost/documents/bulk-edit')
});
throw new Error('expected redirect');
} catch (e) {
expect((e as { status?: number }).status).toBe(303);
@@ -30,7 +38,11 @@ describe('/documents/bulk-edit +page.server.ts', () => {
const locals = {};
try {
// @ts-expect-error — partial event shape sufficient for this guard
await load({ locals });
await load({
locals,
request: new Request('http://localhost/documents/bulk-edit'),
url: new URL('http://localhost/documents/bulk-edit')
});
throw new Error('expected redirect');
} catch (e) {
expect((e as { status?: number }).status).toBe(303);
@@ -40,7 +52,11 @@ describe('/documents/bulk-edit +page.server.ts', () => {
it('returns canWrite=true for a WRITE_ALL user', async () => {
const locals = { user: { groups: [{ permissions: ['WRITE_ALL', 'READ_ALL'] }] } };
// @ts-expect-error — partial event shape sufficient for this guard
const result = await load({ locals });
const result = await load({
locals,
request: new Request('http://localhost/documents/bulk-edit'),
url: new URL('http://localhost/documents/bulk-edit')
});
expect(result).toEqual({ canWrite: true });
});
@@ -52,7 +68,11 @@ describe('/documents/bulk-edit +page.server.ts', () => {
};
try {
// @ts-expect-error — partial event shape sufficient for this guard
await load({ locals });
await load({
locals,
request: new Request('http://localhost/documents/bulk-edit'),
url: new URL('http://localhost/documents/bulk-edit')
});
throw new Error('expected redirect');
} catch (e) {
expect((e as { status?: number }).status).toBe(303);

View File

@@ -33,6 +33,7 @@ describe('documents page load — search params', () => {
await load({
url: makeUrl({ q: 'Urlaub', from: '1920-01-01', to: '1950-12-31' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -57,6 +58,7 @@ describe('documents page load — search params', () => {
await load({
url: makeUrl({ senderId: 'p-1', receiverId: 'p-2' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -81,6 +83,7 @@ describe('documents page load — search params', () => {
await load({
url: makeUrl({ sort: 'TITLE', dir: 'asc', tagQ: 'fam' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -111,6 +114,7 @@ describe('documents page load — search params', () => {
const result = await load({
url: makeUrl({ q: 'test' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -129,6 +133,7 @@ describe('documents page load — search params', () => {
const result = await load({
url: makeUrl({ q: 'Urlaub', from: '1920-01-01', sort: 'TITLE', dir: 'asc' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -148,7 +153,11 @@ describe('documents page load — auth redirect', () => {
} as ReturnType<typeof createApiClient>);
await expect(
load({ url: makeUrl(), fetch: vi.fn() as unknown as typeof fetch })
load({
url: makeUrl(),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
})
).rejects.toMatchObject({ location: '/login' });
});
});
@@ -161,7 +170,11 @@ describe('documents page load — network error fallback', () => {
GET: vi.fn().mockRejectedValue(new Error('Network failure'))
} as ReturnType<typeof createApiClient>);
const result = await load({ url: makeUrl(), fetch: vi.fn() as unknown as typeof fetch });
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
expect(result.error).toBeTruthy();
expect(result.items).toEqual([]);
@@ -199,6 +212,7 @@ describe('documents page load — person name resolution', () => {
const result = await load({
url: makeUrl({ senderId: '11111111-1111-1111-1111-111111111111' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -210,6 +224,7 @@ describe('documents page load — person name resolution', () => {
const result = await load({
url: makeUrl({ receiverId: '22222222-2222-2222-2222-222222222222' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -221,6 +236,7 @@ describe('documents page load — person name resolution', () => {
const result = await load({
url: makeUrl({ senderId: 'not-a-uuid' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});
@@ -234,6 +250,7 @@ describe('documents page load — person name resolution', () => {
const result = await load({
url: makeUrl({ senderId: '11111111-1111-1111-1111-111111111111' }),
request: new Request('http://localhost/documents'),
fetch: vi.fn() as unknown as typeof fetch
});

View File

@@ -33,6 +33,7 @@ it('never calls /api/documents/search regardless of URL params', async () => {
await load({
url: makeUrl({ q: 'Urlaub', from: '2020-01-01' }),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -49,6 +50,7 @@ it('always fetches dashboard data regardless of URL params', async () => {
await load({
url: makeUrl({ q: 'Urlaub' }),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -110,6 +112,7 @@ describe('home page load — dashboard', () => {
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -147,6 +150,7 @@ describe('home page load — dashboard', () => {
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -168,6 +172,7 @@ describe('home page load — dashboard', () => {
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -189,6 +194,7 @@ describe('home page load — dashboard', () => {
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -213,6 +219,7 @@ describe('home page load — dashboard', () => {
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -232,6 +239,7 @@ describe('home page load — auth redirect', () => {
await expect(
load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0])
@@ -249,6 +257,7 @@ describe('home page load — network error fallback', () => {
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: contributorParent()
} as Parameters<typeof load>[0]);
@@ -268,6 +277,7 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: vi
.fn()
@@ -289,6 +299,7 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: vi
.fn()
@@ -310,6 +321,7 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: vi
.fn()
@@ -332,6 +344,7 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: vi.fn().mockResolvedValue({ canWrite: false, canAnnotate: false, canBlogWrite: true })
} as Parameters<typeof load>[0]);
@@ -352,6 +365,7 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: vi
.fn()
@@ -369,6 +383,7 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: vi.fn().mockResolvedValue({ canWrite: true, canAnnotate: false, canBlogWrite: false })
} as Parameters<typeof load>[0]);
@@ -398,6 +413,7 @@ describe('home page load — reader branch (isReader = !canWrite && !canAnnotate
const result = await load({
url: makeUrl(),
request: new Request('http://localhost/'),
fetch: vi.fn() as unknown as typeof fetch,
parent: vi
.fn()

View File

@@ -32,7 +32,13 @@ describe('person detail load — happy path', () => {
.mockResolvedValueOnce({ response: { ok: true }, data: [] })
} as ReturnType<typeof createApiClient>);
const result = await load({ params: { id: 'p1' }, fetch: mockFetch, locals: mockLocals });
const result = await load({
params: { id: 'p1' },
fetch: mockFetch,
request: new Request('http://localhost/persons/p1'),
url: new URL('http://localhost/persons/p1'),
locals: mockLocals
});
expect(result.person.firstName).toBe('Hans');
expect(result.sentDocuments).toHaveLength(1);
@@ -55,7 +61,13 @@ describe('person detail load — happy path', () => {
.mockResolvedValueOnce({ response: { ok: true }, data: [] })
} as ReturnType<typeof createApiClient>);
const result = await load({ params: { id: 'p1' }, fetch: mockFetch, locals: mockLocalsWriter });
const result = await load({
params: { id: 'p1' },
fetch: mockFetch,
request: new Request('http://localhost/persons/p1'),
url: new URL('http://localhost/persons/p1'),
locals: mockLocalsWriter
});
expect(result.canWrite).toBe(true);
});
@@ -76,7 +88,13 @@ describe('person detail load — happy path', () => {
.mockResolvedValueOnce({ response: { ok: true }, data: [] })
} as ReturnType<typeof createApiClient>);
const result = await load({ params: { id: 'p1' }, fetch: mockFetch, locals: mockLocals });
const result = await load({
params: { id: 'p1' },
fetch: mockFetch,
request: new Request('http://localhost/persons/p1'),
url: new URL('http://localhost/persons/p1'),
locals: mockLocals
});
expect(result.sentDocuments).toEqual([]);
expect(result.receivedDocuments).toEqual([]);
@@ -100,7 +118,13 @@ describe('person detail load — error paths', () => {
} as ReturnType<typeof createApiClient>);
await expect(
load({ params: { id: 'missing' }, fetch: mockFetch, locals: mockLocals })
load({
params: { id: 'missing' },
fetch: mockFetch,
request: new Request('http://localhost/persons/p1'),
url: new URL('http://localhost/persons/p1'),
locals: mockLocals
})
).rejects.toMatchObject({
status: 404
});
@@ -120,7 +144,13 @@ describe('person detail load — error paths', () => {
} as ReturnType<typeof createApiClient>);
await expect(
load({ params: { id: 'forbidden' }, fetch: mockFetch, locals: mockLocals })
load({
params: { id: 'forbidden' },
fetch: mockFetch,
request: new Request('http://localhost/persons/p1'),
url: new URL('http://localhost/persons/p1'),
locals: mockLocals
})
).rejects.toMatchObject({
status: 403
});