Files
familienarchiv/frontend/src/lib/shared/discussion/CommentMessage.svelte.test.ts
Marcel a47fe9fbce test(discussion): cover CommentMessage branches
Author + initials, comment body, edited label gated on updatedAt vs
createdAt, edit-mode textarea, delete button gated on isOwn, onDelete
callback wiring.

8 tests covering ~16 of CommentMessage's branches.

Refs #496.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 21:50:28 +02:00

94 lines
2.8 KiB
TypeScript

import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import CommentMessage from './CommentMessage.svelte';
afterEach(cleanup);
const baseMessage = (overrides: Record<string, unknown> = {}) => ({
id: 'm1',
authorId: 'u1',
authorName: 'Anna Schmidt',
content: 'Tolle Geschichte!',
createdAt: '2026-04-15T10:00:00Z',
updatedAt: '2026-04-15T10:00:00Z',
mentionDTOs: [] as unknown[],
...overrides
});
const baseProps = (overrides: Record<string, unknown> = {}) => ({
message: baseMessage(),
isOwn: false,
isEditing: false,
editText: '',
onEdit: () => {},
onDelete: () => {},
onEditTextChange: () => {},
onEditKeydown: () => {},
...overrides
});
describe('CommentMessage', () => {
it('renders the author name and avatar initials', async () => {
render(CommentMessage, { props: baseProps() });
await expect.element(page.getByText('Anna Schmidt')).toBeVisible();
await expect.element(page.getByText('AS')).toBeVisible();
});
it('renders the comment body', async () => {
render(CommentMessage, { props: baseProps() });
await expect.element(page.getByText('Tolle Geschichte!')).toBeVisible();
});
it('shows the edited label when updatedAt > createdAt', async () => {
render(CommentMessage, {
props: baseProps({
message: baseMessage({
createdAt: '2026-04-15T10:00:00Z',
updatedAt: '2026-04-15T11:00:00Z'
})
})
});
await expect.element(page.getByText('(Bearbeitet)')).toBeVisible();
});
it('hides the edited label when updatedAt equals createdAt', async () => {
render(CommentMessage, { props: baseProps() });
await expect.element(page.getByText('(Bearbeitet)')).not.toBeInTheDocument();
});
it('shows the textarea when in edit mode', async () => {
render(CommentMessage, {
props: baseProps({ isOwn: true, isEditing: true, editText: 'Editing content' })
});
const textarea = document.querySelector('textarea') as HTMLTextAreaElement;
expect(textarea.value).toBe('Editing content');
});
it('shows the delete button only when isOwn is true', async () => {
render(CommentMessage, { props: baseProps({ isOwn: true }) });
await expect.element(page.getByRole('button', { name: /löschen anna schmidt/i })).toBeVisible();
});
it('hides the delete button when isOwn is false', async () => {
render(CommentMessage, { props: baseProps() });
await expect.element(page.getByRole('button', { name: /löschen/i })).not.toBeInTheDocument();
});
it('calls onDelete when the delete button is clicked', async () => {
const onDelete = vi.fn();
render(CommentMessage, { props: baseProps({ isOwn: true, onDelete }) });
await page.getByRole('button', { name: /löschen anna schmidt/i }).click();
expect(onDelete).toHaveBeenCalledOnce();
});
});