Skip to content

QA Plans

A QA plan is the central object in aqua. It organizes your test scenarios and steps into a structured, versioned document that can be executed against any environment.

The QA plan data model follows a four-level hierarchy:

QAPlan
└─ QAPlanVersion
└─ Scenario
└─ Step

Each level has a distinct role:

  • QAPlan — The top-level container that represents an entire test plan.
  • QAPlanVersion — An immutable snapshot of the plan at a point in time.
  • Scenario — A named group of related test steps.
  • Step — An individual test action (HTTP request or browser interaction).

A QAPlan holds metadata about the overall test plan.

FieldDescription
nameHuman-readable name for the plan.
descriptionExplanation of what the plan tests.
git_branch(optional) The Git branch this plan is associated with.
pull_request_url(optional) A link to the related pull request.
statusCurrent lifecycle status: draft, active, or archived.

Every time you update a plan’s content, a new QAPlanVersion is created. Versions are immutable snapshots, meaning once created they cannot be modified. Each version receives an auto-incremented version number.

A version contains:

  • variables — Default variable values used across scenarios and steps.
  • scenarios — The ordered list of scenarios and their steps.

Immutability ensures that execution results always reference the exact plan content that was tested.

A scenario is a named group of steps that together verify a particular behavior or workflow.

FieldDescription
nameDescriptive name for the scenario.
requires(optional) A list of variable names that must be present. If any required variable is missing from the environment, the scenario is skipped.
stepsOrdered list of steps to execute.

The requires field enables conditional execution. For example, a scenario that tests admin features can declare requires: ["admin_token"], and it will be automatically skipped when running against an environment that does not provide that variable.

A step is the smallest unit of testing — a single action with optional assertions and value extraction.

FieldDescription
step_keyA user-defined unique identifier for the step. Used for dependency references.
actionThe type of action: "http_request" or "browser".
depends_on(optional) A list of step_key references that must complete before this step runs. Dependencies can cross scenario boundaries.
assertions(optional) Validation checks to run against the step’s result.
extract(optional) Extract values from the result for use as template variables ({{variable}}) in subsequent steps.
condition(optional) A condition that must be met for the step to execute. If not met, the step is skipped. See Conditional Step Execution below.

The depends_on field allows you to express ordering constraints between steps. Dependencies can reference step keys in the same scenario or in different scenarios, giving you flexibility to model complex test flows.

If a dependency step has failed or was skipped, the dependent step will also be skipped.

The extract field lets you capture values from a step’s response and make them available as template variables. Extracted variables are global — they can be referenced by any subsequent step in any scenario.

For example, after creating a resource via an API call, you can extract the returned id and use it as {{resource_id}} in later steps.

The condition field allows you to control whether a step executes based on the value of a variable. This is evaluated after depends_on checks. Two condition types are supported:

  • variable_equals — Execute the step only if a variable equals a specific value.
  • variable_not_equals — Execute the step only if a variable does NOT equal a specific value.

When a variable is undefined, variable_equals conditions are not met (step is skipped), while variable_not_equals conditions are met (step runs).

Conditional steps are typically independent preparation steps that are not connected via depends_on to subsequent steps. The variables used in conditions come from extract in previous steps.

Example — Run different setup steps based on a user’s role:

{
"step_key": "check_role",
"action": "http_request",
"config": {
"method": "GET",
"url": "{{api_base_url}}/users/me",
"headers": { "Authorization": "Bearer {{auth_token}}" }
},
"extract": {
"user_role": "$.data.role"
}
}
{
"step_key": "admin_setup",
"action": "http_request",
"condition": {
"type": "variable_equals",
"variable": "user_role",
"value": "admin"
},
"config": {
"method": "POST",
"url": "{{api_base_url}}/admin/prepare-test-data",
"headers": { "Authorization": "Bearer {{auth_token}}" }
}
}

In this example, the admin_setup step only runs if the extracted user_role variable equals "admin". Otherwise, the step is skipped.

A QA plan moves through three statuses:

draft ◀──▶ active ──▶ archived
StatusMeaning
draftThe plan is being developed or has been updated. It can be edited and executed.
activeThe plan is promoted automatically when all tests pass. Represents a validated, passing plan.
archivedThe plan is no longer in use.

Auto-promotion: The transition from draft to active happens automatically when an execution completes with all steps passing. This ensures that only validated plans carry the active status.

Auto-demotion: When a new version is added to an active plan, the status is automatically reverted to draft. Since the test content has changed, the plan must be re-validated by running the new version successfully.

aqua provides two mechanisms for sharing state between scenarios:

  1. Extract variables — Values extracted in any step are available globally. A variable extracted in Scenario A can be referenced in Scenario B using {{variable}} templates.
  2. Browser storageState — When using the browser driver, cookies and localStorage are preserved across scenarios via the browser’s storageState. This means a login performed in one scenario carries over to subsequent scenarios without repeating the authentication steps.