test(dashboard): cover DashboardResumeStrip branches

Empty card vs populated strip, title rendering, thumbnail image vs
fallback icon, progress bar aria-valuenow, document detail link,
collaborators stack rendering, safeColor fallback to default when hex
invalid.

9 tests covering ~25 of DashboardResumeStrip's branches.

Refs #496.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-10 02:41:05 +02:00
parent fd2ff8de7e
commit aa3e46e2f9

View File

@@ -0,0 +1,105 @@
import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import DashboardResumeStrip from './DashboardResumeStrip.svelte';
afterEach(cleanup);
const makeResume = (overrides: Record<string, unknown> = {}) => ({
documentId: 'd1',
title: 'Brief 1923',
caption: 'Sender → Receiver',
excerpt: 'First paragraph',
totalBlocks: 12,
pct: 50,
thumbnailUrl: '/api/d1/thumb',
collaborators: [{ initials: 'AS', color: '#012851', name: null }],
...overrides
});
describe('DashboardResumeStrip', () => {
it('renders the empty card when resumeDoc is null', async () => {
render(DashboardResumeStrip, { props: { resumeDoc: null } });
const empty = document.querySelector('[data-testid="resume-strip-empty"]');
expect(empty).not.toBeNull();
await expect
.element(page.getByRole('heading', { name: /noch kein dokument begonnen/i }))
.toBeVisible();
});
it('renders the resume strip when resumeDoc is provided', async () => {
render(DashboardResumeStrip, { props: { resumeDoc: makeResume() } });
expect(document.querySelector('[data-testid="resume-strip"]')).not.toBeNull();
});
it('renders the document title', async () => {
render(DashboardResumeStrip, { props: { resumeDoc: makeResume() } });
await expect.element(page.getByRole('heading', { name: /brief 1923/i })).toBeVisible();
});
it('renders the thumbnail image when thumbnailUrl is set', async () => {
render(DashboardResumeStrip, { props: { resumeDoc: makeResume() } });
expect(document.querySelector('[data-testid="resume-thumbnail-img"]')).not.toBeNull();
});
it('renders the placeholder icon when thumbnailUrl is missing', async () => {
render(DashboardResumeStrip, {
props: { resumeDoc: makeResume({ thumbnailUrl: null }) }
});
expect(document.querySelector('[data-testid="resume-thumbnail-fallback"]')).not.toBeNull();
});
it('renders the progress bar with correct aria-valuenow', async () => {
render(DashboardResumeStrip, { props: { resumeDoc: makeResume({ pct: 75 }) } });
const progress = document.querySelector('[role="progressbar"]') as HTMLElement;
expect(progress.getAttribute('aria-valuenow')).toBe('75');
});
it('renders the resume CTA link to the document detail', async () => {
render(DashboardResumeStrip, {
props: { resumeDoc: makeResume({ documentId: 'doc-42' }) }
});
const link = document.querySelector('a[href="/documents/doc-42"]') as HTMLAnchorElement;
expect(link).not.toBeNull();
});
it('renders the collaborators stack', async () => {
render(DashboardResumeStrip, {
props: {
resumeDoc: makeResume({
collaborators: [
{ initials: 'XR', color: '#012851', name: null },
{ initials: 'YQ', color: '#5A3080', name: null }
]
})
}
});
await expect.element(page.getByText('XR')).toBeVisible();
await expect.element(page.getByText('YQ')).toBeVisible();
});
it('falls back to the default color when collaborator color is invalid', async () => {
render(DashboardResumeStrip, {
props: {
resumeDoc: makeResume({
collaborators: [{ initials: 'ZQ', color: 'not-a-hex', name: null }]
})
}
});
// safeColor falls back to #8c9aa3 — browser may serialize as rgb(140, 154, 163)
const span = Array.from(document.querySelectorAll('span')).find(
(s) => s.textContent?.trim() === 'ZQ'
) as HTMLElement;
const style = span.getAttribute('style') ?? '';
expect(style.toLowerCase()).toMatch(/(8c9aa3|140,\s*154,\s*163)/);
});
});