dánwòdánwò

Writing tests

Debugging a failure

Read a failed run's page from top to bottom, and know what each error code asks you to look at.

Every failed run keeps a flight record. Start from its failure page: the error, the steps, the screen, and what happened behind it, in one place.

Open the failure page

npx @danwo/cli show --format md

It prints one page per failed test or matrix trial of the newest run. Pass a run id for an older one.

Read it top to bottom

The top: what failed, and where

The test, the fault if a matrix trial, the error code, and the line the failure went through:

fault: duplicate on webhook checkout.session.completed · failed · EXPECTATION_FAILED (test) · 2.7 s

**Error at tests/buy-credits.danwo.ts:19:**
invariant: expected 1000 to be 500 // Object.is equality

The steps

Each step with its status, its cache outcome, model calls, time and line:

| 4 | getByRole("heading", name: "Thank you for your purchase") toBeVisible() | passed | … | tests/buy-credits.danwo.ts:15 |
| 5 | getByText(/^Credits: /) toHaveText("Credits: 500") | failed: EXPECTATION_FAILED | … | tests/buy-credits.danwo.ts:16 |

The screen at failure

What the page showed, as an accessibility tree:

- main:
  - heading "Thank you for your purchase" [level=1]
  - paragraph: "Credits: 1000"

What was behind the page

Console errors, failed or faulted provider calls, webhook deliveries, and each emulator's state at the end. Here, the same webhook arrived twice and the app answered both:

| topic                      | attempt | status | fault     |
| checkout.session.completed | 1       | 200    | duplicate |
| checkout.session.completed | 1       | 200    |           |

That's the bug: the app credited the account once per delivery.

What the error code says to check

CodeLook at
LOCATOR_NOT_FOUND, LOCATOR_AMBIGUOUSthe screen at failure, and the nearest candidates it lists
EXPECTATION_FAILEDexpected against received: is the app wrong, or the test?
CLAIM_FAILEDthe judge's reason. The claim may be too strict.
APP_ERRORyour app's own 5xx or uncaught error: an app bug
PROVIDER_ERRORthe failed provider call, and whether your app recovered
STALE_RECORDING, NOTHING_RECORDEDrun danwo test once to record, then the matrix
AGENT_LOOPING, BUDGET_EXCEEDEDa vague instruction or a changed page. Split the step, or use locators.
MODEL_OUTPUT_INVALID, MODEL_UNAVAILABLEthe model provider, not your app. Retry, or change model.
MODEL_REFUSEDthe model declined the step. Reword it, or run it on another model.
BROWSER_FAILED, ENVIRONMENT_FAILEDthe browser or the environment: app start-up, emulators, ports
CONFIG_INVALIDthe config, or the call the message names

danwo spec --topic errors lists every code with its exit code.

When a run fails before any test starts, npx @danwo/cli doctor checks the machine and the config.

Connection noise

A browser dropping a socket as a page closes (ECONNRESET, EPIPE, socket hang up) is expected, so danwo doesn't print it. To see those lines while chasing a connection problem:

DANWO_DEBUG=proxy npx @danwo/cli test

Every other proxy error always prints.

Next

On this page

Run it on every pull request

A GitHub check and one comment per pull request, with the flight records attached.

Set up CI