feat: Add replay view content to Cloud CLI skill

This commit is contained in:
Mike Plummer
2026-09-16 13:47:46 -05:00
parent 005d8ae754
commit cccd516bdc
7 changed files with 171 additions and 6 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
{
"name": "cypress",
"description": "Create, update, and fix Cypress tests. Connect to Cypress Cloud to see test results and use data to manage your test suite.",
"version": "1.3.0",
"version": "1.4.0",
"author": {
"name": "Cypress.io",
"email": "support@cypress.io",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "cypress",
"displayName": "Cypress",
"version": "1.3.0",
"version": "1.4.0",
"description": "Create, update, and fix Cypress tests. Connect to Cypress Cloud to see test results and use data to manage your test suite.",
"author": {
"name": "Cypress.io",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "cypress",
"displayName": "Cypress",
"version": "1.3.0",
"version": "1.4.0",
"description": "Create, update, and fix Cypress tests. Connect to Cypress Cloud to see test results and use data to manage your test suite.",
"author": {
"name": "Cypress.io",
+5 -2
View File
@@ -2,7 +2,7 @@
name: cypress-cloud-cli
description: Runs the cy-cloud CLI to inspect Cypress Cloud organizations, projects, runs, specs, tests, failure screenshots, and Test Replay data. Use when the user mentions Cypress Cloud, cy-cloud, cypress-cloud-cli, a Cloud run or test URL, failing or flaky Cypress tests, Test Replay, run triage, Cloud artifacts, or asks why a recorded test failed.
metadata:
version: 1.0.0
version: 1.1.0
---
# Cypress Cloud CLI
@@ -117,8 +117,11 @@ Read only the references required for the current task:
[investigation.md](references/investigation.md).
- **Query Test Replay:** read [investigation.md](references/investigation.md) and
[test-replay.md](references/test-replay.md).
- **Inspect the app itself (DOM, ARIA, computed styles, a live screenshot) at a moment in the test, or
find which command changed an element:** read [replay-view.md](references/replay-view.md).
- **Diagnose why a recorded test failed:** read [investigation.md](references/investigation.md),
[test-replay.md](references/test-replay.md), and [diagnosis.md](references/diagnosis.md).
[test-replay.md](references/test-replay.md), [replay-view.md](references/replay-view.md) when the
timeline alone does not explain the symptom, and [diagnosis.md](references/diagnosis.md).
## Cache and common recovery
@@ -1,7 +1,9 @@
# Diagnosis
Do not merely restate Cloud fields. Use this evidence order after reading
[investigation.md](investigation.md) and, when replay is available, [test-replay.md](test-replay.md):
[investigation.md](investigation.md) and, when replay is available, [test-replay.md](test-replay.md).
When the timeline narrows the failure to an element but not to the command that changed it, add
[replay-view.md](replay-view.md) to pin before/after a suspect command and diff the element's state.
1. Test details and all attempts.
2. Select the failed attempt and pass its `attemptNumber` via `--attempt` to every replay query.
@@ -27,6 +29,9 @@ For "element never appeared" failures, check in order:
3. An expected request that never started.
4. A console exception.
5. Selector, timing, or rendering behavior visible in the screenshot and command timeline.
6. If none of the above is conclusive, open a [replay view](replay-view.md), pin before/after each
suspect command near the element, and compare `inspect` output to find the command that left it
missing, stale, or misrendered.
Report:
@@ -0,0 +1,154 @@
# Replay View
`replay view` opens Test Replay in a real browser and lets you inspect the application under test at
any moment, instead of only reading command/network/log events. Reach for it when
[test-replay.md](test-replay.md) tells you a symptom happened but not why: an element is missing, has
a stale value, or its layout is wrong, and you need to compare DOM/ARIA/computed-style state before
and after a specific command.
Requires a Chromium-family browser on the machine. The CLI tries to find one automatically; point it
at a specific binary with `CYCLOUD_CHROMIUM_PATH` if it cannot, or a specific CDP debugging port with
`CYCLOUD_CHROMIUM_PORT` if the randomly-selected one conflicts with something else on the machine.
## Session model
Every subcommand targets one open viewer, identified by `--testId` or `--testResultUrl` (never both).
Only one viewer can be open per `testId` at a time; commands aimed at that test share it.
- Omit the test target and the command applies to the most-recently-opened viewer.
- Give a test target with no viewer open for it, and one is opened automatically — an explicit `open`
step is a convenience, not a requirement.
- `--headless` only takes effect when a command actually launches a new viewer; it is ignored when an
existing one is reused. Its default is not a fixed value: a new viewer launches headless when
`CI` is set or an AI agent is detected running the CLI, headed otherwise. Pass `--no-headless`
explicitly to force a headed browser even when running as an agent (useful when the user wants to
watch), or `--headless` to force headless in an interactive shell.
```bash
cy-cloud replay view open --testId <uuid>
cy-cloud replay view list
cy-cloud replay view close --testId <uuid>
```
`open` reports `reused: true` when it handed back an already-running viewer instead of launching one.
`list` returns `.tests[]`, one entry per open viewer, with `testId`, `headless`, `launchedAt`,
`lastCommandAt`, `idleTimeoutMs`, and — once resolved from the local cache — `spec` and `testName`.
Use `list` to recover a `testId` you didn't note down, or to confirm a viewer is still open before
issuing a command that would otherwise open (and pay for) a new one.
Opening a viewer is comparatively slow and each idle viewer holds a browser process. Open a test once
and issue multiple `move`/query commands against it rather than reopening per query, and `close` it as
soon as you are done. An idle viewer closes itself after `CYCLOUD_REPLAY_IDLE_TIMEOUT` seconds
(default 300).
## Navigating a viewer
`move` changes what moment/attempt a viewer is showing; `status` reports where it currently is. Both
return the same shape: `testId`, `attempt`, `time`, `pin` (the pinned `commandId`, or `null`),
`pinnedCommand` (`commandId`/`type`/`name`/`state`/`message`, or `null` when nothing is pinned),
`startTime`/`endTime` for the attempt, `commandEvents`/`networkEvents`/`logs` counts, and `failedAt`
when the attempt failed. `--time` and `--pin` are mutually exclusive, and `move` rejects the call
before opening or touching any session if neither `--time`, `--pin`, nor `--attempt` is given:
```bash
# Jump to the point of failure
cy-cloud replay view move --testId <uuid> --time failure
# Jump to a specific timestamp, or the start/end of the attempt
cy-cloud replay view move --testId <uuid> --time 1753063204120
cy-cloud replay view move --testId <uuid> --time start
# Switch attempt (1-indexed, matching Cloud) without moving time
cy-cloud replay view move --testId <uuid> --attempt 2
# Pin to immediately before/after a specific command
cy-cloud replay view move --testId <uuid> --pin '<commandId>|before'
cy-cloud replay view move --testId <uuid> --pin '<commandId>|after'
```
Get `commandId` values from [`replay timeline`](test-replay.md), not from `replay view` itself. A pin
suffix is a 0-based snapshot index, or `before`/`after`; omit the suffix to use the command's default
snapshot.
## Querying the app at a moment
Move first, then query. `dom`, `aria`, and `inspect` all take a required `--selector` (CSS) and an
optional `--at <index>`, and every response — found, missing, or ambiguous — carries the `attempt`
and `time` the query actually ran against, so you can confirm which moment produced the data. The
response itself is one of three flat shapes (not nested under any wrapper key):
- `{ "exists": false, "attempt": ..., "time": ... }` — no match.
- `{ "ambiguous": true, "selector": "...", "count": <n>, "selectors": [{ "index": 0, "selector":
"..." }, ...], "attempt": ..., "time": ... }` — more than one match. `selectors` covers only the
first 10 matches in document order; re-query with a returned `selector`, or with `--at <index>`
using any index up to `count - 1` (not just one of the first 10) to read a specific match directly.
- `{ "exists": true, ..., "attempt": ..., "time": ... }` — exactly one match (or `--at` picked one),
with the subcommand's own data merged in.
```bash
cy-cloud replay view dom --testId <uuid> --selector '[data-cy="cart-total"]'
cy-cloud replay view aria --testId <uuid> --selector '[data-cy="cart-total"]'
cy-cloud replay view inspect --testId <uuid> --selector '[data-cy="cart-total"]'
# Disambiguate a known multi-match selector without a second round trip
cy-cloud replay view inspect --testId <uuid> --selector '.cart-line-item' --at 2
```
- `dom` returns the element's serialized HTML (including descendants) in `.dom`, and adds
`truncated: true` when it was clipped to a size cap.
- `aria` returns the accessibility tree rooted at the element in `.aria`.
- `inspect` returns `.inspect`: `tag`, `attributes`, `box` (`x`/`y`/`width`/`height`), `styles`
(computed), and `aria` (`role`/`name`/`states`) — the most useful single call for "what changed"
questions.
```bash
cy-cloud replay view screenshot --testId <uuid> --path ./screenshots
```
`screenshot` returns `{ "screenshot": "<path>", "attempt": ..., "time": ... }`. `--path` may be a
directory (file named from the viewer's current timestamp) or an exact file path (must not already
exist); when omitted it saves to the OS temp directory, matching `test get --screenshot`, not the
current working directory. Filesystem `EPERM` means the path is not writable from here.
## Pinpointing which command broke an element
The pattern that makes `replay view` worth the cost over reading a screenshot or timeline: pin
immediately before and after the same suspect command and diff the `inspect` output.
1. Find a suspect command from the failure timeline (`replay timeline --aroundFailure`).
2. Open a viewer for the test.
3. Pin before the suspect command and inspect the element.
4. Pin after the same command and inspect again.
5. Diff `box`/`styles`/`attributes`/`aria` between the two. A change there is the exact effect of that
command, not just correlation with the later assertion failure.
6. Close the viewer.
```bash
cy-cloud replay view open --testId <uuid>
cy-cloud replay view move --testId <uuid> --pin '<commandId>|before'
cy-cloud replay view inspect --testId <uuid> --selector '[data-cy="cart-total"]'
cy-cloud replay view move --testId <uuid> --pin '<commandId>|after'
cy-cloud replay view inspect --testId <uuid> --selector '[data-cy="cart-total"]'
cy-cloud replay view close --testId <uuid>
```
Report the before/after `inspect` diff as evidence in [diagnosis.md](diagnosis.md), not just the
element's final state.
## Relation to caching and rate limits
The first `replay view` for a test triggers the same replay download and cache-count-toward-rate-limit
behavior as `replay info`/`replay timeline` (see [test-replay.md](test-replay.md)). Once cached, asset
requests made by `replay view` for that test are batched and cached, so repeated `move`/query calls
against an already-open viewer are cheap.
## Recovery
- No viewer open and no test target given: `No Test Replay viewers are open. Provide a testId to open
a new one.` — pass `--testId` or `--testResultUrl`.
- `move` with none of `--time`, `--pin`, `--attempt`: rejected before any session is opened; supply at
least one.
- Launch failures point at a missing Chromium install; set `CYCLOUD_CHROMIUM_PATH` to a specific
binary and retry. A CDP port conflict is rare but can be worked around with `CYCLOUD_CHROMIUM_PORT`.
- If a query never returns, or a viewer looks stuck, check `status`, then `close` and reopen rather
than waiting past `CYCLOUD_VIEWER_TIMEOUT_MS` (default 30000).
@@ -96,4 +96,7 @@ that cache directory still exists.
- Empty replay events: rerun with no filters, then `--commands`; use paged `--all` only when the
investigation needs every category because task events can contain large payloads.
When the timeline shows a symptom (missing/stale element, wrong layout) but not which command caused
it, open a live viewer and inspect the app directly: read [replay-view.md](replay-view.md).
To turn replay evidence into a root-cause conclusion, read [diagnosis.md](diagnosis.md).