Files
familienarchiv/frontend/src/routes/page.svelte.spec.ts
Marcel 9e7861fa03 feat(geschichten): frontend foundation — canBlogWrite, sanitize util, nav, i18n
- Derives canBlogWrite in +layout.server.ts the same way as canAnnotate.
- Adds Geschichten link to AppNav (desktop + mobile, between Stammbaum and Admin).
- Adds error_geschichte_not_found mapping to errors.ts and translation keys
  for the Geschichten index, detail, editor, and confirmation copy in
  de/en/es.
- Adds isomorphic-dompurify-backed safeHtml() helper with allow-list
  matching the backend OWASP policy (p/br/strong/em/h2/h3/ul/ol/li),
  plus Vitest spec.
- Updates legacy spec test data so the new required canBlogWrite layout
  prop type-checks.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 17:43:29 +02:00

82 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { afterEach, describe, expect, it, vi } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import type { components } from '$lib/generated/api';
import Page from './+page.svelte';
type User = components['schemas']['AppUser'];
afterEach(cleanup);
vi.mock('$app/navigation', () => ({ goto: vi.fn(), invalidateAll: vi.fn() }));
const baseData = {
user: {
id: 'u1',
email: 'max@example.com',
firstName: 'Max',
lastName: '',
groups: [],
enabled: true,
createdAt: '2024-01-01T00:00:00Z'
} as User,
canWrite: true,
canAnnotate: false,
canBlogWrite: false,
resumeDoc: null,
pulse: null,
activityFeed: [],
stats: null,
segmentationDocs: [],
transcriptionDocs: [],
readyDocs: [],
weeklyStats: null,
error: null
};
// ─── Dashboard layout ─────────────────────────────────────────────────────────
describe('Home page dashboard layout', () => {
it('does not render a search input', async () => {
render(Page, { data: baseData });
const input = page.getByPlaceholder('Titel, Personen, Tags durchsuchen…');
await expect.element(input).not.toBeInTheDocument();
});
it('renders a greeting for the logged-in user', async () => {
render(Page, { data: baseData });
await expect.element(page.getByRole('heading', { level: 1 })).toBeInTheDocument();
});
it('renders resume strip empty state when resumeDoc is null', async () => {
render(Page, { data: baseData });
const empty = page.getByTestId('resume-strip-empty');
await expect.element(empty).toBeInTheDocument();
});
it('renders resume card when resumeDoc is provided', async () => {
const resume = {
documentId: 'doc-1',
title: 'Geburtsurkunde',
caption: 'Max · 1920',
excerpt: 'Hiermit…',
totalBlocks: 3,
pct: 33,
collaborators: []
};
render(Page, { data: { ...baseData, resumeDoc: resume } });
const strip = page.getByTestId('resume-strip');
await expect.element(strip).toBeInTheDocument();
});
it('shows drop zone when canWrite is true', async () => {
render(Page, { data: { ...baseData, canWrite: true } });
await expect.element(page.getByText(/Dateien auf einmal hochladen/i)).toBeInTheDocument();
});
it('hides drop zone when canWrite is false', async () => {
render(Page, { data: { ...baseData, canWrite: false } });
await expect.element(page.getByText(/Dateien auf einmal hochladen/i)).not.toBeInTheDocument();
});
});