This documentation is available as Markdown. For the complete index, see llms.txt. Skip to content

Troubleshooting

For the complete documentation index, see llms.txt

Diagnostics

In normal operation the CLI prints a single actionable line — no stack traces. For full diagnostics (JSONL log + per-call artifacts), set:

Terminal window
cd unotest && UNOTEST_DEBUG=1 npx @unotest/web e2e <name>

The JSONL lands in unotest/.debug/<pid>-<start-time>/log.jsonl (rotated as log-001.jsonl, …, with index.jsonl and one folder per tool call beside it); stdout stays as it was. The log is layered (tool, step, resolver, driver, refs, snapshot, network); the step layer carries enter / exit events per scenario statement (file, line, column, the enclosing step("…") label), so every driver action below it says which statement it happened under.

Common issues

  • astro: not found / command missing — install dependencies first (npm install).
  • No MCP tools in the editor — re-run init, then reload the editor so it re-reads .mcp.json.
  • Selector keeps drifting — switch to a stable selector (getByTestId / getByRole).
  • A JS global in a scenario — for time and waiting a scenario has steps of its own: Date.now() → clockFreeze / clockTick / clockRun, or nowMs(); setTimeout(…) → pause(ms) or waitUntil(() => …). Another framework’s spelling (clock.freeze(…), page.waitForTimeout(…)) is answered with the name to use here.
  • run_test answers spawn_failed — the runner child died before it wrote its first runtime.json; the reason carries its exit code and the last lines of spawn.stderr.log in the run’s directory. A runner that is alive is waited for (up to 60 s; a run waiting in the queue is reported as queued instead), so this is a real start failure — read the stderr tail.
  • run_test answers config_error — the runner refused the scenario before its first step because the judge it calls with assertJudge cannot answer. Nothing was driven; the reason carries the runner’s stderr with what to fix (a missing UNOTEST_JUDGE_* variable, a judge service that is not running). Fix the setup, not the launch. The judge guide lists the variables.
  • A run hangs after a failed step — the page’s main thread is busy (a script in an endless loop), and reading it for the failure bundle waits for an answer that never comes. Since 0.49.1 each read gets 15 s; the test stays red with its own error, and the output adds the page gave no answer within 15s after the failed step. Find what keeps the page busy. A DSL evaluate(js) on such a page fails its step after the action timeout (defaultTimeoutMs) with the page gave no answer; a script that has started runs as long as it needs, within the test’s time budget.
  • Flaky tab/iframe timing — wait for the tab or the content, not for a time: waitForPage() takes the tab a click opened and makes it active; in a frame, enterFrame(loc) and then a waitFor… on what it shows. pause(ms) with a // reason: comment is the last resort.
  • iOS: “command not found” on xcrun — you’re not on macOS or missing Xcode CLI tools. iOS is macOS-only.

Known limitations

  • Network HAR & video aren’t captured yet (failure bundle tier 3). Use screenshot + console + semantic DOM + trace.
  • dragAndDrop / clipboard paste use synthetic events, not native HTML5 DragEvent / ClipboardEvent. For apps that require native events, dispatch via evaluate().
  • The viewer currently drives web only. Its runner architecture is multi-runner-ready, but mobile isn’t wired into it yet.

For agent-facing rules, see the Authoring guide.