Skip to content

test(replay): split session-replay-vars.test.ts by actual subject (#1460) - #1468

Merged
thymikee merged 2 commits into
mainfrom
claude/peaceful-hawking-hxxm87
Jul 28, 2026
Merged

test(replay): split session-replay-vars.test.ts by actual subject (#1460)#1468
thymikee merged 2 commits into
mainfrom
claude/peaceful-hawking-hxxm87

Conversation

@thymikee

Copy link
Copy Markdown
Member

Closes #1460.

session-replay-vars.test.ts contained zero references to buildReplayBuiltinVars (the module it was named after — that module's real test is session-replay-builtin-vars.test.ts, untouched by this PR). It actually held tests of src/replay/vars.ts, src/replay/script.ts, and runReplayScriptFile (src/daemon/handlers/session-replay-runtime.ts). This PR redistributes each of the file's 66 test blocks to where its subject actually lives, and deletes the original file. No production code was changed.

Discrepancy vs. the issue's estimate

The issue guessed "~15 tests...are pure duplication" against script.test.ts. That guess was checked per-test and found incorrect: script.test.ts had zero coverage of the env directive feature or of parseReplayScriptDetailed's actionLines, so all 6 script.ts-subject tests moved as genuinely new coverage, none deleted.

Across the whole file, only 1 test total was deleted, as a genuine duplicate of existing session-replay-runtime.test.ts coverage.

Disposition tally

  • 16 test blocks (19 individual test cases, one is a 4-case test.each) → moved to new src/replay/__tests__/vars.test.ts
  • 6 test blocks → moved to src/replay/__tests__/script.test.ts
  • 43 test blocks → moved to new src/daemon/handlers/__tests__/session-replay-runtime-maestro.test.ts
  • 1 test block → deleted as a duplicate
  • 16 + 6 + 43 + 1 = 66, matching the original file's test count exactly. No test was silently dropped.

Why a new sibling file instead of merging into session-replay-runtime.test.ts

The 43 runReplayScriptFile tests all depend on a runReplayFixture helper that requires vi.mock('../../../core/dispatch.ts', ...) mocking resolveTargetDevice (realistic android/ios device objects) and dispatchCommand (rejecting, to keep post-failure screen-digest-capture paths deterministic). session-replay-runtime.test.ts already has its own, differently-shaped vi.mock of the same module (dispatchCommand resolves {}, resolveTargetDevice is a bare vi.fn()). Vitest allows only one vi.mock per module per file, so merging would require reconciling two incompatible mock configurations — out of scope for a pure test-file split per the issue's "keep the move minimal and mechanical" instruction. The new sibling file carries the runReplayFixture helper and its vi.mock over verbatim.

That sibling file also carries a handful of generic (non-Maestro) .ad runReplayScriptFile tests alongside the Maestro-heavy majority, since they share the same fixture helper; this is called out in a comment at the top of the file.

Per-test itemized disposition

Moved to src/replay/__tests__/vars.test.ts (16 blocks / 19 cases)

  1. resolveReplayString substitutes variables
  2. resolveReplayString supports fallback with :-default
  3. resolveReplayString prefers scope value over fallback
  4. resolveReplayString fallback preserves embedded braces via escapes
  5. resolveReplayString throws on unresolved variable with file:line
  6. resolveReplayString is case-sensitive
  7. resolveReplayString substitutes multiple vars on one line
  8. buildReplayVarScope precedence: cli > shell > file > builtin
  9. collectReplayShellEnv strips AD_VAR_ prefix and ignores other vars
  10. collectReplayShellEnv skips keys that land in reserved AD_* namespace after strip
  11. parseReplayCliEnvEntries splits KEY=VALUE and rejects invalid keys
  12. resolveReplayAction walks positionals and string flags
  13. resolveReplayAction walks runtime hints
  14. resolveReplayAction produces dispatch-ready literals for a realistic fixture
  15. test.each block rejects AD_* as reserved namespace in $name (4 cases: file env via readReplayScriptMetadata, CLI via parseReplayCliEnvEntries, buildReplayVarScope.fileEnv, buildReplayVarScope.cliEnv) — kept together as one cross-cutting invariant rather than split across files
  16. parseReplayCliEnvEntries error wording is user-friendly for invalid keys

Moved to src/replay/__tests__/script.test.ts (6 blocks — verified NOT duplicates; script.test.ts had no prior env/actionLines coverage)

  1. parseReplayScriptDetailed tracks line numbers (the actionLines array)
  2. readReplayScriptMetadata parses env KEY=VALUE directives
  3. readReplayScriptMetadata accepts env before context
  4. readReplayScriptMetadata parses quoted env values with spaces
  5. readReplayScriptMetadata rejects invalid env key
  6. readReplayScriptMetadata rejects duplicate env key

Deleted as duplicate (1 block)

  • --update no longer rejects scripts with env directives (the guard existed only for rewrite safety) — deleted as duplicate of session-replay-runtime.test.ts's --update no longer refuses env directives (the guard existed only for rewrite safety) (same guard-removal regression, same ADR 0012 migration-step-6 context). The one extra assertion in the deleted test (that variable substitution completed, calls[0].positionals === ['settings']) is not distinct coverage — substitution itself is thoroughly covered by the vars.ts unit tests moved to vars.test.ts.

Moved to new src/daemon/handlers/__tests__/session-replay-runtime-maestro.test.ts (43 blocks — all new coverage, zero duplicates of the existing 17-test/18-call-site session-replay-runtime.test.ts)

  1. --update no longer rejects Maestro compat flow controls (the guard existed only for rewrite safety)
  2. runReplayScriptFile dispatches resolved literals with file env overridden by CLI
  3. .ad replay normalizes resolved gesture and swipe syntax into structured daemon input
  4. runReplayScriptFile reports snapshot diagnostics from per-action session samples
  5. runReplayScriptFile reports snapshot diagnostics on replay failure
  6. runReplayScriptFile applies CLI env overrides before Maestro compat mapping
  7. runReplayScriptFile runs Maestro runScript in replay order and exposes output variables
  8. runReplayScriptFile supports successful Maestro runScript http.post calls
  9. runReplayScriptFile strips prototype pollution keys from runScript json()
  10. runReplayScriptFile reports Maestro runScript failures at the runScript step
  11. runReplayScriptFile reports iOS Maestro openLink setup failures before assertions
  12. runReplayScriptFile explains empty Maestro runScript JSON bodies
  13. runReplayScriptFile rejects Maestro runScript output keys containing dots
  14. runReplayScriptFile retries Maestro scrollUntilVisible with scroll probes
  15. runReplayScriptFile uses semantic iOS dispatch for an exact text tapOn
  16. runReplayScriptFile uses matched Android id geometry for tapOn
  17. runReplayScriptFile captures fresh geometry for tapOn after assertVisible
  18. runReplayScriptFile scopes duplicate tap targets after native Maestro assertVisible
  19. runReplayScriptFile treats absent Maestro assertNotVisible targets as passing
  20. runReplayScriptFile propagates Maestro assertNotVisible infrastructure failures
  21. runReplayScriptFile waits briefly for Maestro assertNotVisible to stabilize
  22. runReplayScriptFile treats absent Maestro extendedWaitUntil.notVisible targets as passing
  23. runReplayScriptFile resolves Maestro percentage point taps from the direct viewport
  24. runReplayScriptFile retries Maestro id tapOn through snapshot coordinates
  25. runReplayScriptFile resolves Maestro tapOn index and childOf from snapshots
  26. runReplayScriptFile lets snapshot id tap handle Maestro one-point edge controls
  27. runReplayScriptFile resolves a text-entry target once before typing
  28. runReplayScriptFile resolves Maestro swipe.label from a labeled element rect
  29. runReplayScriptFile keeps Maestro swipe.label anchored to the matched label rect
  30. runReplayScriptFile resolves Maestro screen swipes from the direct viewport
  31. runReplayScriptFile delegates Android directional swipes and preserves percentage points
  32. runReplayScriptFile maps Maestro enter to keyboard enter
  33. runReplayScriptFile waits for Maestro animation screenshots to stabilize
  34. runReplayScriptFile propagates unsupported keyboard enter dispatch
  35. runReplayScriptFile retries Maestro retry commands until they pass
  36. runReplayScriptFile propagates Maestro runFlow.when runtime errors
  37. runReplayScriptFile runs Maestro runFlow.when.visible commands when present
  38. runReplayScriptFile runs nested Maestro runtime commands inside runFlow.when
  39. runReplayScriptFile resolves nested Maestro runFlow.when command variables once at execution
  40. runReplayScriptFile reads shell env from request (client-collected), not daemon process.env
  41. runReplayScriptFile falls back to process.env when request omits replayShellEnv
  42. runReplayScriptFile writes per-action timing events to active trace
  43. AD_ARTIFACTS resolves to per-attempt dir when artifactsDir flag is set by the test runner

Verification

  • pnpm test:unit — 524 test files, 4659 tests passed, 4 skipped, no failures.
  • pnpm check:tooling — lint, typecheck, layering, depgraph, production-exports, mcp-metadata, build, bundle-owner-files all pass.
  • session-replay-builtin-vars.test.ts (the correctly-named buildReplayBuiltinVars test) is untouched.

Per the issue: this is a mechanical move only. A later PR (#1451) will restructure this area further.


Generated by Claude Code

)

session-replay-vars.test.ts contained zero references to
buildReplayBuiltinVars (the module it was named after) — it actually held
tests of replay/vars.ts, replay/script.ts, and runReplayScriptFile. Redistribute
each test to where its subject actually lives:

- vars.ts unit tests move to new src/replay/__tests__/vars.test.ts
- script.ts env-directive/actionLines tests move into script.test.ts (none
  were duplicates of existing coverage there)
- runReplayScriptFile tests merge into a new sibling,
  session-replay-runtime-maestro.test.ts, since they depend on a
  vi.mock('../../../core/dispatch.ts') configuration incompatible with the
  one already in session-replay-runtime.test.ts
- one genuine duplicate (`--update` env-directive regression test) is
  deleted in favor of the equivalent already in session-replay-runtime.test.ts

No production code changed.
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 1.87 MB 1.87 MB -213 B
JS gzip 598.9 kB 598.8 kB -128 B
npm tarball 714.6 kB 714.5 kB -129 B
npm unpacked 2.50 MB 2.50 MB -213 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 21.3 ms 21.0 ms -0.3 ms
CLI --help 47.0 ms 43.4 ms -3.6 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/reporting.js -381 B -156 B
dist/src/session.js +328 B +79 B
dist/src/cli-help.js -160 B -51 B

The Fallow Code Quality gate flagged the "dispatches resolved literals
with file env overridden by CLI" test in the new
session-replay-runtime-maestro.test.ts for exceeding the cyclomatic
complexity threshold, since fallow audits it as newly-added code in
this file. Extract the unresolved-interpolation check into a helper
and destructure the captured calls to cut branching, with identical
assertions.
@thymikee

Copy link
Copy Markdown
Member Author

Reviewed clean at 5bd2b96b76f563c3d539050282d124887ffeb59c.

The split keeps each replay test with its actual subject: vars and script coverage is co-located, and the runtime/Maestro sibling preserves the necessary isolated dispatch mock. The 66-block disposition is accounted for (one genuine duplicate removed); all required checks are green. Ready for human review.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Jul 28, 2026
@thymikee
thymikee merged commit 666d5ae into main Jul 28, 2026
28 checks passed
@thymikee
thymikee deleted the claude/peaceful-hawking-hxxm87 branch July 28, 2026 15:38
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-28 15:39 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(replay): session-replay-vars.test.ts (2,299 lines) tests everything except its namesake — split by actual subject

2 participants