编写测试

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
PACKAGE_MISSINGa danwo package the command needs. Run the install 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. For a mobile config it checks the simulator or emulator toolchain too, and Flutter for a Flutter app.

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.

HTTP/2 and gRPC calls

The proxy speaks HTTP/2 to a client that offers only HTTP/2, such as a gRPC client. Everyone else, browsers included, gets HTTP/1.1. Each HTTP/2 call is its own entry in the flight record, with its path, status and the fault it got.

The client saysWhat it means
UNAVAILABLE, and the record shows a 502the proxy couldn't reach the real server; the 502's body says why
INTERNAL: Received RST_STREAM with code 2a reset fault hit this call, or the server reset it
certificate signed by unknown authoritythe client doesn't trust danwo's CA; see other languages
no application protocol in the TLS handshakethe client offered neither HTTP/1.1 nor HTTP/2

Next

本页内容

在每个 Pull Request 上运行

每个 Pull Request 一个 GitHub Check 和一条评论,并附上完整的运行记录。

配置 CI