test: inject real ConfirmService via context (batch 1/2)

Replaces the vi.mock('$lib/shared/services/confirm.svelte') stub with a
real createConfirmService() provided through render's context map, mirroring
the existing admin/tags/[id]/page.svelte.spec.ts pattern. The generic
confirm.test-fixture.svelte renders only ConfirmDialog and cannot wrap an
arbitrary page; none of these specs trigger confirm(), so the children's
getConfirmService() simply reads the provided context instead of a module
mock. No vi.mock of confirm.svelte remains in these 5 specs. Part of #560.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-02 20:00:41 +02:00
parent e5cf98e1d4
commit a4d4ff35d9
5 changed files with 156 additions and 42 deletions

View File

@@ -2,9 +2,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
vi.mock('$lib/shared/services/confirm.svelte', () => ({
getConfirmService: () => ({ confirm: async () => false })
}));
import { createConfirmService, CONFIRM_KEY } from '$lib/shared/services/confirm.svelte.js';
const { default: TranscriptionEditView } = await import('./TranscriptionEditView.svelte');
import type { TranscriptionBlockData } from '$lib/shared/types';
@@ -37,7 +35,10 @@ const baseProps = (overrides: Record<string, unknown> = {}) => ({
describe('TranscriptionEditView', () => {
it('renders the empty-state coach when there are no blocks', async () => {
render(TranscriptionEditView, { props: baseProps() });
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps()
});
// TranscribeCoachEmptyState renders some German text
expect(document.body.textContent).toMatch(/markier|block|transkrip/i);
@@ -45,6 +46,7 @@ describe('TranscriptionEditView', () => {
it('renders the review progress counter when there are blocks', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock({ id: 'b1', reviewed: false }), baseBlock({ id: 'b2', reviewed: true })]
})
@@ -55,6 +57,7 @@ describe('TranscriptionEditView', () => {
it('shows the "alle als fertig markieren" button when onMarkAllReviewed is provided', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
onMarkAllReviewed: async () => {}
@@ -66,6 +69,7 @@ describe('TranscriptionEditView', () => {
it('disables the mark-all-reviewed button when all blocks are reviewed', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock({ reviewed: true })],
onMarkAllReviewed: async () => {}
@@ -80,6 +84,7 @@ describe('TranscriptionEditView', () => {
it('enables the mark-all-reviewed button when not all blocks are reviewed', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock({ reviewed: false })],
onMarkAllReviewed: async () => {}
@@ -93,7 +98,10 @@ describe('TranscriptionEditView', () => {
});
it('hides the mark-all-reviewed button when onMarkAllReviewed is not provided', async () => {
render(TranscriptionEditView, { props: baseProps({ blocks: [baseBlock()] }) });
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({ blocks: [baseBlock()] })
});
await expect
.element(page.getByRole('button', { name: /alle als fertig/i }))
@@ -102,6 +110,7 @@ describe('TranscriptionEditView', () => {
it('renders the OcrTrigger only when canRunOcr is true and onTriggerOcr is provided', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
canRunOcr: true,
@@ -116,6 +125,7 @@ describe('TranscriptionEditView', () => {
it('hides the OcrTrigger when canRunOcr is false', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
canRunOcr: false,
@@ -129,6 +139,7 @@ describe('TranscriptionEditView', () => {
it('renders the training-label chips when canWrite=true and there are blocks', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
canWrite: true,
@@ -143,6 +154,7 @@ describe('TranscriptionEditView', () => {
it('hides the training-label section when canWrite is false', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
canWrite: false
@@ -155,6 +167,7 @@ describe('TranscriptionEditView', () => {
it('toggles the training label chip when clicked', async () => {
const onToggleTrainingLabel = vi.fn().mockResolvedValue(undefined);
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
canWrite: true,
@@ -174,6 +187,7 @@ describe('TranscriptionEditView', () => {
it('renders blocks sorted by sortOrder', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [
baseBlock({ id: 'b3', sortOrder: 3, text: 'Third' }),
@@ -193,6 +207,7 @@ describe('TranscriptionEditView', () => {
it('renders both blocks with their text after rerender with a new activeAnnotationId', async () => {
const { rerender } = render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [
baseBlock({ id: 'b1', annotationId: 'ann-1', sortOrder: 1, text: 'First' }),
@@ -223,6 +238,7 @@ describe('TranscriptionEditView', () => {
it('handleMarkAllReviewed calls onMarkAllReviewed when clicked', async () => {
const onMarkAllReviewed = vi.fn().mockResolvedValue(undefined);
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock({ reviewed: false })],
onMarkAllReviewed
@@ -238,6 +254,7 @@ describe('TranscriptionEditView', () => {
it('renders all blocks with their text', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [
baseBlock({ id: 'b1', text: 'Erster Block' }),
@@ -252,6 +269,7 @@ describe('TranscriptionEditView', () => {
it('shows the next-block CTA when there are blocks', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()]
})
@@ -263,6 +281,7 @@ describe('TranscriptionEditView', () => {
it('shows the active training label highlighted when included in trainingLabels', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
canWrite: true,
@@ -281,6 +300,7 @@ describe('TranscriptionEditView', () => {
it('renders the inactive training-label chip class when not in trainingLabels', async () => {
render(TranscriptionEditView, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: baseProps({
blocks: [baseBlock()],
canWrite: true,

View File

@@ -1,10 +1,8 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
vi.mock('$lib/shared/services/confirm.svelte', () => ({
getConfirmService: () => ({ confirm: async () => false })
}));
import { createConfirmService, CONFIRM_KEY } from '$lib/shared/services/confirm.svelte.js';
const { default: AdminGroupEditPage } = await import('./+page.svelte');
@@ -19,13 +17,17 @@ const baseGroup = (overrides: Record<string, unknown> = {}) => ({
describe('admin/groups/[id] page', () => {
it('renders the edit heading with the group name', async () => {
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup() }, form: undefined }
});
await expect.element(page.getByRole('heading', { name: /familie/i })).toBeVisible();
});
it('hydrates the name input from data.group.name', async () => {
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup({ name: 'Admins' }) }, form: undefined }
});
@@ -35,6 +37,7 @@ describe('admin/groups/[id] page', () => {
it('checks the permission checkboxes that are in data.group.permissions', async () => {
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: { group: baseGroup({ permissions: ['READ_ALL', 'ADMIN_TAG'] }) },
form: undefined
@@ -57,6 +60,7 @@ describe('admin/groups/[id] page', () => {
it('shows the success banner when form.success is true', async () => {
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup() }, form: { success: true } }
});
@@ -65,6 +69,7 @@ describe('admin/groups/[id] page', () => {
it('shows the error banner when form.error is set', async () => {
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: { group: baseGroup() },
form: { error: 'Name darf nicht leer sein.' }
@@ -75,21 +80,30 @@ describe('admin/groups/[id] page', () => {
});
it('renders the cancel link to /admin/groups', async () => {
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup() }, form: undefined }
});
const links = document.querySelectorAll('a[href="/admin/groups"]');
expect(links.length).toBeGreaterThan(0);
});
it('renders the delete and save buttons', async () => {
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup() }, form: undefined }
});
await expect.element(page.getByRole('button', { name: /löschen/i })).toBeVisible();
await expect.element(page.getByRole('button', { name: /speichern/i })).toBeVisible();
});
it('does not render success banner when form is undefined', async () => {
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup() }, form: undefined }
});
const banner = document.querySelector('.bg-green-50');
expect(banner).toBeNull();
@@ -97,6 +111,7 @@ describe('admin/groups/[id] page', () => {
it('does not render error-banner div when form.success is true (success path only)', async () => {
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup() }, form: { success: true } }
});
@@ -106,7 +121,10 @@ describe('admin/groups/[id] page', () => {
});
it('renders all 8 permission checkboxes (4 standard + 4 admin)', async () => {
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup() }, form: undefined }
});
const checkboxes = document.querySelectorAll('input[name="permissions"]');
expect(checkboxes.length).toBe(8);
@@ -114,6 +132,7 @@ describe('admin/groups/[id] page', () => {
it('handles a group with empty permissions array', async () => {
render(AdminGroupEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: { group: baseGroup({ permissions: [] }) }, form: undefined }
});

View File

@@ -1,10 +1,8 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
vi.mock('$lib/shared/services/confirm.svelte', () => ({
getConfirmService: () => ({ confirm: async () => false })
}));
import { createConfirmService, CONFIRM_KEY } from '$lib/shared/services/confirm.svelte.js';
const { default: AdminUserEditPage } = await import('./+page.svelte');
@@ -32,13 +30,19 @@ const baseData = (overrides: Record<string, unknown> = {}) => ({
describe('admin/users/[id] page', () => {
it('renders the edit heading with the user email', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
await expect.element(page.getByRole('heading', { name: /anna@example/i })).toBeVisible();
});
it('renders all three card sections', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
await expect.element(page.getByRole('heading', { name: /persönliche daten/i })).toBeVisible();
await expect.element(page.getByRole('heading', { name: /^gruppen$/i })).toBeVisible();
@@ -46,13 +50,17 @@ describe('admin/users/[id] page', () => {
});
it('shows the update success banner when form.success is true', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: { success: true } } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: { success: true } }
});
await expect.element(page.getByText('Änderungen gespeichert.')).toBeVisible();
});
it('shows the update error banner when form.error is set', async () => {
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: { error: 'E-Mail bereits vergeben' } }
});
@@ -60,7 +68,10 @@ describe('admin/users/[id] page', () => {
});
it('preselects the user groups in UserGroupsSection', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
const checkboxes = Array.from(
document.querySelectorAll('input[name="groupIds"]')
@@ -70,27 +81,39 @@ describe('admin/users/[id] page', () => {
});
it('renders cancel link to /admin/users', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
const cancel = document.querySelector('a[href="/admin/users"]');
expect(cancel).not.toBeNull();
});
it('renders the delete button', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
await expect.element(page.getByRole('button', { name: /löschen/i })).toBeVisible();
});
it('does not show success banner when form is undefined', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
const banner = document.querySelector('.bg-green-50');
expect(banner).toBeNull();
});
it('does not show error banner when form.error is undefined', async () => {
render(AdminUserEditPage, { props: { data: baseData(), form: { success: false } } });
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: { success: false } }
});
// The error banner has both border-red-200 AND text-red-700 — the delete button has red-50
// background but is a button, not a div. Look for the specific error <div>.
@@ -100,6 +123,7 @@ describe('admin/users/[id] page', () => {
it('handles a user with empty groups list (selectedGroupIds defaults to [])', async () => {
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({ editUser: { ...baseEditUser, groups: [] } }),
form: undefined
@@ -117,6 +141,7 @@ describe('admin/users/[id] page', () => {
const editUser = { ...baseEditUser } as typeof baseEditUser & { groups?: undefined };
delete (editUser as { groups?: unknown }).groups;
render(AdminUserEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ editUser }), form: undefined }
});

View File

@@ -1,9 +1,7 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
vi.mock('$lib/shared/services/confirm.svelte', () => ({
getConfirmService: () => ({ confirm: async () => false })
}));
import { createConfirmService, CONFIRM_KEY } from '$lib/shared/services/confirm.svelte.js';
const { default: DocumentEditPage } = await import('./+page.svelte');
@@ -31,7 +29,10 @@ const baseData = (overrides: Record<string, unknown> = {}) => ({
describe('documents/[id]/edit page', () => {
it('renders the page with the DocumentEditLayout', async () => {
render(DocumentEditPage, { props: { data: baseData(), form: undefined } });
render(DocumentEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
// At minimum, the body has content
const main = document.body.firstElementChild;
@@ -39,7 +40,10 @@ describe('documents/[id]/edit page', () => {
});
it('renders both hidden submit-target forms', async () => {
render(DocumentEditPage, { props: { data: baseData(), form: undefined } });
render(DocumentEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
const reviewForm = document.querySelector('form#mark-for-review-form');
const deleteForm = document.querySelector('form#delete-form');
@@ -48,7 +52,10 @@ describe('documents/[id]/edit page', () => {
});
it('renders the action bar with delete, cancel, mark-for-review, and save buttons/links', async () => {
render(DocumentEditPage, { props: { data: baseData(), form: undefined } });
render(DocumentEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
// Find delete button
const deleteBtn = Array.from(document.querySelectorAll('button')).find((b) =>
@@ -58,13 +65,17 @@ describe('documents/[id]/edit page', () => {
});
it('uses doc.title in the document title when set', async () => {
render(DocumentEditPage, { props: { data: baseData(), form: undefined } });
render(DocumentEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
await vi.waitFor(() => expect(document.title).toContain('Brief an Helene'));
});
it('falls back to originalFilename when title is empty', async () => {
render(DocumentEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({ document: { ...baseDoc, title: '', originalFilename: 'fallback.pdf' } }),
form: undefined
@@ -75,7 +86,10 @@ describe('documents/[id]/edit page', () => {
});
it('renders the cancel link to the document detail page', async () => {
render(DocumentEditPage, { props: { data: baseData(), form: undefined } });
render(DocumentEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: undefined }
});
const link = document.querySelector('a[href="/documents/d1"]');
expect(link).not.toBeNull();
@@ -83,6 +97,7 @@ describe('documents/[id]/edit page', () => {
it('passes form.error to DocumentEditLayout when form is set', async () => {
render(DocumentEditPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData(), form: { error: 'Save failed' } }
});

View File

@@ -27,9 +27,7 @@ vi.mock('$app/navigation', () => ({
onNavigate: () => () => {}
}));
vi.mock('$lib/shared/services/confirm.svelte', () => ({
getConfirmService: () => ({ confirm: async () => false })
}));
import { createConfirmService, CONFIRM_KEY } from '$lib/shared/services/confirm.svelte.js';
const { default: DocumentDetailPage } = await import('./+page.svelte');
@@ -63,7 +61,10 @@ const baseData = (overrides: Record<string, unknown> = {}) => ({
describe('documents/[id] page', () => {
it('renders the DocumentTopBar and resolves the document title in svelte:head', async () => {
mockPage.url = new URL('http://localhost/documents/d1');
render(DocumentDetailPage, { props: { data: baseData() } });
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData() }
});
expect(document.querySelector('[data-topbar]')).not.toBeNull();
await vi.waitFor(() => expect(document.title).toContain('Brief an Helene'));
@@ -71,7 +72,10 @@ describe('documents/[id] page', () => {
it('mounts the page region with the [data-hydrated] container', async () => {
mockPage.url = new URL('http://localhost/documents/d1');
render(DocumentDetailPage, { props: { data: baseData() } });
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData() }
});
expect(document.querySelector('[data-hydrated]')).not.toBeNull();
});
@@ -79,7 +83,10 @@ describe('documents/[id] page', () => {
it('persists last-visited document ID to localStorage on mount', async () => {
localStorage.removeItem('familienarchiv.lastVisited');
mockPage.url = new URL('http://localhost/documents/d1');
render(DocumentDetailPage, { props: { data: baseData() } });
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData() }
});
await vi.waitFor(() => {
const stored = localStorage.getItem('familienarchiv.lastVisited');
@@ -89,7 +96,10 @@ describe('documents/[id] page', () => {
it('uses doc.title as the document title when set', async () => {
mockPage.url = new URL('http://localhost/documents/d1');
render(DocumentDetailPage, { props: { data: baseData() } });
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData() }
});
await vi.waitFor(() => expect(document.title).toContain('Brief an Helene'));
});
@@ -97,6 +107,7 @@ describe('documents/[id] page', () => {
it('falls back to originalFilename when title is empty', async () => {
mockPage.url = new URL('http://localhost/documents/d2');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: { ...baseDoc, id: 'd2', title: '', originalFilename: 'fallback.pdf' }
@@ -110,6 +121,7 @@ describe('documents/[id] page', () => {
it('falls back to "Dokument" when title and originalFilename are empty', async () => {
mockPage.url = new URL('http://localhost/documents/d3');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: { ...baseDoc, id: 'd3', title: '', originalFilename: '' }
@@ -122,7 +134,10 @@ describe('documents/[id] page', () => {
it('renders the topbar Edit-link affordance when canWrite is true', async () => {
mockPage.url = new URL('http://localhost/documents/d4');
render(DocumentDetailPage, { props: { data: baseData({ canWrite: true }) } });
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ canWrite: true }) }
});
await expect.element(browserPage.getByRole('link', { name: 'Bearbeiten' })).toBeVisible();
});
@@ -130,6 +145,7 @@ describe('documents/[id] page', () => {
it('renders the topbar when geschichten and inferredRelationship are passed through', async () => {
mockPage.url = new URL('http://localhost/documents/d5');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
geschichten: [{ id: 'g1', title: 'Story', publishedAt: null }],
@@ -146,6 +162,7 @@ describe('documents/[id] page', () => {
it('renders the topbar even when doc.id is empty (defensive)', async () => {
mockPage.url = new URL('http://localhost/documents/d-empty');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: '', title: 'No ID' } }) }
});
@@ -156,6 +173,7 @@ describe('documents/[id] page', () => {
it('renders sender data in the metadata drawer when sender is populated', async () => {
mockPage.url = new URL('http://localhost/documents/d7');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: {
@@ -176,6 +194,7 @@ describe('documents/[id] page', () => {
it('renders the topbar when filePath is set on the document', async () => {
mockPage.url = new URL('http://localhost/documents/d8');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: {
@@ -195,6 +214,7 @@ describe('documents/[id] page', () => {
it('renders the topbar with a complete user object passed through', async () => {
mockPage.url = new URL('http://localhost/documents/d9');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: { ...baseDoc, id: 'd9' },
@@ -209,6 +229,7 @@ describe('documents/[id] page', () => {
it('Escape keydown leaves the transcribe panel hidden when not already in transcribe mode', async () => {
mockPage.url = new URL('http://localhost/documents/d10');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: 'd10' } }) }
});
@@ -220,6 +241,7 @@ describe('documents/[id] page', () => {
it('non-Escape keydown does not affect the transcribe panel state', async () => {
mockPage.url = new URL('http://localhost/documents/d11');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: 'd11' } }) }
});
@@ -232,6 +254,7 @@ describe('documents/[id] page', () => {
it('renders the topbar with a deep-link comment query param', async () => {
mockPage.url = new URL('http://localhost/documents/d12?comment=c-abc');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: 'd12' } }) }
});
@@ -241,6 +264,7 @@ describe('documents/[id] page', () => {
it('renders sender name and Edit affordance with all metadata populated', async () => {
mockPage.url = new URL('http://localhost/documents/d-meta');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: {
@@ -278,6 +302,7 @@ describe('documents/[id] page', () => {
it('enters transcribe mode and shows the panel close button when ?task=transcribe is set', async () => {
mockPage.url = new URL('http://localhost/documents/d-task?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: { ...baseDoc, id: 'd-task' },
@@ -296,6 +321,7 @@ describe('documents/[id] page', () => {
try {
mockPage.url = new URL('http://localhost/documents/d-fail?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({ document: { ...baseDoc, id: 'd-fail' } })
}
@@ -328,6 +354,7 @@ describe('documents/[id] page', () => {
try {
mockPage.url = new URL('http://localhost/documents/d-blocks?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: 'd-blocks' } }) }
});
await expect.element(browserPage.getByText('Erster')).toBeVisible();
@@ -343,6 +370,7 @@ describe('documents/[id] page', () => {
);
mockPage.url = new URL('http://localhost/documents/d-new');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({ document: { ...baseDoc, id: 'd-new', title: 'New Doc' } })
}
@@ -360,6 +388,7 @@ describe('documents/[id] page', () => {
try {
mockPage.url = new URL('http://localhost/documents/d-ocr-fail?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ canWrite: true, document: { ...baseDoc, id: 'd-ocr-fail' } }) }
});
await vi.waitFor(() => {
@@ -391,6 +420,7 @@ describe('documents/[id] page', () => {
try {
mockPage.url = new URL('http://localhost/documents/d-ocr-run?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ canWrite: true, document: { ...baseDoc, id: 'd-ocr-run' } }) }
});
await expect.element(browserPage.getByText('OCR läuft')).toBeVisible();
@@ -402,6 +432,7 @@ describe('documents/[id] page', () => {
it('renders the topbar when the document has all OCR-relevant fields populated', async () => {
mockPage.url = new URL('http://localhost/documents/d-ocr-meta?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: {
@@ -424,6 +455,7 @@ describe('documents/[id] page', () => {
it('treats undefined geschichten as the empty array (geschichten ?? [] branch)', async () => {
mockPage.url = new URL('http://localhost/documents/d-no-stories');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: {
data: baseData({
document: { ...baseDoc, id: 'd-no-stories' },
@@ -449,6 +481,7 @@ describe('documents/[id] page', () => {
try {
mockPage.url = new URL('http://localhost/documents/d-ocr-done?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: 'd-ocr-done' } }) }
});
await vi.waitFor(() => {
@@ -474,6 +507,7 @@ describe('documents/[id] page', () => {
try {
mockPage.url = new URL('http://localhost/documents/d-ocr-no-job?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: 'd-ocr-no-job' } }) }
});
await vi.waitFor(() => {
@@ -496,6 +530,7 @@ describe('documents/[id] page', () => {
try {
mockPage.url = new URL('http://localhost/documents/d-ocr-throw?task=transcribe');
render(DocumentDetailPage, {
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
props: { data: baseData({ document: { ...baseDoc, id: 'd-ocr-throw' } }) }
});
await vi.waitFor(() => {