test(shared): cover BackButton and OverflowPillButton
BackButton: visible vs aria-only label branches, custom class application, history.back() click handler. OverflowPillButton: +N pill render, aria-expanded matrix (closed default → open after click), per-person link rendering with correct href, Escape closes the dropdown. Both are reused widely; their coverage closes the line and function gap left after the DocumentTopBar split inflated the denominator. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
50
frontend/src/lib/shared/primitives/BackButton.svelte.test.ts
Normal file
50
frontend/src/lib/shared/primitives/BackButton.svelte.test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import BackButton from './BackButton.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('BackButton', () => {
|
||||
it('renders the visible label by default (showLabel=true)', async () => {
|
||||
render(BackButton, { props: {} });
|
||||
|
||||
await expect.element(page.getByRole('button', { name: /^zurück$/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('hides the visible label when showLabel is false', async () => {
|
||||
render(BackButton, { props: { showLabel: false } });
|
||||
|
||||
const btn = (await page.getByRole('button').element()) as HTMLButtonElement;
|
||||
// The label is exposed via aria-label only when showLabel=false.
|
||||
expect(btn.getAttribute('aria-label')).toBe('Zurück');
|
||||
expect(btn.textContent?.trim()).toBe('');
|
||||
});
|
||||
|
||||
it('does not set an aria-label when the visible label is shown', async () => {
|
||||
render(BackButton, { props: { showLabel: true } });
|
||||
|
||||
const btn = (await page.getByRole('button').element()) as HTMLButtonElement;
|
||||
expect(btn.getAttribute('aria-label')).toBeNull();
|
||||
});
|
||||
|
||||
it('applies the supplied class string to the button', async () => {
|
||||
render(BackButton, { props: { class: 'custom-class' } });
|
||||
|
||||
const btn = (await page.getByRole('button').element()) as HTMLButtonElement;
|
||||
expect(btn.classList.contains('custom-class')).toBe(true);
|
||||
});
|
||||
|
||||
it('calls history.back() when clicked', async () => {
|
||||
const backSpy = vi.spyOn(globalThis.history, 'back').mockImplementation(() => {});
|
||||
try {
|
||||
render(BackButton, { props: {} });
|
||||
|
||||
await page.getByRole('button').click();
|
||||
|
||||
expect(backSpy).toHaveBeenCalledOnce();
|
||||
} finally {
|
||||
backSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import OverflowPillButton from './OverflowPillButton.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
const persons = [
|
||||
{ id: 'p1', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' },
|
||||
{ id: 'p2', firstName: 'Bert', lastName: 'Meier', displayName: 'Bert Meier' }
|
||||
];
|
||||
|
||||
describe('OverflowPillButton', () => {
|
||||
it('renders the +N pill labelled with the count', async () => {
|
||||
render(OverflowPillButton, { props: { extraCount: 3, persons } });
|
||||
|
||||
await expect.element(page.getByText(/\+3/)).toBeVisible();
|
||||
});
|
||||
|
||||
it('starts with aria-expanded=false', async () => {
|
||||
render(OverflowPillButton, { props: { extraCount: 2, persons } });
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('button', { name: /weitere empfänger/i }))
|
||||
.toHaveAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
it('opens the dropdown when the pill is clicked', async () => {
|
||||
render(OverflowPillButton, { props: { extraCount: 2, persons } });
|
||||
|
||||
await page.getByRole('button', { name: /weitere empfänger/i }).click();
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('button', { name: /weitere empfänger/i }))
|
||||
.toHaveAttribute('aria-expanded', 'true');
|
||||
});
|
||||
|
||||
it('renders one link per person inside the open dropdown', async () => {
|
||||
render(OverflowPillButton, { props: { extraCount: 2, persons } });
|
||||
|
||||
await page.getByRole('button', { name: /weitere empfänger/i }).click();
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('link', { name: 'Anna Schmidt' }))
|
||||
.toHaveAttribute('href', '/persons/p1');
|
||||
await expect
|
||||
.element(page.getByRole('link', { name: 'Bert Meier' }))
|
||||
.toHaveAttribute('href', '/persons/p2');
|
||||
});
|
||||
|
||||
it('closes the dropdown when Escape is pressed', async () => {
|
||||
render(OverflowPillButton, { props: { extraCount: 2, persons } });
|
||||
|
||||
const btn = page.getByRole('button', { name: /weitere empfänger/i });
|
||||
await btn.click();
|
||||
const btnEl = (await btn.element()) as HTMLButtonElement;
|
||||
btnEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
||||
|
||||
await expect.element(btn).toHaveAttribute('aria-expanded', 'false');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user