feat: add the snapshot and dom tap commands for reading AUT DOM#34255
Open
davidr-cy wants to merge 8 commits into
Open
feat: add the snapshot and dom tap commands for reading AUT DOM#34255davidr-cy wants to merge 8 commits into
davidr-cy wants to merge 8 commits into
Conversation
cypress
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Project |
cypress
|
| Branch Review |
davidr/feat/tap-cli/tap-snapshots
|
| Run status |
|
| Run duration | 25m 36s |
| Commit |
|
| Committer | David Rowe |
| View all properties for this run ↗︎ | |
| Test results | |
|---|---|
|
|
7
|
|
|
3
|
|
|
988
|
|
|
19
|
|
|
15351
|
| View all changes introduced in this branch ↗︎ | |
Warning
Partial Report: The results for the Application Quality reports may be incomplete.
UI Coverage
64%
|
|
|---|---|
|
|
27
|
|
|
48
|
Accessibility
99.02%
|
|
|---|---|
|
|
0 critical
3 serious
1 moderate
0 minor
|
|
|
18
|
Tests for review

src/tap/commands/run-state.cy.ts • 5 failed tests • app-ct

src/tap/commands/commands.cy.ts • 1 failed test • app-ct
| Test | Artifacts | |
|---|---|---|
| tap/commands/commands > fails dispatch without reading the runner when the required test option is missing |
Test Replay
|
|

cypress/e2e/e2e/origin/commands/actions.cy.ts • 0 failed tests • 5x-driver-electron
| Test | Artifacts | |
|---|---|---|

cypress/e2e/commands/actions/clear.cy.ts • 0 failed tests • 5x-driver-electron
| Test | Artifacts | |
|---|---|---|
The first 5 failed specs are shown, see all 800 specs in Cypress Cloud.

runner/ct-framework-errors.cy.ts • 1 flaky test • app-e2e
| Test | Artifacts | |
|---|---|---|
| Angular 18 > error conditions |
Test Replay
Screenshots
|
|

create-from-component.cy.ts • 1 flaky test • app-e2e
| Test | Artifacts | |
|---|---|---|
| ... > Shows create from component card for Vue projects |
Test Replay
Screenshots
|
|

commands/net_stubbing.cy.ts • 1 flaky test • 5x-driver-electron
| Test | Artifacts | |
|---|---|---|
| ... > can timeout when retrieving upstream response |
Test Replay
|
|
78fb9cb to
8ed2606
Compare
ab6bd03 to
a4e16ac
Compare
a4e16ac to
ddcd8ac
Compare
8ed2606 to
92dbaba
Compare
ddcd8ac to
a209a74
Compare
92dbaba to
19f7898
Compare
a209a74 to
c196607
Compare
19f7898 to
07941de
Compare
c196607 to
934ad77
Compare
07941de to
7647a01
Compare
7647a01 to
9bc0eb3
Compare
934ad77 to
52c822d
Compare
9bc0eb3 to
1177708
Compare
52c822d to
7d67ba1
Compare
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7d67ba1. Configure here.
Two schema-driven subcommands let an agent inspect the app under test: - `snapshot <test> <command>` reads the DOM snapshot the driver captured for a command-log entry — the same snapshots the reporter shows on hover. It returns the page HTML (or, with --selector, just the matching elements), the element(s) the command acted on (the [data-cypress-el] subject), the before/after snapshot listing, and optionally the page stylesheets. Reads the live runner via getSnapshotPropsForLog rather than getTestsState, whose serialization blacklists snapshots. - `dom [selector]` reads the AUT's current live document for interactive inspection. Both cap returned HTML at a character budget (default 30000) and flag truncation, so an unscoped read of a heavy page can't flood the caller. Test and command ids are positional params on snapshot: commander 6 stores options as properties, so an option named `command` clashes with its built-in `command` property.
…mands Reads the app-under-test DOM directly over CDP instead of serializing it in the runner page: - Removes the app-side `snapshot` and `dom` tap commands (and their helpers/specs). Historical DOM will come from pinning a command (next), and live DOM now comes from CDP. - Extends `withTapSession` to expose the attached CDP client + session so extractors can run Page/DOM/CSS/Accessibility against the AUT frame. - Adds `resolveAutFrame`: the AUT is a same-process child frame of the runner page (name `Your project: '<name>'`) — verified empirically to be a child frame, not an OOPIF, so one attached session reaches it. - Adds the CLI-native `tap frame` command group and `frame dom`, which reads the current AUT DOM (whole page or a selector's matches) via an isolated world, capping output browser-side. `frame ax`, `frame inspect`, and the binding `pin` command follow. The frozen getSchema/exec contract is unchanged; `frame` is CLI-native.
`cypress tap frame ax [selector]` returns the app-under-test's accessibility tree — roles, names, values, and key states — from Accessibility.getFullAXTree scoped to the AUT frame, projected to a compact indented tree (noise roles collapsed, ignored nodes dropped) with a --max-nodes cap. A selector roots the read at a subtree by matching the element's backend node id; a non-matching selector is an empty result, a malformed one is INVALID_SELECTOR.
`cypress tap pin <test> <command> [--at]` renders a command's captured DOM snapshot into the live app-under-test frame (via the reporter's restore path), so the CDP `tap frame` commands can read that historical moment — its HTML, accessibility tree, computed styles — deterministically instead of whatever the live frame happens to show. `pin --clear` restores the pre-pin DOM; it is idempotent. The pin is app state that persists between tap calls (each CLI call is a fresh CDP connection, so no handle crosses them). Guards: NO_RUN, RUN_IN_PROGRESS, ALREADY_PINNED (one pin at a time), TEST_NOT_FOUND, COMMAND_NOT_FOUND, SNAPSHOT_UNAVAILABLE, SNAPSHOT_NOT_FOUND. The snapshot store's pinned flag is set so the reporter's hover machinery can't clobber the pinned DOM.
- `cypress tap frame inspect <selector>` returns one element's tag, attributes, curated computed styles, box rect, and accessibility node. It reads the element's info in an isolated world (getComputedStyle / getBoundingClientRect on the element) and takes only the AX node from CDP — avoiding the brittle requestNode/nodeId path. - `run-state` (and therefore `status`) now reports the currently pinned command, so a pin is always visible and a stranded one is recoverable.
Align with Playwright's naming for the accessibility tree (its ariaSnapshot / toMatchAriaSnapshot API and the "aria snapshot" its agent tooling returns). `tap frame ax` becomes `tap frame aria`; the extractor, its result types, and the per-element accessibility field on `frame inspect` follow suit. CDP protocol identifiers (AXNode, getFullAXTree) keep their names.
A pin leaked across spec switches and re-runs: the module-level pin state survived, so `status` kept reporting a pin that no longer existed and a `pin --clear` could restore a stale snapshot over the new run's DOM. Reconcile the pin against the current run before every pin/status/clear: the pin is live only while the exact snapshot object it rendered is still the command's current snapshot. A re-run re-captures fresh objects (even when the log id is reused) and a spec switch drops the command entirely — both fail the identity check, so the stale pin is released without restoring its now-gone DOM.
Route the pin through the app's native pin so the AUT shows the pinned banner/controls and the reporter command log reflects it — the pinned command highlights and its test opens (mirrors the existing unpin notification). Re-pinning the same command with a new --at now moves the pin to that snapshot in place instead of erroring ALREADY_PINNED; a different command still requires a clear first.
7d67ba1 to
d808bce
Compare
1177708 to
f3c2f7c
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.

