feat(planner): ask before a stray click throws away an edited place or booking (#2253)

This commit is contained in:
Maurice
2026-10-01 13:11:09 +02:00
parent 477f41693d
commit a98449d573
32 changed files with 199 additions and 7 deletions
@@ -1,5 +1,6 @@
// FE-COMP-DIALOGSHELL-001 to FE-COMP-DIALOGSHELL-013
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { useState } from 'react';
import { render, screen, fireEvent } from '../../../tests/helpers/render';
import userEvent from '@testing-library/user-event';
import { resetBodyScrollLock } from '../../utils/bodyScrollLock';
@@ -59,6 +60,58 @@ describe('DialogShell', () => {
});
});
describe('DialogShell unsaved-changes question (#2253)', () => {
function Editor() {
const [name, setName] = useState('');
return (
<DialogShell onClose={onClose} labelledBy="e-title" discardGuard={{ name }}
header={<DialogHeader tile={null} tint={NEUTRAL_TINT} labelId="e-title" onClose={onClose} title="Place" />}>
<input aria-label="Name" value={name} onChange={e => setName(e.target.value)} />
</DialogShell>
);
}
const backdrop = () => document.querySelector('.trek-modal-backdrop') as HTMLElement;
const clickBackdrop = () => { fireEvent.mouseDown(backdrop()); fireEvent.click(backdrop()); };
it('FE-COMP-DIALOGSHELL-2253-1: an untouched editor closes on the backdrop straight away', () => {
render(<Editor />);
clickBackdrop();
expect(onClose).toHaveBeenCalledTimes(1);
});
it('FE-COMP-DIALOGSHELL-2253-2: after typing, the backdrop asks; keep editing stays, discard closes', async () => {
const user = userEvent.setup();
render(<Editor />);
await user.type(screen.getByLabelText('Name'), 'Cafe');
clickBackdrop();
expect(onClose).not.toHaveBeenCalled();
expect(screen.getByRole('alertdialog')).toHaveTextContent('Discard your changes?');
await user.click(screen.getByRole('button', { name: 'Keep editing' }));
expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument();
expect(screen.getByLabelText('Name')).toHaveValue('Cafe');
await user.keyboard('{Escape}');
expect(screen.getByRole('alertdialog')).toBeInTheDocument();
// Escape on the question only takes the question away.
await user.keyboard('{Escape}');
expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument();
expect(onClose).not.toHaveBeenCalled();
clickBackdrop();
await user.click(screen.getByRole('button', { name: 'Discard' }));
expect(onClose).toHaveBeenCalledTimes(1);
});
it('FE-COMP-DIALOGSHELL-2253-3: typing back to where it started closes without asking', async () => {
const user = userEvent.setup();
render(<Editor />);
await user.type(screen.getByLabelText('Name'), 'a');
await user.clear(screen.getByLabelText('Name'));
clickBackdrop();
expect(onClose).toHaveBeenCalledTimes(1);
});
});
describe('DialogHeader', () => {
it('FE-COMP-DIALOGSHELL-004: a plain title is the heading the dialog is named by', () => {
render(<DialogHeader tile={<DialogTile><span data-testid="tile-icon" /></DialogTile>} tint={NEUTRAL_TINT} labelId="t1" onClose={onClose} title="Export" />);