Understanding sequential request execution and test flow control in HTTPSpec
HTTPSpec executes requests sequentially within each test file, stopping on the first assertion failure. This design enables powerful testing patterns for workflows that require ordered operations.
If any assertion fails, subsequent requests in that file do NOT execute:
### Make a simple 200 request to HTTP BinGET http://httpbin.org/status/200Content-Type: application/json### Make a simple 404 request to HTTP BinGET http://httpbin.org/status/404Content-Type: application/json//# status == 403### Make a simple 201 request to HTTP BinGET http://httpbin.org/status/201Content-Type: application/json
Execution flow:
First request (200) → no assertions → passes → continue
Second request (404) → asserts status == 403 → fails → STOP
Third request (201) → never executes
Output:
[Fail] Expected status code 403, got 404
Once an assertion fails, all subsequent requests in that file are skipped. Design your test files with this behavior in mind.
Test workflows where later requests depend on earlier ones:
### Create an orderPOST https://api.example.com/ordersContent-Type: application/jsonAuthorization: Bearer ABC123{ "user_id": 123, "items": [{"product_id": 456, "quantity": 2}]}//# status == 201//# body contains "order_id"### Add item to the orderPOST https://api.example.com/orders/789/itemsContent-Type: application/jsonAuthorization: Bearer ABC123{"product_id": 999, "quantity": 1}//# status == 200### Complete the orderPOST https://api.example.com/orders/789/completeAuthorization: Bearer ABC123//# status == 200//# body contains "completed"
Currently, HTTPSpec does not support extracting values from one response to use in the next request. This is a planned feature. For now, you’ll need to hardcode IDs or use predictable values.
### Create draft documentPOST https://api.example.com/documentsContent-Type: application/json{"title": "My Document", "status": "draft"}//# status == 201//# body contains "draft"### Submit for reviewPOST https://api.example.com/documents/123/submit//# status == 200//# body contains "pending_review"### Approve documentPOST https://api.example.com/documents/123/approve//# status == 200//# body contains "approved"### Publish documentPOST https://api.example.com/documents/123/publish//# status == 200//# body contains "published"
Verify that the system recovers from error states:
### Attempt invalid operationPOST https://api.example.com/invalid-endpoint//# status == 404### Verify system still worksGET https://api.example.com/health//# status == 200//# body == "OK"
Requests without assertions still execute and must succeed (no HTTP errors):
### This request has no assertions but must complete successfullyGET https://api.example.com/usersContent-Type: application/json### This request will execute if the previous one succeedsGET https://api.example.com/users/123//# status == 200
If the first request fails (network error, connection timeout, etc.), the test fails even without explicit assertions.
Put critical assertions early to avoid wasted requests:
### Verify authentication worksGET https://api.example.com/auth/verifyAuthorization: Bearer ABC123//# status == 200### Now do the actual testPOST https://api.example.com/users
### Create user (required for subsequent tests)POST https://api.example.com/usersContent-Type: application/json{"name": "Alice"}//# status == 201### Fetch user (depends on previous request)GET https://api.example.com/users/123//# status == 200
If cleanup fails, subsequent test runs might have issues:
### TestPOST https://api.example.com/users//# status == 201### Cleanup - if this fails, user stays in DBDELETE https://api.example.com/users/123//# status == 204
Consider using unique identifiers or timestamps to avoid conflicts.
### This will failGET https://api.example.com/users/999999//# status == 200 # Expected 200 but gets 404### This cleanup will NEVER runDELETE https://api.example.com/users/999999