Stop the focus border test assuming a second device row

Firefox in CI reports one microphone and no outputs, so the menu has a
single selectable row and hovering the second timed out. The test now
drives the pointer by coordinate over the first row, which holds however
many devices a browser reports.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
fkwp
2026-09-11 13:26:01 +02:00
co-authored by Claude Opus 5
parent b82b0a889c
commit edda068f9f
2 changed files with 24 additions and 10 deletions
@@ -342,6 +342,14 @@ is what holds it there.
remaining manual checks are AC6, which needs Safari, and AC21, which needs a screen
reader.
### 2026-09-11 — e2e tests must not assume how many devices a browser reports
- Twice now a new e2e test has failed in CI for the same reason: how many devices a browser
invents differs between them and from a developer machine. Chromium reports several
microphones and outputs; Firefox in CI reports one microphone and no outputs, so the menu
holds a single selectable row. A test that hovered the second row timed out there.
- Tests in `playwright/audio-menu.spec.ts` now assert only what holds at any device count.
Where a fixed device list is what makes the check meaningful, it belongs in a story.
## PRs
- #4254 — draft, one commit per slice — AC1–AC27 (AC6, AC21, AC24 manual by the reviewer;
+16 -10
View File
@@ -181,8 +181,15 @@ test("the focus border follows the keyboard and not the pointer", async ({
await SpaHelpers.createCall(page, "Focus", "Focus border", true);
await page.getByTestId("videoTile").first().waitFor();
const chevron = page.getByRole("button", { name: "Microphone" });
const rows = page.getByRole("menu").getByRole("menuitemradio");
await page.getByRole("button", { name: "Microphone" }).click();
const menu = page.getByRole("menu");
await expect(menu).toBeVisible();
// However many devices this browser reports, there is at least one row.
const row = menu.getByRole("menuitemradio").first();
const box = await row.boundingBox();
if (box === null) throw new Error("Expected the row to be laid out");
const centre = { x: box.x + box.width / 2, y: box.y + box.height / 2 };
const borderOfFocused = async (): Promise<string> =>
page.evaluate(() => {
const el = document.activeElement;
@@ -190,20 +197,19 @@ test("the focus border follows the keyboard and not the pointer", async ({
});
// Reached with the pointer: the hover background carries it, no border.
await chevron.click();
await page.getByRole("menu").waitFor();
await rows.nth(1).hover();
expect(await borderOfFocused()).toBe("none");
await page.mouse.move(centre.x, centre.y);
await expect.poll(borderOfFocused).toBe("none");
// Reached with the keyboard: a border marks where the keyboard is. The menu
// moves focus to whatever the pointer is over, so the browser cannot tell
// these two apart on its own.
await page.keyboard.press("ArrowDown");
expect(await borderOfFocused()).toBe("solid");
await expect.poll(borderOfFocused).toBe("solid");
// And back, on the next movement of the pointer.
await rows.nth(0).hover();
expect(await borderOfFocused()).toBe("none");
// And gone again on the next movement of the pointer. A point the pointer
// is not already at, so that the move is one.
await page.mouse.move(centre.x + 4, centre.y + 2);
await expect.poll(borderOfFocused).toBe("none");
});
async function firstUncheckedIndex(