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
committed by marcel
parent abe860bec7
commit b1b8505b93
5 changed files with 156 additions and 42 deletions

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(() => {