fix(chess): global Esc handler + stable test selectors for layouts e2e
- LayoutEditor: move Esc handling to a window keydown listener so the modal closes regardless of where focus currently sits (the prior onKeyDown on the modal div only fired when the root div itself held focus). - LayoutPicker: add data-testid on the description <p> so e2e assertions can target it unambiguously instead of relying on free-text matches that also select the hidden <option> labels. - e2e: use the new testid. All 12 layouts e2e tests pass; existing multiplayer + full-flow e2e suites still green.
This commit is contained in:
parent
832ebe9cd6
commit
89c22d6bd5
3 changed files with 21 additions and 3 deletions
|
|
@ -52,7 +52,9 @@ test.describe('LayoutPicker (lobby)', () => {
|
|||
test('selecting Dunsany updates the description', async ({ page }) => {
|
||||
const picker = page.getByTestId('layout-picker');
|
||||
await picker.selectOption('dunsany');
|
||||
await expect(page.locator('text=/Dunsany/i').first()).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId('layout-picker-description'),
|
||||
).toContainText(/pawn tide/i);
|
||||
});
|
||||
|
||||
test('?layoutId=dunsany query param pre-selects the layout', async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
* incrementally — simpler and avoids ambiguity about which source
|
||||
* of truth wins).
|
||||
*/
|
||||
import { useMemo, useState, type ReactNode } from 'react';
|
||||
import { useEffect, useMemo, useState, type ReactNode } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import {
|
||||
fromFen,
|
||||
|
|
@ -92,6 +92,19 @@ export function LayoutEditor({
|
|||
const [libraryOpen, setLibraryOpen] = useState(false);
|
||||
const [libraryVersion, setLibraryVersion] = useState(0); // bump to force reload
|
||||
|
||||
// Global Esc listener: close the editor regardless of where focus
|
||||
// currently is. We can't rely on the modal div's onKeyDown because
|
||||
// the user might have focused a textarea / button inside a nested
|
||||
// panel, and keyboard events on those don't bubble to the modal
|
||||
// root in a way that works universally.
|
||||
useEffect(() => {
|
||||
const handler = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') onClose();
|
||||
};
|
||||
window.addEventListener('keydown', handler);
|
||||
return () => window.removeEventListener('keydown', handler);
|
||||
}, [onClose]);
|
||||
|
||||
// Derived FEN whenever placements change — keeps the readonly view
|
||||
// in sync. The user's in-flight fenDraft is a SEPARATE state so
|
||||
// typing doesn't get clobbered by a re-render.
|
||||
|
|
|
|||
|
|
@ -116,7 +116,10 @@ export function LayoutPicker({
|
|||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-neutral-500 leading-relaxed">
|
||||
<p
|
||||
data-testid="layout-picker-description"
|
||||
className="text-xs text-neutral-500 leading-relaxed"
|
||||
>
|
||||
{isCustom ? 'Custom layout loaded from your editor.' : value.description}
|
||||
</p>
|
||||
{value.suggestedPresets !== undefined &&
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue