From 4d8a86ad286268453f10e1602d3c7fea2f38de4f Mon Sep 17 00:00:00 2001 From: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com> Date: Tue, 4 Aug 2026 21:40:18 +0100 Subject: [PATCH] Fix the two nightly frontend failures (a11y contrast + Firefox Copy menu test) (#7286) Fixes the two nightly frontend jobs that started failing after #7163 (new design, part one). Two unrelated causes, one small fix each. ## Accessibility scan (`--c-primary-hover`) The full a11y scan flagged a colour-contrast violation on the portal pipelines ToolPicker story. #7163 moved the light canvas from `--p-gray-50` (#f9fafb) to the slightly darker `--p-paper` (#f5f4f1), but the accent text colour stayed put. That token doubles as the label colour for quiet and tertiary buttons, so the pairing slipped from 4.64:1 to 4.41:1 purely from the background change. Darkening the custom-theme mix from 85% to 80% primary puts it back at 4.89:1. It is also the hover fill for primary buttons, where a marginally deeper blue is if anything more correct. Only the nightly caught this because PR runs scan just the stories whose files changed, and #7163 did not touch that story file. ## Cross-browser Playwright (right-click Copy menu) Failed in Firefox only. The feature itself is fine in every browser. The test hit-tested a word using a fixed fraction of the page box, and the page is auto-fit to the viewer, so the rendered text scales with the viewport. The Firefox and WebKit projects run at 1280x720, where the page renders about 375px wide and the first line of text is only a few pixels tall. #7163 shrank the viewer area slightly (the rails now float with a gutter), which shrank the auto-fit page just enough to tip that fraction to landing below the glyphs. Nothing was selected, so no menu appeared. Pinning 1920x1080 for that one test makes the glyphs comfortably larger than the click tolerance everywhere, rather than re-tuning a fraction that was only ever a couple of pixels from failing. A Firefox skip was considered and rejected: the sibling clipboard test is already Chromium-only and its comment states the Copy menu is covered cross-browser by this test, so skipping would leave the menu with no Firefox coverage at all. ## Verification Test pinned run is green across chromium, firefox and webkit. Contrast checked with the theme linter's contrast report. --- .../stubbed/viewer-text-selection.spec.ts | 46 +++++++++++-------- frontend/editor/src/core/theme/colors.css | 3 +- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/frontend/editor/src/core/tests/stubbed/viewer-text-selection.spec.ts b/frontend/editor/src/core/tests/stubbed/viewer-text-selection.spec.ts index d9a08ae9e7..55dad6e2a4 100644 --- a/frontend/editor/src/core/tests/stubbed/viewer-text-selection.spec.ts +++ b/frontend/editor/src/core/tests/stubbed/viewer-text-selection.spec.ts @@ -120,27 +120,35 @@ test("Ctrl+C copies selected text to the clipboard", async ({ expect(clipboardText.trim().length).toBeGreaterThan(0); }); -test("right-click on a word auto-selects it and reveals the Copy menu", async ({ - page, -}) => { - test.setTimeout(60_000); - const firstPage = await loadSampleAndOpenViewer(page); - const box = await firstPage.boundingBox(); - if (!box) throw new Error("no box"); +// Pinned wide: the page is auto-fit, so at the 1280x720 firefox/webkit projects +// the text renders too small to hit-test a word reliably. +test.describe("right-click selection", () => { + test.use({ viewport: { width: 1920, height: 1080 } }); - // Right-click on a word in the top paragraph "Test document for word documents". - await page.mouse.click(box.x + box.width * 0.21, box.y + box.height * 0.105, { - button: "right", + test("right-click on a word auto-selects it and reveals the Copy menu", async ({ + page, + }) => { + test.setTimeout(60_000); + const firstPage = await loadSampleAndOpenViewer(page); + const box = await firstPage.boundingBox(); + if (!box) throw new Error("no box"); + + // Right-click a word in the top paragraph "Test document for word documents". + await page.mouse.click( + box.x + box.width * 0.21, + box.y + box.height * 0.105, + { button: "right" }, + ); + await page.waitForTimeout(400); + + const selectionRects = firstPage.locator( + ".pdf-selection-layer > div:first-child > div", + ); + await expect(selectionRects.first()).toBeAttached({ timeout: 5_000 }); + + const copyButton = page.getByRole("button", { name: "Copy" }).first(); + await expect(copyButton).toBeVisible({ timeout: 5_000 }); }); - await page.waitForTimeout(400); - - const selectionRects = firstPage.locator( - ".pdf-selection-layer > div:first-child > div", - ); - await expect(selectionRects.first()).toBeAttached({ timeout: 5_000 }); - - const copyButton = page.getByRole("button", { name: "Copy" }).first(); - await expect(copyButton).toBeVisible({ timeout: 5_000 }); }); test("right-click on the page does not surface the browser context menu", async ({ diff --git a/frontend/editor/src/core/theme/colors.css b/frontend/editor/src/core/theme/colors.css index c7b0ccb08f..e79bc64c49 100644 --- a/frontend/editor/src/core/theme/colors.css +++ b/frontend/editor/src/core/theme/colors.css @@ -161,7 +161,8 @@ html[data-app-theme="midnight"] { /* ── Base accent — fixed default (blue buttons); [data-accent="default"] blocks at the end keep surfaces neutral. LIGHT base here, DARK base next. ── */ html[data-app-theme="custom"] { --c-primary: var(--p-blue-500); - --c-primary-hover: color-mix(in srgb, var(--c-primary) 85%, var(--p-black)); + /* Also the accent text colour (--_text), so 80% keeps 4.5:1 on the canvas. */ + --c-primary-hover: color-mix(in srgb, var(--c-primary) 80%, var(--p-black)); --c-primary-subtle: color-mix(in srgb, var(--c-primary) 14%, transparent); --c-text-on-primary: var(--p-white); --c-accent-fg: var(--c-primary);