117 lines
3.7 KiB
TypeScript
117 lines
3.7 KiB
TypeScript
import { page } from 'vitest/browser';
|
||
import { describe, it, expect, vi } from 'vitest';
|
||
import { render } from 'vitest-browser-svelte';
|
||
|
||
const { submitRef } = vi.hoisted(() => ({
|
||
submitRef: {
|
||
current: null as unknown as (opts: { formData: FormData; cancel?: () => void }) => unknown
|
||
}
|
||
}));
|
||
|
||
vi.mock('$app/forms', () => ({
|
||
enhance: (_node: unknown, submit: unknown) => {
|
||
submitRef.current = submit as typeof submitRef.current;
|
||
return () => {};
|
||
}
|
||
}));
|
||
|
||
import BlockModal from './BlockModal.svelte';
|
||
|
||
const categories = [{ id: 1, name: 'Physical' }];
|
||
const groups = [{ id: 1, name: 'Prayers' }];
|
||
const proclamations = [
|
||
{ id: 'p1', name: 'Peace', categoryId: 1, groupId: 1 },
|
||
{ id: 'p2', name: 'Strength', categoryId: 1, groupId: 1 }
|
||
];
|
||
|
||
function mount(overrides: Record<string, unknown> = {}) {
|
||
return render(BlockModal, {
|
||
open: true,
|
||
mode: 'create',
|
||
categories,
|
||
groups,
|
||
proclamations,
|
||
existingBlocks: [],
|
||
initialStartMinutes: 6 * 60,
|
||
initialEndMinutes: 8 * 60,
|
||
initialProclamationIds: ['p1'],
|
||
onClose: () => {},
|
||
onSaved: () => {},
|
||
...overrides
|
||
});
|
||
}
|
||
|
||
function submit() {
|
||
const form = document.querySelector('form') as HTMLFormElement;
|
||
return submitRef.current({ formData: new FormData(form), cancel: () => {} });
|
||
}
|
||
|
||
describe('BlockModal', () => {
|
||
it('uses separate hour and minute selects for start and end', async () => {
|
||
mount();
|
||
|
||
await expect.element(page.getByRole('combobox', { name: /^Start hour$/ })).toBeInTheDocument();
|
||
await expect
|
||
.element(page.getByRole('combobox', { name: /^Start minute$/ }))
|
||
.toBeInTheDocument();
|
||
await expect.element(page.getByRole('combobox', { name: /^End hour$/ })).toBeInTheDocument();
|
||
await expect.element(page.getByRole('combobox', { name: /^End minute$/ })).toBeInTheDocument();
|
||
});
|
||
|
||
it('pre-fills the selects from the initial times', async () => {
|
||
mount({ initialStartMinutes: 7 * 60 + 30, initialEndMinutes: 9 * 60 + 15 });
|
||
|
||
await expect.element(page.getByRole('combobox', { name: /^Start hour$/ })).toHaveValue('7');
|
||
await expect.element(page.getByRole('combobox', { name: /^Start minute$/ })).toHaveValue('30');
|
||
await expect.element(page.getByRole('combobox', { name: /^End hour$/ })).toHaveValue('9');
|
||
await expect.element(page.getByRole('combobox', { name: /^End minute$/ })).toHaveValue('15');
|
||
});
|
||
|
||
it('shows the review times and selected proclamation titles', async () => {
|
||
mount();
|
||
|
||
await expect.element(page.getByText('6:00 AM – 8:00 AM')).toBeInTheDocument();
|
||
await expect.element(page.getByText('Peace')).toBeInTheDocument();
|
||
});
|
||
|
||
it('marks an overnight block in the review', async () => {
|
||
mount({ initialStartMinutes: 21 * 60, initialEndMinutes: 9 * 60 });
|
||
|
||
await expect.element(page.getByText('9:00 PM – 9:00 AM (next day)')).toBeInTheDocument();
|
||
});
|
||
|
||
it('rejects an overlapping time range with the specific error', async () => {
|
||
mount({
|
||
existingBlocks: [{ id: 'b1', startMinutes: 6 * 60, endMinutes: 8 * 60 }],
|
||
initialStartMinutes: 7 * 60,
|
||
initialEndMinutes: 9 * 60
|
||
});
|
||
|
||
await page.getByRole('combobox', { name: /^Start hour$/ }).element();
|
||
submit();
|
||
|
||
await expect
|
||
.element(page.getByText(/This overlaps with your 6:00 AM–8:00 AM block\./))
|
||
.toBeInTheDocument();
|
||
});
|
||
|
||
it('requires at least one proclamation', async () => {
|
||
mount({ initialProclamationIds: [] });
|
||
|
||
await page.getByRole('combobox', { name: /^Start hour$/ }).element();
|
||
submit();
|
||
|
||
await expect.element(page.getByText('Select at least one proclamation.')).toBeInTheDocument();
|
||
});
|
||
|
||
it('does not show an error for a valid selection', async () => {
|
||
mount();
|
||
|
||
await page.getByRole('combobox', { name: /^Start hour$/ }).element();
|
||
const result = submit();
|
||
|
||
expect(typeof result).toBe('function');
|
||
await expect.element(page.getByRole('alert')).not.toBeInTheDocument();
|
||
});
|
||
});
|