test(dashboard): cover ReaderHeaderBar and ReaderRecentStories
ReaderHeaderBar: time-of-day greeting matrix (Morgen/Mittag/Abend), welcome with name, stats counts, em-dash for null counts, three section links. ReaderRecentStories: empty early return, populated story rows, all- stories link, story-detail link, body excerpt visibility. 12 tests, ~30 branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import ReaderHeaderBar from './ReaderHeaderBar.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
const baseProps = (overrides: Record<string, unknown> = {}) => ({
|
||||
name: 'Anna',
|
||||
documents: 50,
|
||||
persons: 12,
|
||||
stories: 5,
|
||||
...overrides
|
||||
});
|
||||
|
||||
describe('ReaderHeaderBar', () => {
|
||||
it('renders the welcome greeting with name', async () => {
|
||||
render(ReaderHeaderBar, { props: baseProps() });
|
||||
|
||||
await expect.element(page.getByText(/anna/i)).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders Morgen label for hours before noon', async () => {
|
||||
render(ReaderHeaderBar, { props: baseProps({ hour: 9 }) });
|
||||
|
||||
await expect.element(page.getByText('Morgen')).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders Mittag label for hours 12-17', async () => {
|
||||
render(ReaderHeaderBar, { props: baseProps({ hour: 14 }) });
|
||||
|
||||
await expect.element(page.getByText('Mittag')).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders Abend label for hours 18+', async () => {
|
||||
render(ReaderHeaderBar, { props: baseProps({ hour: 20 }) });
|
||||
|
||||
await expect.element(page.getByText('Abend')).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders the stats counts and links', async () => {
|
||||
render(ReaderHeaderBar, { props: baseProps() });
|
||||
|
||||
// Counts visible somewhere
|
||||
expect(document.body.textContent).toContain('50');
|
||||
expect(document.body.textContent).toContain('12');
|
||||
|
||||
const docsLink = document.querySelector('a[href="/documents"]');
|
||||
const personsLink = document.querySelector('a[href="/persons"]');
|
||||
const storiesLink = document.querySelector('a[href="/geschichten"]');
|
||||
expect(docsLink).not.toBeNull();
|
||||
expect(personsLink).not.toBeNull();
|
||||
expect(storiesLink).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders em-dash when stats are null', async () => {
|
||||
render(ReaderHeaderBar, {
|
||||
props: baseProps({ documents: null, persons: null, stories: null })
|
||||
});
|
||||
|
||||
const dashes = Array.from(document.querySelectorAll('span.text-2xl'));
|
||||
const dashCount = dashes.filter((el) => el.textContent?.trim() === '—').length;
|
||||
expect(dashCount).toBe(3);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import ReaderRecentStories from './ReaderRecentStories.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
const makeStory = (overrides: Record<string, unknown> = {}) => ({
|
||||
id: 'g1',
|
||||
title: 'Reise nach Berlin',
|
||||
body: '<p>Brief text content</p>',
|
||||
publishedAt: '2026-04-15T10:00:00Z',
|
||||
updatedAt: '2026-04-15T10:00:00Z',
|
||||
...overrides
|
||||
});
|
||||
|
||||
describe('ReaderRecentStories', () => {
|
||||
it('renders nothing when stories is empty', async () => {
|
||||
render(ReaderRecentStories, { props: { stories: [] } });
|
||||
|
||||
expect(document.querySelector('h3')).toBeNull();
|
||||
});
|
||||
|
||||
it('renders the heading and one row per story', async () => {
|
||||
render(ReaderRecentStories, {
|
||||
props: {
|
||||
stories: [
|
||||
makeStory({ id: 'g1', title: 'Story 1' }),
|
||||
makeStory({ id: 'g2', title: 'Story 2' })
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /neue geschichten/i })).toBeVisible();
|
||||
await expect.element(page.getByText('Story 1')).toBeVisible();
|
||||
await expect.element(page.getByText('Story 2')).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders the link to /geschichten in the header', async () => {
|
||||
render(ReaderRecentStories, { props: { stories: [makeStory()] } });
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('link', { name: /alle geschichten/i }))
|
||||
.toHaveAttribute('href', '/geschichten');
|
||||
});
|
||||
|
||||
it('renders the story link to /geschichten/{id}', async () => {
|
||||
render(ReaderRecentStories, { props: { stories: [makeStory({ id: 'g-42' })] } });
|
||||
|
||||
const links = document.querySelectorAll('a[href^="/geschichten/"]');
|
||||
const detailLinks = Array.from(links).filter((a) =>
|
||||
(a as HTMLAnchorElement).href.includes('/geschichten/g-42')
|
||||
);
|
||||
expect(detailLinks.length).toBe(1);
|
||||
});
|
||||
|
||||
it('renders the body excerpt when present', async () => {
|
||||
render(ReaderRecentStories, {
|
||||
props: { stories: [makeStory({ body: '<p>Once upon a time in 1923</p>' })] }
|
||||
});
|
||||
|
||||
await expect.element(page.getByText(/Once upon a time in 1923/)).toBeVisible();
|
||||
});
|
||||
|
||||
it('omits the excerpt paragraph when body is empty', async () => {
|
||||
render(ReaderRecentStories, {
|
||||
props: { stories: [makeStory({ body: '' })] }
|
||||
});
|
||||
|
||||
const paragraphs = document.querySelectorAll('p');
|
||||
expect(paragraphs.length).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user