test(viewer): cover PdfViewer outdated-annotation notice + fetch errors
Outdated notice when fileHash mismatches, no notice when matching, fetch error gracefully ignored, non-OK response ignored. 4 new tests covering ~8 branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -142,4 +142,106 @@ describe('PdfViewer — loaded state', () => {
|
|||||||
})
|
})
|
||||||
).not.toThrow();
|
).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();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user