test(confirm): add ConfirmDialog component spec (12 tests)
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:
130
frontend/src/lib/components/ConfirmDialog.svelte.spec.ts
Normal file
130
frontend/src/lib/components/ConfirmDialog.svelte.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user