test(e2e): port eyes.feature to Playwright - #74869
Open
stephenliang wants to merge 1 commit into
Open
Conversation
stephenliang
marked this pull request as ready for review
August 25, 2026 17:44
stephenliang
force-pushed
the
stephen/port-eyes-playwright
branch
2 times, most recently
from
August 25, 2026 18:04
6249019 to
e9fd531
Compare
Port 7 scenarios from dashboard/test/ui/features/eyes.feature. Each scenario becomes a @visual test carrying the Eyes checkpoints, plus an axe scan where the result is the same on every engine. The RTL surfaces get no axe scan. axe's color-contrast and scrollable-region-focusable verdicts differ between engines on identical computed styles, so a shared baseline is not available and a per-engine one would only record the discrepancy. Two examples, both measured: firefox alone sees #workspace-header overflow its box by 4px, and webkit alone reports #runButton at 3.07:1 against the 4.5:1 AA requirement while chromium and firefox pass it. That contrast failure is real (white on #f46800) and wants a separate fix; it is not a test artifact. Also fix the shared instructions-overlay dismissal in LegacyBlocklyLab: it located the OK button by accessible name, which InstructionsCsfMiddleCol.jsx renders from i18n.dialogOK(), so it never matched under /lang/ar-sa and fell through to a coordinate click the instructions panel intercepts. It now anchors on the same block's <hr> instead. Two pieces of this port belong to existing owners rather than to new shared utilities. The level-content dialog is now LevelDialogComponent, composed onto LessonLevelPage beside introVideoModal. The header fade-in is now HeaderComponent.waitForFadeIn, beside the other header waits; the font-relayout wait moves off shared/stability.ts to HeaderComponent.waitForSettled. The two header signals stay separate on purpose: waitForFadeIn is a single locator assertion and sits on the lab-boot path, while waitForSettled polls page.evaluate and is too costly to put there. The feature is tagged @playwright to record that it has been ported. Note this does not yet stop Cucumber from running it: rake test:eyes_ui selects features with `grep -lr '@eyes'` and applies no @playwright exclusion. Verified against test-studio.code.org. The eyes spec alone is clean: a11y 90/90 at 5x across chromium/firefox/webkit, visual 21/21. Across the 14 specs touching the shared page objects, 568/576 at 3x on three browsers; the 8 remaining are webkit-dominated crashes and 90s timeouts under local resource pressure, and an unmodified HEAD scores 565/576 on the same suite and hardware. Source: dashboard/test/ui/features/eyes.feature Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
stephenliang
force-pushed
the
stephen/port-eyes-playwright
branch
from
August 25, 2026 21:02
e9fd531 to
13df9aa
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the 7 scenarios in
dashboard/test/ui/features/eyes.featureto Playwright, and fixes the shared instructions-overlay dismissal they exposed.Port
Each Cucumber scenario becomes a
@visualtest carrying the Eyes checkpoints, plus an axe scan where the result is the same on every engine. New page objects:MatchLevel,TextCompressionLevel. New helpers:tests/shared/dialogs.ts,waitForHeaderFadeIn().Why the RTL surfaces have no axe scan
axe's
color-contrastandscrollable-region-focusableverdicts differ between engines even when the computed styles are identical, so there is no shared baseline to assert and a per-engine one would only be recording the discrepancy. Both differences were measured rather than assumed:scrollable-region-focusable#workspace-headeroverflows its box by 4px (scrollHeight25 vsclientHeight21); chromium and webkit see no overflow at all.color-contrast#runButtonreported at 3.07:1 against the 4.5:1 AA requirement. chromium and firefox report identicalcolor,background-color,font-size(16px) andfont-weight(600), and pass it.The contrast failure is real and is not a test artifact. White
#ffffffon#f46800computes to 3.07:1, below the 4.5:1 WCAG AA requirement for normal-weight text. webkit is correct here and the other two engines are under-reporting. This affects the primary Run button on legacy Blockly labs, not just RTL, so it wants its own fix rather than a baseline entry.Shared POM fix
LegacyBlocklyLab.waitForReady()located the instructions overlay's OK button by accessible name.InstructionsCsfMiddleCol.jsxrenders that name fromi18n.dialogOK(), so it never matched under/lang/ar-saand every dismissal fell through to a coordinate click that the level's own instructions panel intercepts. It now anchors on the<hr>in the sameoverlayVisible-gated block, which is locale-independent.This file has 17 consumers, so the 12 sibling specs that exercise it were re-run — see below.
Where the new code lives
Two pieces of this port belong to existing owners rather than to new shared utilities.
The level-content dialog is a
LevelDialogComponentintests/components/, composed ontoLessonLevelPagebesideintroVideoModal, matching the five dialog components already there. It replaces atests/shared/dialogs.tsmodule of free functions.The header fade-in is
HeaderComponent.waitForFadeIn(), beside the header's other waits, and the font-relayout wait moves offshared/stability.tstoHeaderComponent.waitForSettled().shared/stability.tsis left with only engine-agnostic primitives. The two header signals stay separate deliberately:waitForFadeInis a single locator assertion and sits on the lab-boot path that every lab spec runs, whilewaitForSettledpollspage.evaluateand is too costly to put there.Links
Testing story
Verified against
test-studio.code.org. The eyes spec on its own is clean:--repeat-each=5, chromium + firefox + webkitVISUAL_PROVIDER=playwrightEvery remaining axe baseline is asserted identically on all three engines, so the a11y lane carries no per-browser lookup table and no
browserNamebranching.Because this changes page objects that other specs share, the 14 specs touching them were also run at
--repeat-each=3on three browsers: 568/576. The 8 remaining failures are webkit-dominated 90s timeouts and browser crashes under local resource pressure — the runs left 11GB of core dumps behind on a machine with 4GB free. An unmodifiedHEADscores 565/576 on the same suite and hardware, so this branch is at or slightly above the baseline rather than regressing it. These need a CI run on healthier hardware to be conclusive.Deployment notes
The feature is tagged
@playwrightto record that it has been ported, but that tag does not yet stop Cucumber from running it:rake test:eyes_uiselects features withgrep -lr '@eyes'and applies no@playwrightexclusion. So these scenarios run in both suites and keep consuming Applitools checkpoints until that task learns the tag. Pre-existing and repo-wide —initial_page_views2.featureandinitial_page_views3.featurealready have the same@eyes @playwrightshape. Worth a follow-up ticket; deliberately not changed here.