test(qa): B-UI primitive behavior spec (dialog/select/disabled)
- e2e/b-ui.spec.js: functional checks axe can't assert — Add Bill dialog opens with a focus trap and Esc cancels with no bill created (Cancel = no side effect); the category Select opens by mouse and keyboard and lists options; the sort-direction button stays inert (disabled) in Custom order. Read-only, so safe in the parallel suite. Directly covers the B-UI batch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
18c7025f3a
commit
5fe1f6499b
|
|
@ -0,0 +1,62 @@
|
|||
// 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();
|
||||
});
|
||||
Loading…
Reference in New Issue