refactor(pdf-viewer-tests): extract shared fake, add loadDocument error path, fix assertions
Some checks failed
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / OCR Service Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / fail2ban Regex (pull_request) Has been cancelled
CI / Compose Bucket Idempotency (pull_request) Has been cancelled
CI / Unit & Component Tests (push) Failing after 2m3s
CI / OCR Service Tests (push) Successful in 16s
CI / Backend Unit Tests (push) Successful in 4m15s
CI / fail2ban Regex (push) Successful in 38s
CI / Compose Bucket Idempotency (push) Failing after 11s
Some checks failed
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / OCR Service Tests (pull_request) Has been cancelled
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / fail2ban Regex (pull_request) Has been cancelled
CI / Compose Bucket Idempotency (pull_request) Has been cancelled
CI / Unit & Component Tests (push) Failing after 2m3s
CI / OCR Service Tests (push) Successful in 16s
CI / Backend Unit Tests (push) Successful in 4m15s
CI / fail2ban Regex (push) Successful in 38s
CI / Compose Bucket Idempotency (push) Failing after 11s
- Extract makeFakePdfjsLib / makeFakeLibLoader to testHelpers.ts — single source of truth used by both PdfViewer.svelte.test.ts and usePdfRenderer.svelte.test.ts; removes the diverging-fidelity DRY violation flagged by @felixbrandt and @saraholt in the PR review - Add 'loadDocument sets error and loading=false when getDocument().promise rejects' test to usePdfRenderer.svelte.test.ts — closes the error-path gap flagged by @felixbrandt and @saraholt - Replace toBeInTheDocument() with toBeVisible() in the three absorbed spec-file tests — uniform assertion style across the loaded-state describe block, as flagged by @felixbrandt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #550.
This commit is contained in:
@@ -1,40 +1,11 @@
|
|||||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||||
import { cleanup, render } from 'vitest-browser-svelte';
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
import { page } from 'vitest/browser';
|
import { page } from 'vitest/browser';
|
||||||
import type { LibLoader } from '$lib/document/viewer/usePdfRenderer.svelte';
|
|
||||||
import PdfViewer from './PdfViewer.svelte';
|
import PdfViewer from './PdfViewer.svelte';
|
||||||
|
import { makeFakeLibLoader } from './testHelpers';
|
||||||
|
|
||||||
afterEach(cleanup);
|
afterEach(cleanup);
|
||||||
|
|
||||||
function makeFakePdfjsLib() {
|
|
||||||
class TextLayerMock {
|
|
||||||
render() {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
cancel() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
GlobalWorkerOptions: { workerSrc: '' },
|
|
||||||
getDocument: vi.fn().mockReturnValue({
|
|
||||||
promise: Promise.resolve({
|
|
||||||
numPages: 2,
|
|
||||||
getPage: vi.fn().mockResolvedValue({
|
|
||||||
getViewport: vi.fn().mockReturnValue({ width: 595, height: 842 }),
|
|
||||||
render: vi.fn().mockReturnValue({ promise: Promise.resolve() }),
|
|
||||||
streamTextContent: vi.fn().mockReturnValue(new ReadableStream())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
TextLayer: TextLayerMock
|
|
||||||
} as unknown as typeof import('pdfjs-dist');
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeFakeLibLoader(): LibLoader {
|
|
||||||
const fakePdfjs = makeFakePdfjsLib();
|
|
||||||
return vi.fn().mockResolvedValue([fakePdfjs, { default: '' }] as const);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('PdfViewer — empty / error states', () => {
|
describe('PdfViewer — empty / error states', () => {
|
||||||
it('renders the no-file placeholder when url is empty', async () => {
|
it('renders the no-file placeholder when url is empty', async () => {
|
||||||
render(PdfViewer, { url: '', libLoader: makeFakeLibLoader() });
|
render(PdfViewer, { url: '', libLoader: makeFakeLibLoader() });
|
||||||
@@ -293,18 +264,18 @@ describe('PdfViewer — loaded state', () => {
|
|||||||
|
|
||||||
it('shows previous and next page navigation buttons', async () => {
|
it('shows previous and next page navigation buttons', async () => {
|
||||||
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
||||||
await expect.element(page.getByRole('button', { name: /zurück/i })).toBeInTheDocument();
|
await expect.element(page.getByRole('button', { name: /zurück/i })).toBeVisible();
|
||||||
await expect.element(page.getByRole('button', { name: /weiter/i })).toBeInTheDocument();
|
await expect.element(page.getByRole('button', { name: /weiter/i })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows zoom controls', async () => {
|
it('shows zoom controls', async () => {
|
||||||
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
||||||
await expect.element(page.getByRole('button', { name: /vergrößern/i })).toBeInTheDocument();
|
await expect.element(page.getByRole('button', { name: /vergrößern/i })).toBeVisible();
|
||||||
await expect.element(page.getByRole('button', { name: /verkleinern/i })).toBeInTheDocument();
|
await expect.element(page.getByRole('button', { name: /verkleinern/i })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays the page counter once the PDF has loaded', async () => {
|
it('displays the page counter once the PDF has loaded', async () => {
|
||||||
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
||||||
await expect.element(page.getByText(/1\s*\/\s*2/)).toBeInTheDocument();
|
await expect.element(page.getByText(/1\s*\/\s*2/)).toBeVisible();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
31
frontend/src/lib/document/viewer/testHelpers.ts
Normal file
31
frontend/src/lib/document/viewer/testHelpers.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { vi } from 'vitest';
|
||||||
|
import type { LibLoader } from './usePdfRenderer.svelte';
|
||||||
|
|
||||||
|
export function makeFakePdfjsLib() {
|
||||||
|
class TextLayerMock {
|
||||||
|
render() {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
cancel() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
GlobalWorkerOptions: { workerSrc: '' },
|
||||||
|
getDocument: vi.fn().mockReturnValue({
|
||||||
|
promise: Promise.resolve({
|
||||||
|
numPages: 2,
|
||||||
|
getPage: vi.fn().mockResolvedValue({
|
||||||
|
getViewport: vi.fn().mockReturnValue({ width: 595, height: 842 }),
|
||||||
|
render: vi.fn().mockReturnValue({ promise: Promise.resolve() }),
|
||||||
|
streamTextContent: vi.fn().mockReturnValue(new ReadableStream())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
TextLayer: TextLayerMock
|
||||||
|
} as unknown as typeof import('pdfjs-dist');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeFakeLibLoader(): LibLoader {
|
||||||
|
const fakePdfjs = makeFakePdfjsLib();
|
||||||
|
return vi.fn().mockResolvedValue([fakePdfjs, { default: '' }] as const);
|
||||||
|
}
|
||||||
@@ -1,24 +1,6 @@
|
|||||||
import { describe, it, expect, vi } from 'vitest';
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import type { LibLoader } from './usePdfRenderer.svelte';
|
|
||||||
import { createPdfRenderer } from './usePdfRenderer.svelte';
|
import { createPdfRenderer } from './usePdfRenderer.svelte';
|
||||||
|
import { makeFakeLibLoader } from './testHelpers';
|
||||||
function makeFakeLibLoader(): LibLoader {
|
|
||||||
return vi.fn().mockResolvedValue([
|
|
||||||
{
|
|
||||||
GlobalWorkerOptions: { workerSrc: '' },
|
|
||||||
getDocument: vi.fn().mockReturnValue({
|
|
||||||
promise: Promise.resolve({ numPages: 1, getPage: vi.fn() })
|
|
||||||
}),
|
|
||||||
TextLayer: class {
|
|
||||||
render() {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
cancel() {}
|
|
||||||
}
|
|
||||||
} as unknown as typeof import('pdfjs-dist'),
|
|
||||||
{ default: '' }
|
|
||||||
] as const);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: init() and loadDocument() require pdfjsLib (browser module).
|
// Note: init() and loadDocument() require pdfjsLib (browser module).
|
||||||
// These tests cover pure state logic only — bounds clamping and zoom limits.
|
// These tests cover pure state logic only — bounds clamping and zoom limits.
|
||||||
@@ -222,4 +204,24 @@ describe('createPdfRenderer', () => {
|
|||||||
await r.init();
|
await r.init();
|
||||||
expect(fakeLoader).toHaveBeenCalledOnce();
|
expect(fakeLoader).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('loadDocument sets error and loading=false when getDocument().promise rejects', async () => {
|
||||||
|
const failingLib = {
|
||||||
|
GlobalWorkerOptions: { workerSrc: '' },
|
||||||
|
getDocument: vi.fn().mockReturnValue({
|
||||||
|
promise: Promise.reject(new Error('PDF not found'))
|
||||||
|
}),
|
||||||
|
TextLayer: class {
|
||||||
|
render() {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
cancel() {}
|
||||||
|
}
|
||||||
|
} as unknown as typeof import('pdfjs-dist');
|
||||||
|
const r = createPdfRenderer(vi.fn().mockResolvedValue([failingLib, { default: '' }] as const));
|
||||||
|
await r.init();
|
||||||
|
await r.loadDocument('/bad/path');
|
||||||
|
expect(r.loading).toBe(false);
|
||||||
|
expect(r.error).toBe('PDF not found');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user