diff --git a/frontend/src/lib/document/viewer/PdfViewer.svelte.test.ts b/frontend/src/lib/document/viewer/PdfViewer.svelte.test.ts index 3918c6db..583e1f91 100644 --- a/frontend/src/lib/document/viewer/PdfViewer.svelte.test.ts +++ b/frontend/src/lib/document/viewer/PdfViewer.svelte.test.ts @@ -142,4 +142,106 @@ describe('PdfViewer — loaded state', () => { }) ).not.toThrow(); }); + + it('shows the outdated-annotation notice when annotations have non-matching fileHash', async () => { + const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue( + new Response( + JSON.stringify([ + { + id: 'a1', + documentId: 'test', + pageNumber: 1, + x: 0.1, + y: 0.1, + width: 0.1, + height: 0.1, + color: '#000', + createdAt: '2026-01-01T00:00:00Z', + fileHash: 'old-hash' + } + ]), + { status: 200, headers: { 'Content-Type': 'application/json' } } + ) + ); + try { + render(PdfViewer, { + url: '/api/documents/test/file', + documentId: 'test', + documentFileHash: 'new-hash' + }); + + await new Promise((r) => setTimeout(r, 100)); + const notice = document.querySelector('[data-testid="annotation-outdated-notice"]'); + expect(notice).not.toBeNull(); + } finally { + fetchSpy.mockRestore(); + } + }); + + it('does not show outdated-annotation notice when all annotations match', async () => { + const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue( + new Response( + JSON.stringify([ + { + id: 'a1', + documentId: 'test', + pageNumber: 1, + x: 0.1, + y: 0.1, + width: 0.1, + height: 0.1, + color: '#000', + createdAt: '2026-01-01T00:00:00Z', + fileHash: 'matching-hash' + } + ]), + { status: 200, headers: { 'Content-Type': 'application/json' } } + ) + ); + try { + render(PdfViewer, { + url: '/api/documents/test/file', + documentId: 'test', + documentFileHash: 'matching-hash' + }); + + await new Promise((r) => setTimeout(r, 100)); + const notice = document.querySelector('[data-testid="annotation-outdated-notice"]'); + expect(notice).toBeNull(); + } finally { + fetchSpy.mockRestore(); + } + }); + + it('handles fetch error when loading annotations gracefully', async () => { + const fetchSpy = vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('network')); + try { + expect(() => + render(PdfViewer, { + url: '/api/documents/test/file', + documentId: 'test' + }) + ).not.toThrow(); + await new Promise((r) => setTimeout(r, 50)); + } finally { + fetchSpy.mockRestore(); + } + }); + + it('handles non-OK fetch response when loading annotations', async () => { + const fetchSpy = vi + .spyOn(globalThis, 'fetch') + .mockResolvedValue(new Response('error', { status: 500 })); + try { + expect(() => + render(PdfViewer, { + url: '/api/documents/test/file', + documentId: 'test' + }) + ).not.toThrow(); + await new Promise((r) => setTimeout(r, 50)); + } finally { + fetchSpy.mockRestore(); + } + }); });