cypress tapCLI (internal dev tooling); no separate public issue.Additional details
Adds two schema-driven
cypress tapsubcommands that let an agent read the app-under-test's DOM straight from the command log, so failures can be diagnosed from the terminal:tap snapshot <test> <command>— reads the DOM snapshot the driver captured for a command-log entry (the same snapshots the reporter shows on hover). Returns the page HTML, or with--selectorjust the matching elements; the element(s) the command acted on (the[data-cypress-el]subject); thebefore/aftersnapshot listing; and, with--styles, the page stylesheets.--atselects which snapshot;--max-charscaps the payload (default 30000, flagstruncated).tap dom [selector]— reads the AUT's current live document, for inspecting an interactive session.Implementation notes:
getSnapshotPropsForLog— the reporter's own hover seam — notgetTestsState, whose serialization blacklistssnapshots. The handler adopts the detached clone, readsouterHTML, and never mutates it, so it can't disturb the visible AUT.test/commandare positional params, not options: commander 6 stores options as properties, so an option namedcommandclashes with its built-incommandproperty.TapCommandError; a zero-count selector match is a result, not an error.knip.jsongets per-filetypesignores matching the existing tap convention.Steps to test
Manual end-to-end (open mode, Chrome-family or Electron browser):
node scripts/cypress.js open --project <project> --e2e --browser electroncypress tap run <spec>, then pollcypress tap statusuntil it finishes.cypress tap tests→ pick a failing test id;cypress tap commands --test <id>→ pick a command id.cypress tap snapshot <test> <command> --selector '<css>'to inspect the DOM at that command;cypress tap dom '<css>'to inspect the live page.Validated end-to-end against a real instance (Cypress 15.19.0): element-not-found, wrong-text assertion, and visibility-regression scenarios each diagnosed from the CLI, plus the full typed-error model.
How has the user experience changed?
No change to end-user-facing Cypress behavior — this is internal
cypress tapdeveloper tooling. Two new subcommands appear incypress taphelp when talking to a running instance.PR Tasks
cypress-documentation?type definitions?Note
Medium Risk
Programmatic pin mutates the live AUT DOM and coordinates reporter/snapshot store state; CDP frame reads are scoped to internal tap tooling with caps and typed errors, but incorrect pin restore could confuse an open interactive session.
Overview
Adds CLI-native
cypress tap framewithdom,aria, andinspectsubcommands that read the app-under-test over Chrome DevTools Protocol (isolated world + accessibility APIs), because the in-page tap binding cannot reach those domains. The CLI locates the AUT iframe by itsYour project:frame name, andwithTapSessionnow exposesclient/sessionIdfor these extractors.Introduces a schema
tap pincommand that renders a command-log DOM snapshot into the live AUT (via the app’s native pin path), captures pre-pin DOM for restore, supports--at/--clear, stale-pin reconciliation, and syncs the reporter when pinning from the CLI.tap status/ hiddenrun-statenow include an optionalpinnedfield.Reporter and event-manager wiring adds
reporter:snapshot:pinned/snapshotPinnedso programmatic pins match user-driven pin UI state.Reviewed by Cursor Bugbot for commit d808bce. Bugbot is set up for automated code reviews on this repo. Configure here.