test(confirm): add ConfirmDialog component spec (12 tests)
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 3s
CI / Backend Unit Tests (pull_request) Failing after 1s
CI / Unit & Component Tests (push) Failing after 3s
CI / Backend Unit Tests (push) Failing after 1s

Covers: title/body rendering, destructive vs primary button class,
custom labels, settle true/cancel, aria-labelledby, and hide-after-settle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #228.
This commit is contained in:
Marcel
2026-04-12 14:38:58 +02:00
parent a2d078b8f9
commit d046c89631

View File

@@ -0,0 +1,130 @@
import { describe, it, expect, afterEach, vi } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import ConfirmDialog from './ConfirmDialog.svelte';
import { createConfirmService, CONFIRM_KEY } from '$lib/services/confirm.svelte.js';
afterEach(cleanup);
function renderDialog() {
const service = createConfirmService();
const result = render(ConfirmDialog, {
context: new Map([[CONFIRM_KEY, service]])
});
return { ...result, service };
}
describe('ConfirmDialog', () => {
it('renders the title when options are set', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Delete this item?' });
await expect.element(page.getByText('Delete this item?')).toBeInTheDocument();
service.settle(false);
});
it('renders the body when provided', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Delete?', body: 'This cannot be undone.' });
await expect.element(page.getByText('This cannot be undone.')).toBeInTheDocument();
service.settle(false);
});
it('does not render body element when body is omitted', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Delete?' });
await expect.element(page.getByText('Delete?')).toBeInTheDocument();
const body = document.querySelector('p');
expect(body).toBeNull();
service.settle(false);
});
it('applies bg-danger class on confirm button when destructive', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Delete?', destructive: true });
await expect.element(page.getByText('Delete?')).toBeInTheDocument();
const confirmBtn = document.querySelector('button[class*="bg-danger"]');
expect(confirmBtn).not.toBeNull();
service.settle(false);
});
it('applies bg-primary class on confirm button when not destructive', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Confirm action?' });
await expect.element(page.getByText('Confirm action?')).toBeInTheDocument();
const confirmBtn = document.querySelector('button[class*="bg-primary"]');
expect(confirmBtn).not.toBeNull();
service.settle(false);
});
it('renders custom confirmLabel when provided', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Remove?', confirmLabel: 'Yes, remove it' });
await expect.element(page.getByRole('button', { name: 'Yes, remove it' })).toBeInTheDocument();
service.settle(false);
});
it('renders custom cancelLabel when provided', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Remove?', cancelLabel: 'No, keep it' });
await expect.element(page.getByRole('button', { name: 'No, keep it' })).toBeInTheDocument();
service.settle(false);
});
it('settles true when confirm button is clicked', async () => {
const { service } = renderDialog();
const resultPromise = service.confirm({ title: 'Do it?' });
await expect.element(page.getByText('Do it?')).toBeInTheDocument();
const confirmBtn = document.querySelectorAll<HTMLButtonElement>('button[type="button"]')[1];
confirmBtn.click();
expect(await resultPromise).toBe(true);
});
it('settles false when cancel button is clicked', async () => {
const { service } = renderDialog();
const resultPromise = service.confirm({ title: 'Do it?' });
await expect.element(page.getByText('Do it?')).toBeInTheDocument();
const cancelBtn = document.querySelectorAll<HTMLButtonElement>('button[type="button"]')[0];
cancelBtn.click();
expect(await resultPromise).toBe(false);
});
it('hides content when no options are set', () => {
renderDialog();
const heading = document.querySelector('#confirm-title');
expect(heading).toBeNull();
});
it('has aria-labelledby pointing to the title element', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Accessible title' });
await expect.element(page.getByText('Accessible title')).toBeInTheDocument();
const dialog = document.querySelector('dialog');
expect(dialog?.getAttribute('aria-labelledby')).toBe('confirm-title');
const title = document.getElementById('confirm-title');
expect(title).not.toBeNull();
service.settle(false);
});
it('does not show content after settling', async () => {
const { service } = renderDialog();
service.confirm({ title: 'Gone soon?' });
await expect.element(page.getByText('Gone soon?')).toBeInTheDocument();
service.settle(false);
await vi.waitFor(() => {
expect(document.querySelector('#confirm-title')).toBeNull();
});
});
});