From 1cc992832129b0823b0eb8d5cb188f9156d0d618 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 10 May 2026 02:08:15 +0200 Subject: [PATCH] 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 --- .../discussion/CommentMessage.svelte.test.ts | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 frontend/src/lib/shared/discussion/CommentMessage.svelte.test.ts diff --git a/frontend/src/lib/shared/discussion/CommentMessage.svelte.test.ts b/frontend/src/lib/shared/discussion/CommentMessage.svelte.test.ts new file mode 100644 index 00000000..e5c00c67 --- /dev/null +++ b/frontend/src/lib/shared/discussion/CommentMessage.svelte.test.ts @@ -0,0 +1,93 @@ +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 = {}) => ({ + 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 = {}) => ({ + 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(); + }); +});