API testing
tapstep is not a Postman replacement — it makes the API a first-class citizen
inside a flow. Use request: steps for setup, teardown and backend checks,
and chain them with UI steps in the same file: what you create through the API
you verify on screen, sharing the same ${variables}.
A pure-API flow
Section titled “A pure-API flow”A flow with device: none never resolves or boots a device — it runs
anywhere, instantly:
device: noneenv: { API: "https://api.example.dev" }commands: - request: method: POST url: ${API}/staff auth: { bearer: "${STAFF_TOKEN}" } json: { email: "qa@test.dev", role: staff } extract: { staffId: $.id } # JSONPath → ${staffId} assert: status: 201 # a code, or a class: "2xx" json: { $.role: staff } - request: url: ${API}/staff/${staffId} retryUntil: { status: "2xx" } # poll every second until it passes timeout: 15000Under device: none only request, scripts, value asserts (assertTrue,
assertFile) and control flow are allowed — a UI command is a validation
error. In the desktop app such flows run without the device picker; in the
CLI no device is probed or auto-booted.
Chaining API and UI
Section titled “Chaining API and UI”In a normal (device) flow, request: steps mix freely with UI steps:
appId: https://staging.example.devcommands: - request: # arrange: create through the API method: POST url: ${API}/staff auth: { bearer: "${STAFF_TOKEN}" } json: { email: "qa@test.dev" } extract: { staffId: $.id } - openLink: "${APP}/staff/${staffId}" # act + assert: verify in the UI - assertVisible: "qa@test.dev"What request: supports
Section titled “What request: supports”| Field | Meaning |
|---|---|
method, url |
GET by default; - request: <url> is a GET shorthand. |
headers, query |
String maps, ${}-substituted. |
json / body |
Structured JSON body or a raw string (one or the other). |
auth |
{ bearer: ${TOKEN} } or { basic: { user, pass } }. |
extract |
var: $.json.path — response values into ${var} for later steps. |
assert |
status (code or "2xx"), json equalities or { contains: "…" }, headers, schema (a JSON Schema file next to the flow, or inline). |
retryUntil |
Same shape as assert, but polls until it passes or timeout expires — wait for the backend to reach a state. |
timeout |
Per-request ms (default 30000); the polling deadline with retryUntil. |
After every request ${response.status} and ${response.body} are available
to the following steps. On a failed assertion the report carries the method,
URL, status and a slice of the response body — in JUnit, Allure and HTML
output alike.
Deliberately out of scope: load testing, mocks/stubs, GUI collections. For end-to-end work the common Postman moves — call, extract, assert, poll — are covered right in the flow.