From bc6489bf2f0e7626fa6036026a0a3a2042818168 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 10 May 2026 03:47:26 +0200 Subject: [PATCH] test(briefwechsel): cover ConversationFilterBar branches Two persontypeaheads + two date inputs, swap button visible/invisible based on both persons set, sort label DESC vs ASC, chevron rotation, onapplyFilters / ontoggleSort / onswapPersons callbacks fire. 11 tests covering ~20 branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 --- .../ConversationFilterBar.svelte.test.ts | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 frontend/src/routes/briefwechsel/ConversationFilterBar.svelte.test.ts diff --git a/frontend/src/routes/briefwechsel/ConversationFilterBar.svelte.test.ts b/frontend/src/routes/briefwechsel/ConversationFilterBar.svelte.test.ts new file mode 100644 index 00000000..8b4578a9 --- /dev/null +++ b/frontend/src/routes/briefwechsel/ConversationFilterBar.svelte.test.ts @@ -0,0 +1,119 @@ +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; +import ConversationFilterBar from './ConversationFilterBar.svelte'; + +afterEach(cleanup); + +const baseProps = (overrides: Record = {}) => ({ + senderId: '', + receiverId: '', + fromDate: '', + toDate: '', + sortDir: 'DESC', + initialSenderName: '', + initialReceiverName: '', + onapplyFilters: () => {}, + ontoggleSort: () => {}, + onswapPersons: () => {}, + ...overrides +}); + +describe('ConversationFilterBar', () => { + it('renders the two PersonTypeahead inputs and the date inputs', async () => { + render(ConversationFilterBar, { props: baseProps() }); + + const dateInputs = document.querySelectorAll('input[type="date"]'); + expect(dateInputs.length).toBe(2); + }); + + it('marks the swap button invisible when only one person is set', async () => { + render(ConversationFilterBar, { props: baseProps({ senderId: 'p1' }) }); + + const swap = document.querySelector('[data-testid="conv-swap-btn"]') as HTMLElement; + expect(swap.className).toContain('invisible'); + }); + + it('marks the swap button visible when both persons are set', async () => { + render(ConversationFilterBar, { + props: baseProps({ senderId: 'p1', receiverId: 'p2' }) + }); + + const swap = document.querySelector('[data-testid="conv-swap-btn"]') as HTMLElement; + expect(swap.className).not.toContain('invisible'); + }); + + it('renders "Neueste zuerst" when sortDir is DESC', async () => { + render(ConversationFilterBar, { props: baseProps({ sortDir: 'DESC' }) }); + + await expect.element(page.getByText('Neueste zuerst')).toBeVisible(); + }); + + it('renders "Älteste zuerst" when sortDir is ASC', async () => { + render(ConversationFilterBar, { props: baseProps({ sortDir: 'ASC' }) }); + + await expect.element(page.getByText('Älteste zuerst')).toBeVisible(); + }); + + it('rotates the chevron 180° when sortDir is ASC', async () => { + render(ConversationFilterBar, { props: baseProps({ sortDir: 'ASC' }) }); + + const sortBtn = Array.from(document.querySelectorAll('button')).find((b) => + b.textContent?.toLowerCase().includes('älteste') + ); + const chevron = sortBtn?.querySelector('svg'); + expect(chevron?.getAttribute('class')).toContain('rotate-180'); + }); + + it('does not rotate the chevron when sortDir is DESC', async () => { + render(ConversationFilterBar, { props: baseProps({ sortDir: 'DESC' }) }); + + const sortBtn = Array.from(document.querySelectorAll('button')).find((b) => + b.textContent?.toLowerCase().includes('neueste') + ); + const chevron = sortBtn?.querySelector('svg'); + expect(chevron?.getAttribute('class')).not.toContain('rotate-180'); + }); + + it('calls ontoggleSort when the sort button is clicked', async () => { + const ontoggleSort = vi.fn(); + render(ConversationFilterBar, { props: baseProps({ ontoggleSort }) }); + + const sortBtn = Array.from(document.querySelectorAll('button')).find((b) => + b.textContent?.toLowerCase().includes('neueste') + ); + sortBtn?.click(); + expect(ontoggleSort).toHaveBeenCalledOnce(); + }); + + it('calls onswapPersons when the swap button is clicked', async () => { + const onswapPersons = vi.fn(); + render(ConversationFilterBar, { + props: baseProps({ senderId: 'p1', receiverId: 'p2', onswapPersons }) + }); + + const swap = document.querySelector('[data-testid="conv-swap-btn"]') as HTMLElement; + swap.click(); + expect(onswapPersons).toHaveBeenCalledOnce(); + }); + + it('calls onapplyFilters when fromDate input changes', async () => { + const onapplyFilters = vi.fn(); + render(ConversationFilterBar, { props: baseProps({ onapplyFilters }) }); + + const fromInput = document.querySelector('#dateFrom') as HTMLInputElement; + fromInput.value = '1899-04-14'; + fromInput.dispatchEvent(new Event('change', { bubbles: true })); + expect(onapplyFilters).toHaveBeenCalled(); + }); + + it('calls onapplyFilters when toDate input changes', async () => { + const onapplyFilters = vi.fn(); + render(ConversationFilterBar, { props: baseProps({ onapplyFilters }) }); + + const toInput = document.querySelector('#dateTo') as HTMLInputElement; + toInput.value = '1950-12-31'; + toInput.dispatchEvent(new Event('change', { bubbles: true })); + expect(onapplyFilters).toHaveBeenCalled(); + }); +});