Skip to content

Visual HTML report

The visual report is a single offline HTML file that lets you replay a Tales run action by action, screenshot by screenshot. It is designed for mobile runs today; the data model is shaped so a future web/browser provider can slot in without changes.

Terminal window
tales test ./e2e/ios/pass \
--seed 1234 \
--report-html build/reports/visual.html \
--capture-screenshots actions

Open build/reports/visual.html in any modern browser. The file is fully offline, no CDN, no network requests, no npm.

FlagDescription
--report-html <path>Write the visual HTML report to <path>. The parent directory is created if missing.
--capture-screenshots <mode>Pick the screenshot capture mode. One of none, failures, steps, actions.
Flags passedEffective mode
neitherfailures (legacy)
--report-html onlyactions
explicit --capture-screenshotsalways wins

Invalid values exit with code 2 and a message listing the four supported modes.

The HTML follows a macOS-Setup aesthetic:

  • dark gradient backdrop, centered light card with soft shadow
  • screenshot pane on the left
  • vertical action timeline on the right, grouped by step: each step contributes a header (name + status pill + duration) followed by its actions in execution order; the active action is centered and highlighted, previous actions above, future actions below
  • playback controls below: previous / play-pause / next, speed selector (0.5×, 0.75×, 1×, 1.5×, 2×), progress bar
  • header has a scenario selector plus an overall status pill

Keyboard shortcuts:

KeyAction
SpacePlay / pause
Next action
Previous action
HomeFirst action
EndLast action

Playback timing is derived from each action’s measured duration, clamped to [500ms, 3000ms] and divided by the current speed factor. Long real waits (wait_visible with a 10s timeout) therefore show their real duration in the action label but are scrubbed quickly during playback.

When a capture mode writes artifacts, they are nested under the existing mobile artifacts tree so screenshots stay grouped with the failure artifacts they belong to:

build/artifacts/mobile/
<scenario>-<hash>/
<step>/
<phase>/
attempt-<n>/
actions/
0000-tap-welcome.register/
screenshot.png
hierarchy.json
0001-input_text-register.email/
screenshot.png
hierarchy.json
step/
screenshot.png # CaptureSteps mode only
hierarchy.json
screenshot.png # legacy step-level failure
hierarchy.json

No screenshot or hierarchy is ever written. Step-level failure artifacts that previously appeared on failure are also suppressed. The only artifact still surfaced is the driver_log produced when the embedded driver fails to start, because it is the only way to debug a non-starting driver.

Matches the pre-visual-report behavior: one screenshot and one hierarchy written at the step level on failure. Per-action results are still recorded in the data model (with no screenshot paths) so JSONL action events and the HTML timeline can still list what was queued.

One screenshot and one hierarchy captured at the end of each step. Internally a synthetic step_end ActionResult is appended after the real actions; the visual timeline renders one extra tile per step.

One screenshot and one hierarchy captured after each UI action succeeds, plus a best-effort capture on the failing action. This is the mode that makes the replay feel like a video. Used automatically when --report-html is provided.

scripts/verify-ios-visual.sh greps the rendered HTML for a list of known-demo secrets (hunter2, Secret123) and fails the build if any leaks. Add new canaries to that list when introducing new demo secrets.

Per-action capture in actions mode adds a Screenshot() and a Hierarchy() call to every UI action. On a slow simulator this can add several seconds per scenario. Recommendations:

  • CI, stick to failures unless you specifically want the visual replay.
  • Local debugging, run --capture-screenshots actions only when needed.
  • Capture errors never mask the underlying action error. They are silently dropped: the action’s status, duration, and error reflect the real operation, while the missing screenshot / hierarchy fields on that action signal that the capture itself failed.
  • Screenshot-based, not real video. No MP4 generation.
  • No visual diff between runs.
  • Mobile provider only. HTTP and keyword steps appear as plain entries with no screenshots. A web/browser provider is planned.
  • Assets are external files by default (no base64 embedding). Moving the HTML file without moving build/artifacts/ breaks image references, copy the artifacts tree alongside.
  • Relative-path conversion falls back to the absolute path if filepath.Rel fails (cross-volume on Windows). The report still works locally but loses portability.
  • Console, prints HTML report: <path> after writing.
  • JSONL (--report-jsonl), emits one "type":"action" event per action after the step event when step.Actions is populated. Empty action slices produce byte-identical JSONL to the pre-visual-report format.
  • JUnit (--report-junit), unchanged. Action-level data is intentionally not flattened into JUnit XML.