API testing
Two steps in the Integration category let a test talk to the application’s API directly, instead of going through its screens:
| Step | What it does |
|---|---|
HTTP request (http.request) |
Sends one request and saves the response in a variable |
Poll API (http.poll) |
Repeats a request until a condition on the response is true |
They run inside the test’s browser context, so they share the UI session’s cookies. A request made after signing in on screen is authenticated as that user.
Typical uses:
- Set up test data fast: create the vendor with one API call, then test the screen.
- Tear down what the test created, in cleanup.
- Verify that what the screen claims was really stored.
- Wait for asynchronous work (a job, an approval) without a fixed Wait.
HTTP request
Section titled “HTTP request”| Parameter | Required | Meaning |
|---|---|---|
| url | yes | Absolute URL, a template: {{apiUrl}}/orders/{{order.body.id}} |
| method | GET (default), POST, PUT, PATCH, DELETE, HEAD |
|
| headers | Name → template, e.g. Authorization = Bearer {{auth.body.token}} |
|
| body | Text sent as-is, a template. If it starts with { or [ and you set no Content-Type, it is sent as application/json. |
|
| expectStatus | Accepted status codes: 201, 2xx, 200,204, 4xx, or any. Empty means any 2xx. Anything else fails the step. |
|
| saveAs | Variable that receives the response | |
| sensitive | Masks every string in the response body in reports, logs and saved variables. Use it on login and token calls. |
Using the response
Section titled “Using the response”A saved response looks like this:
{ "status": 201, "ok": true, "headers": { "content-type": "application/json" }, "body": { "id": "V-1001", "name": "Acme", "status": "Active" }, "durationMs": 4}JSON bodies are parsed, so later steps can use fields:
- in a template:
{{vendor.body.id}}, in a URL, header, body or value to type, - in a check: an Expression assertion
vendor.body.status == 'Active', - lists by index:
orders.body.0.id, andCOUNT(orders.body) > 0.
The response is saved even when the status check fails, so cleanup can still use it.
Poll API
Section titled “Poll API”All the HTTP request parameters, plus:
| Parameter | Required | Meaning |
|---|---|---|
| until | yes | Expression checked after each response, which is available as response, e.g. response.body.state == 'done' |
| intervalMs | Time between requests (default 1000, max 60000) | |
| maxAttempts | Most requests to send (max 1000). The step’s Timeout also limits the whole poll. |
A poll that never meets its condition fails. It cannot run forever.
Pattern: test data setup
Section titled “Pattern: test data setup”1. HTTP request POST {{apiUrl}}/auth/token body {"user":"{{secret.API_USER}}",…} saveAs auth sensitive2. Set variable vendorName = CONCAT('Vendor ', NOW())3. HTTP request POST {{apiUrl}}/vendors header Authorization: Bearer {{auth.body.token}} body {"name":"{{vendorName}}"} expectStatus 201 saveAs vendor4. Open {{baseUrl}}/vendors5. Exists text "Active" scoped to row with key {{vendor.body.id}}- Give records unique names so runs that share an environment do not collide.
- To find the record on screen, scope the target to its grid row by key. Scope keys are templates; strategy values are fixed text.
Pattern: teardown
Section titled “Pattern: teardown”Put deletes in the test’s cleanup list, which runs whether the test passed or
failed. Give each cleanup step On error: Continue and accept 404:
"cleanup": [ { "id": "delete-vendor", "type": "http.request", "onError": "continue", "params": { "method": "DELETE", "url": "{{apiUrl}}/vendors/{{vendor.body.id}}", "headers": { "Authorization": "Bearer {{auth.body.token}}" }, "expectStatus": "204,404" } }]Delete in reverse order of creation (children before parents).
Cleanup steps cannot yet be added in the editor. Add them in the test JSON. See Editor limitations.
Pattern: verify server state
Section titled “Pattern: verify server state”- UI steps create the record. An Extract step reads its id from the screen.
- HTTP request
GET {{apiUrl}}/vendors/{{createdId}}, saveAsstored. - One Expression assertion per field, each marked Soft assertion, so one run reports every mismatch.
Pattern: wait for a background job
Section titled “Pattern: wait for a background job”HTTP request POST {{apiUrl}}/orders/{{order.body.id}}/approve expectStatus 202 saveAs jobPoll API GET {{apiUrl}}/jobs/{{job.body.id}} until response.body.state == 'done' intervalMs 500 maxAttempts 40Examples
Section titled “Examples”examples/api-demo/ has four complete tests and a small demo API:
npm run demo:apinpm run seed:api-examples -- <projectId> <ownerUserId> --runSee examples/api-demo/README.md and
Data, backup and seeding.