API Testing
API Testing lets you create, organize, and run REST API test collections with assertions and variable chaining.
License: API Testing requires Pro or Enterprise tier.
Overview
API Testing in QAID provides a Postman-like interface for testing REST APIs:
- Collections group related API requests together
- Requests define HTTP calls with headers, body, auth, and assertions
- Variable chaining passes data between requests (e.g., extract a token from login, use it in subsequent requests)
- Collection runs execute all requests sequentially and track pass/fail results
- Playwright export generates standalone
.spec.tsfiles for CI/CD integration
Getting Started
Creating a Collection
- Navigate to API Testing in the sidebar
- Click "New Collection"
- Enter:
- Name (required) — e.g., "User API Tests"
- Base URL (optional) — e.g.,
https://api.example.com. Relative request URLs will be appended to this.
- Click "Create"
Adding Requests
- Open a collection
- Click "Add Request" in the left panel
- Configure the request (see Request Builder below)
- Changes auto-save as you type
Request Builder
The request builder has a URL bar and five configuration tabs.
URL Bar
- Method dropdown — GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
- URL field — Full URL (
https://api.example.com/users) or relative path (/users) - Send button — Quick-test a single request without creating a run
Headers Tab
Key-value editor for custom HTTP headers. Each header has an enable/disable checkbox.
Example:
| Key | Value |
|---|---|
X-Custom-Header | my-value |
Accept | application/json |
Body Tab
Select a body type:
| Type | Content-Type | Use For |
|---|---|---|
| None | — | GET requests |
| JSON | application/json | API payloads |
| Form | application/x-www-form-urlencoded | Form submissions |
| Text | text/plain | Raw text |
Enter the body content in the text area. Supports variable interpolation with {{variableName}} syntax.
Auth Tab
Choose an authentication method:
| Type | Fields | Header Generated |
|---|---|---|
| Inherit | — | Uses collection-level auth |
| No Auth | — | No auth header |
| Bearer Token | Token | Authorization: Bearer <token> |
| Basic Auth | Username, Password | Authorization: Basic <base64> |
| API Key | Key name, Value, Add to (Header/Query) | Custom header or query param |
All auth fields support {{variable}} interpolation.
Assertions Tab
Define checks that run against the response. Each assertion has a type, operator, and expected value.
Status Code
Verify the HTTP status code.
| Operator | Example |
|---|---|
| equals | Status equals 200 |
| not_equals | Status not equals 500 |
>=, >, <=, < | Status < 400 |
JSON Path
Check values in the JSON response body using dot notation.
| Operator | Path Example | Expected |
|---|---|---|
| equals | data.user.name | "John" |
| contains | data.message | "success" |
| exists | data.token | — |
| not_exists | data.error | — |
| matches (regex) | data.email | ".*@example.com" |
| length_gte | data.items | 5 |
Header
Check response headers (case-insensitive matching).
| Operator | Header | Expected |
|---|---|---|
| contains | content-type | application/json |
| exists | x-request-id | — |
Response Time
Verify the response completes within a time limit.
| Operator | Expected |
|---|---|
<= | 1000 (ms) |
Body Contains
Check the raw response body text.
| Operator | Expected |
|---|---|
| contains | "success" |
| not_contains | "error" |
| matches (regex) | "id\":\s*\d+" |
Variables Tab
Extract values from responses to use in subsequent requests.
| Variable Name | JSON Path | Result |
|---|---|---|
userId | data.user.id | Extracts data.user.id from JSON response |
authToken | data.token | Extracts data.token from JSON response |
Use extracted variables in other requests with {{userId}} or {{authToken}} in URLs, headers, body, or auth fields.
Variable Chaining
Variable chaining lets you pass data between requests in a collection run.
How It Works
- Request 1 (Login) extracts
{{token}}from its response - Request 2 (Get User) uses
{{token}}in its Bearer auth - Request 2 extracts
{{userId}}from its response - Request 3 (Update User) uses both
{{token}}and{{userId}}
Variable Scope
Variables are resolved in this order (highest priority first):
- Extracted variables from previous requests in the run
- Collection-level variables (static, set on the collection)
- Initial variables passed when starting the run
Tips
- Variable names are case-sensitive:
{{userId}}is not the same as{{userid}} - Unresolved variables stay as literal text (e.g.,
{{unknown}}is sent as-is) - Use dot notation for nested values:
data.user.profile.id - The left panel shows dependency arrows between requests that share variables
Quick Send vs Collection Run
| Quick Send | Collection Run | |
|---|---|---|
| Triggered by | "Send" button on a request | "Run Collection" button |
| Scope | Single request | All enabled requests |
| Variables | Collection-level only | Accumulated across requests |
| Results saved? | No (transient) | Yes (in Runs tab) |
| Purpose | Debug/test during design | Full integration test |
Running a Collection
Starting a Run
- Open a collection
- Click "Run Collection" in the header
- All enabled requests execute sequentially
- Results appear in the Runs tab
During Execution
- Requests run one at a time (sequential, not parallel) to support variable chaining
- If a request fails, execution continues to the next request (all requests run regardless)
- Variables accumulate as each request completes
Viewing Results
Switch to the Runs tab to see all past runs. Click a run to see detailed results:
Summary cards:
- Pass Rate (percentage)
- Total Time (milliseconds)
- Requests Passed (count)
- Assertions Passed (count)
Per-request results:
- Status icon (pass/fail/error/skipped)
- HTTP status code badge
- Response time
- Assertion count
- Click to expand for details:
- Assertion results (each with pass/fail and message)
- Extracted variables
- Response body (formatted JSON)
- Response headers
Result Statuses
| Status | Meaning |
|---|---|
| Passed | All assertions passed |
| Failed | One or more assertions failed |
| Error | Network error, timeout, or request failed to execute |
| Skipped | Request was disabled |
Disabling Requests
Toggle the enabled state on a request to skip it during collection runs. Useful for:
- Temporarily excluding requests that are under development
- Conditional test flows
- Reducing run time
Disabled requests are also excluded from Playwright export.
Duplicating Requests
Hover over a request in the left panel and click the copy icon to duplicate it. This creates an exact copy with "(copy)" appended to the name.
Exporting to Playwright
Generate a standalone Playwright test file from your collection:
- Open a collection
- The export generates a
.spec.tsfile with:- One
test()per enabled request - Playwright
requestAPI calls (GET, POST, etc.) expect()assertions for status codes, JSON paths, and headers- Proper Content-Type and auth headers
- One
Example output:
import { test, expect } from '@playwright/test';
test.describe('User API Tests', () => {
const BASE_URL = 'https://api.example.com';
test('GET List Users', async ({ request }) => {
const response = await request.get(`${BASE_URL}/users`);
expect(response.status()).toBe(200);
const body = await response.json();
expect(body.data).toBeDefined();
});
});Note: Variable interpolation is not translated to Playwright (assertions use static values). For dynamic flows with variable chaining, use QAID's built-in collection runs.
Collection Settings
Edit collection settings by updating:
- Name — Collection display name
- Base URL — Shared base for relative request URLs
- Auth — Default authentication for all requests (requests can override with "Inherit")
- Variables — Static key-value pairs available to all requests
Best Practices
Organizing Collections
- Group related endpoints in one collection (e.g., "Auth API", "User API", "Orders API")
- Order requests logically — put login/setup first, then operations, then cleanup
- Use descriptive request names
Variable Chaining
- Extract tokens and IDs early in the collection
- Use meaningful variable names (
authToken, nott) - Check variables with
existsassertions to catch extraction failures
Assertions
- Always assert status codes
- Use JSON path assertions for response structure validation
- Add response time assertions for performance monitoring
- Use
containsoverequalsfor values that may change slightly
Authentication
- Set collection-level auth for shared tokens
- Use per-request auth overrides only when testing different roles
- Use variable interpolation for dynamic tokens:
{{authToken}}
Troubleshooting
Request Fails with Network Error
- Check that the URL is correct and the server is reachable
- If using a relative URL, ensure the collection has a Base URL set
- Check for CORS issues if testing from a different domain
Variables Not Resolving
- Verify the JSON path in the Variables tab matches the actual response structure
- Check that the producing request runs before the consuming request
- Variable names are case-sensitive
Assertions Failing Unexpectedly
- Use Quick Send to inspect the actual response
- Check that JSON paths match the response structure (use dot notation:
data.items.0.id) - For header assertions, header names are matched case-insensitively
Response Body Truncated
- Large response bodies may be truncated in stored results
- Full responses are visible during Quick Send
Related Topics
- Automated Tests — UI-based end-to-end tests
- Test Plan — Organize API and UI tests together
- Test Runs — Execute test plans
- Settings — Project and environment configuration