// B-UI: functional behavior of shared primitives that axe/a11y can't assert — // dialogs cancel without side effects, Selects open by mouse and keyboard, // disabled controls stay inert. All checks are READ-ONLY (Esc/Cancel/reopen), so // they're safe alongside the other UI specs in the parallel suite. const { test, expect } = require('@playwright/test'); const { STORAGE_STATE } = require('./constants'); test.use({ storageState: STORAGE_STATE }); test('dialog: Add Bill opens, Esc closes it, and creates nothing (Cancel = no side effect)', async ({ page }) => { await page.goto('/'); const badges = page.locator('button[title="Click to mark paid"]:visible, button[title="Click to mark unpaid"]:visible'); await expect(badges.first()).toBeVisible(); // wait for bills to load before counting const before = await badges.count(); await page.getByRole('button', { name: 'Add Bill' }).click(); const dialog = page.getByRole('dialog'); await expect(dialog).toBeVisible(); // Focus moved into the dialog (focus trap). await expect(dialog.locator(':focus')).toHaveCount(1); await page.keyboard.press('Escape'); await expect(dialog).toBeHidden(); // No bill was created and the page is still functional. await expect(page.getByRole('button', { name: 'Add Bill' })).toBeVisible(); await expect.poll(() => badges.count()).toBe(before); }); test('select: category filter opens by mouse and by keyboard and lists options', async ({ page, isMobile }) => { test.skip(isMobile, 'filter panel layout differs on mobile'); await page.goto('/'); // Radix Select trigger exposes role="combobox". const trigger = page.getByRole('combobox', { name: 'Filter by category' }); await expect(trigger).toBeVisible(); // Mouse: opens a listbox with the "All categories" option. await trigger.click(); const listbox = page.getByRole('listbox'); await expect(listbox).toBeVisible(); await expect(page.getByRole('option', { name: 'All categories' })).toBeVisible(); await page.keyboard.press('Escape'); await expect(listbox).toBeHidden(); // Keyboard: focus the trigger and open with Enter. await trigger.focus(); await page.keyboard.press('Enter'); await expect(page.getByRole('listbox')).toBeVisible(); await page.keyboard.press('Escape'); }); test('disabled control: sort-direction button is inert in Custom order', async ({ page, isMobile }) => { test.skip(isMobile, 'filter panel layout differs on mobile'); await page.goto('/'); // Default sort is "Custom order", for which the asc/desc toggle is disabled. const dir = page.getByRole('button', { name: 'Asc' }); await expect(dir).toBeVisible(); await expect(dir).toBeDisabled(); // Clicking a disabled control must be a no-op (force past the actionability guard). await dir.click({ force: true }); await expect(dir).toBeDisabled(); });