ConversationThumbnail still imported the `$lib/thumbnails` helper that
a02f6cdc deleted, so every SSR render of /briefwechsel crashed with
"Cannot find module '$lib/thumbnails'". Finish that refactor by reading
`doc.thumbnailUrl` straight off the Document DTO (same shape
DocumentThumbnail already uses), and update the spec fixtures to match.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
113 lines
3.3 KiB
TypeScript
113 lines
3.3 KiB
TypeScript
import { describe, it, expect, afterEach } from 'vitest';
|
|
import { cleanup, render } from 'vitest-browser-svelte';
|
|
|
|
import ConversationThumbnail from './ConversationThumbnail.svelte';
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
});
|
|
|
|
describe('ConversationThumbnail', () => {
|
|
it('renders the thumbnail image with a cache-busting v= query param', () => {
|
|
render(ConversationThumbnail, {
|
|
doc: {
|
|
id: '1111',
|
|
thumbnailUrl: '/api/documents/1111/thumbnail?v=2026-04-10T09%3A00%3A00Z',
|
|
thumbnailAspect: 'PORTRAIT',
|
|
pageCount: 1
|
|
}
|
|
});
|
|
|
|
const img = document.querySelector('img') as HTMLImageElement | null;
|
|
expect(img).not.toBeNull();
|
|
expect(img!.getAttribute('src')).toContain('/api/documents/1111/thumbnail');
|
|
expect(img!.getAttribute('src')).toContain('v=');
|
|
});
|
|
|
|
it('uses portrait dimensions when aspect is PORTRAIT', () => {
|
|
render(ConversationThumbnail, {
|
|
doc: {
|
|
id: 'p1',
|
|
thumbnailUrl: '/api/documents/p1/thumbnail?v=2026-04-10T09%3A00%3A00Z',
|
|
thumbnailAspect: 'PORTRAIT',
|
|
pageCount: 1
|
|
}
|
|
});
|
|
|
|
const tile = document.querySelector('[data-testid="conv-thumb-tile"]') as HTMLElement;
|
|
expect(tile.getAttribute('data-aspect')).toBe('PORTRAIT');
|
|
});
|
|
|
|
it('uses landscape dimensions when aspect is LANDSCAPE', () => {
|
|
render(ConversationThumbnail, {
|
|
doc: {
|
|
id: 'l1',
|
|
thumbnailUrl: '/api/documents/l1/thumbnail?v=2026-04-10T09%3A00%3A00Z',
|
|
thumbnailAspect: 'LANDSCAPE',
|
|
pageCount: 1
|
|
}
|
|
});
|
|
|
|
const tile = document.querySelector('[data-testid="conv-thumb-tile"]') as HTMLElement;
|
|
expect(tile.getAttribute('data-aspect')).toBe('LANDSCAPE');
|
|
});
|
|
|
|
it('falls back to PORTRAIT when thumbnailAspect is missing', () => {
|
|
render(ConversationThumbnail, {
|
|
doc: {
|
|
id: 'n1',
|
|
thumbnailUrl: '/api/documents/n1/thumbnail?v=2026-04-10T09%3A00%3A00Z'
|
|
}
|
|
});
|
|
|
|
const tile = document.querySelector('[data-testid="conv-thumb-tile"]') as HTMLElement;
|
|
expect(tile.getAttribute('data-aspect')).toBe('PORTRAIT');
|
|
});
|
|
|
|
it('renders the page badge when pageCount is greater than 1', () => {
|
|
render(ConversationThumbnail, {
|
|
doc: {
|
|
id: 'm1',
|
|
thumbnailUrl: '/api/documents/m1/thumbnail?v=2026-04-10T09%3A00%3A00Z',
|
|
thumbnailAspect: 'PORTRAIT',
|
|
pageCount: 4
|
|
}
|
|
});
|
|
|
|
const badge = document.querySelector('[data-testid="conv-thumb-page-badge"]') as HTMLElement;
|
|
expect(badge).not.toBeNull();
|
|
expect(badge.textContent).toContain('4');
|
|
// Senior-readable size: text-sm (14px) rather than text-xs (12px) on a
|
|
// small tile avoids marginal legibility on a 320px phone.
|
|
expect(badge.className).toContain('text-sm');
|
|
});
|
|
|
|
it('hides the page badge when pageCount is 1 or missing', () => {
|
|
render(ConversationThumbnail, {
|
|
doc: {
|
|
id: 's1',
|
|
thumbnailUrl: '/api/documents/s1/thumbnail?v=2026-04-10T09%3A00%3A00Z',
|
|
thumbnailAspect: 'PORTRAIT',
|
|
pageCount: 1
|
|
}
|
|
});
|
|
|
|
const badge = document.querySelector('[data-testid="conv-thumb-page-badge"]');
|
|
expect(badge).toBeNull();
|
|
});
|
|
|
|
it('renders a skeleton placeholder when no thumbnailUrl is set yet', () => {
|
|
render(ConversationThumbnail, {
|
|
doc: {
|
|
id: 'blank',
|
|
thumbnailAspect: 'PORTRAIT'
|
|
}
|
|
});
|
|
|
|
expect(document.querySelector('img')).toBeNull();
|
|
const skeleton = document.querySelector('[data-testid="conv-thumb-skeleton"]');
|
|
expect(skeleton).not.toBeNull();
|
|
expect(skeleton!.className).toContain('motion-safe:animate-pulse');
|
|
});
|
|
});
|