> For the complete documentation index, see [llms.txt](https://learning.contextqa.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://learning.contextqa.com/web-testing/test-data-management.md).

# Test Data Management

{% hint style="info" %}
**Who is this for?** Testers and SDETs who need parameterized, data-driven testing — running the same test with multiple data sets without duplicating test cases.
{% endhint %}

ContextQA provides four complementary data management mechanisms: local variables scoped to one test case, global variables shared across the workspace, environment parameters that vary between deployment targets, and test data profiles for data-driven testing. Insert values through the step editor's data or parameter picker whenever possible. The visible syntax depends on the source: an environment value such as `baseURL` appears as `*|baseURL|*`, while a field captured from an earlier API response uses a runtime expression such as `${loginResult.body.token}`.

[Watch the local-versus-global variables walkthrough](https://drive.google.com/file/d/1iX_UkzEWYG52QiNoIl7em5qnNrxV7oeW/preview) and the [environments-and-profiles walkthrough](https://drive.google.com/file/d/1UbcQCoDLHLrjbau3Jfb9HqGF3lnsGR-m/preview).

For values that must be fresh and unique on every run — a new email address, a current timestamp, a random amount — ContextQA also provides [random functions](#generating-random-test-data-with-random-functions), which generate a new value each time the test executes.

{% hint style="info" %}
Global variables, environment variables, and test data profiles are managed together in the [Environment Data Management](/web-testing/environment-data-management.md) workspace. This page explains how each variable type resolves inside test steps.
{% endhint %}

## Prerequisites

* You have at least one test case created.
* You have access to the workspace settings (you are a workspace member with Editor or Admin role).
* For data profiles: you have an environment and a test case that can use the selected profile rows.

***

## Variable naming rules

Every variable name you define — local variables, global variables, environment parameters, test data profile columns, and the variables that store an API response or a step's output — follows one consistent set of naming rules. ContextQA validates the name as you type and blocks saving until the name is valid, so a malformed name never reaches a test run where it is harder to debug.

### Format rules

A valid variable name:

* Starts with a letter (`A`–`Z`, `a`–`z`) or an underscore (`_`).
* Contains only letters, numbers, and underscores after the first character.
* Contains no spaces or other special characters.
* Is case-sensitive — `orderId` and `orderid` are two different variables.

| Example     | Valid? | Reason                                               |
| ----------- | ------ | ---------------------------------------------------- |
| `orderId`   | Yes    | Starts with a letter; letters and digits only        |
| `_token`    | Yes    | A leading underscore is allowed                      |
| `user_2`    | Yes    | Digits are allowed after the first character         |
| `2ndUser`   | No     | Cannot start with a number                           |
| `user name` | No     | Spaces are not allowed                               |
| `user-name` | No     | Hyphens and other special characters are not allowed |
| `123`       | No     | Cannot be only numbers                               |

### Reserved keywords

A variable name cannot match a reserved keyword. Reserved keywords are identifiers that ContextQA and the underlying test runtime already use — JavaScript keywords, runtime globals, and internal execution variables. Naming a variable after one of them shadows the built-in and breaks the generated test, so ContextQA rejects these names.

Reserved keywords are matched case-insensitively, so `os`, `OS`, and `Os` are all rejected.

Common reserved keywords include:

* Runtime globals such as `os`, `path`, `fs`, `moment`, `shell`, `otpauth`, and `page`.
* JavaScript keywords such as `const`, `let`, `function`, `return`, `class`, and `await`.
* HTTP method names such as `get`, `post`, `put`, and `delete`.

If a name is rejected as reserved, add a prefix or suffix to make it unique — for example, use `osName` instead of `os`, or `userPath` instead of `path`.

### Referencing nested values

When you *reference* a variable that holds structured data, you can access its members and array elements with dot and index notation — `${loginResponse.body.token}` or `${items[0]}`. This applies only where you reference a variable. When you *declare* a variable name, the name itself must be a plain identifier with no `.` or `[]`.

### Error messages

When a name breaks a rule, the field shows the specific reason:

| Message                                                                                     | Cause                                          | Fix                                                |
| ------------------------------------------------------------------------------------------- | ---------------------------------------------- | -------------------------------------------------- |
| `Name cannot start with a number.`                                                          | The name begins with a digit                   | Start with a letter or underscore                  |
| `Name cannot start with a special character.`                                               | The name begins with a symbol                  | Start with a letter or underscore                  |
| `Name cannot be only numbers.`                                                              | The name contains only digits                  | Include at least one letter or underscore          |
| `Name can only contain letters, numbers, and underscores, no spaces or special characters.` | The name contains a space or special character | Remove spaces and symbols; use underscores instead |
| `Name cannot be a reserved keyword.`                                                        | The name matches a reserved keyword            | Choose a different, unique name                    |

{% hint style="info" %}
The AI Agent step's **What should the agent achieve?** field phrases these same messages as "Variable name …" instead of "Name …". The rules are identical.
{% endhint %}

***

## Local Variables

Local variables are scoped to a single test case. They exist only during the execution of that test case and are not visible to any other test case. Use local variables for values that are specific to one test scenario — a dynamically generated ID, a test-run timestamp, an intermediate value computed from an API response.

### Defining Local Variables

1. Open the test case.
2. Select the **Variables** tab in the test editor.
3. Select the add-variable action.
4. Enter the variable **Name** and optional **Default Value**.
5. Save the test case.

Alternatively, local variables are created implicitly when a REST API Call step stores its response: set "Store response in variable" to `myVar` and the variable `myVar` becomes available in all subsequent steps.

### Using Local Variables in Steps

Use the **Runtime** or variable picker in the step editor to insert a local variable into a supported field. The picker preserves the exact name and syntax expected by that field.

For example, choose a local `userId` from the Runtime picker when a later step needs the identifier captured earlier in the same test.

### Setting a Local Variable Dynamically

You can set or update a local variable at runtime using a **Set Variable** action in an AI Agent step:

```
Set the variable searchTerm to "blue running shoes"
```

Or capture a value displayed on the page:

```
Read the Order ID displayed on the confirmation page and store it as ${capturedOrderId}
```

The AI agent reads the specified element's text content and assigns it to the named variable. This captured value can then be used in subsequent steps or REST API calls.

***

## Global Variables

Global variables are workspace-scoped — they are available to every test case in the workspace. Use global variables for values that are shared across many test cases but are not environment-specific: a default admin account email, a standard test product name, a default search query.

### Creating Global Variables

1. Navigate to **Environment & Data → Global Data**.
2. Select **New global variable**.
3. Enter the variable **Name** and **Value**, then select its type.
4. Click **Save**.

### Using Global Variables in Steps

Insert global variables through the step editor's data picker. If a global variable and a local variable share the same name, verify the selected source in the picker rather than typing the reference manually.

For example, choose a workspace-wide `defaultSearchTerm` from the picker when many tests should use the same approved value.

### When to Use Global vs Local Variables

| Scenario                                            | Use                                    |
| --------------------------------------------------- | -------------------------------------- |
| Admin email used in 30+ test cases                  | Global variable                        |
| User ID returned by an API call in one test         | Local variable                         |
| Default search term used across multiple test cases | Global variable                        |
| Intermediate calculation within one test            | Local variable                         |
| Test data row values from a data profile            | Local (auto-populated per profile row) |

***

## Test Data Profiles

Test data profiles enable data-driven testing: running the same test case multiple times, each time with a different set of input values. A profile is a table where each column is a named variable and each row is one complete test run.

### Creating a Test Data Profile

1. Navigate to **Environment & Data → Test Data Profiles**.
2. Select **New test data profile**.
3. Enter a **Profile Name** (e.g., `LoginScenarios_MultiRole`).
4. Save the profile, open it, and select **Manage columns** to add each value your test uses.
   * Enter the column name exactly as it will be referenced in the test steps (case-sensitive).
5. Click **+ Add Row** for each data scenario.
6. Fill in the values for each cell.
7. Assign the profile to the environment that will supply its row values, then save.

### Example Data Profile

Profile name: `LoginScenarios_MultiRole`

| `username`         | `password`    | `expected_dashboard_title` | `expected_role_label` |
| ------------------ | ------------- | -------------------------- | --------------------- |
| `admin@test.com`   | `Admin123!`   | `Admin Dashboard`          | `Administrator`       |
| `manager@test.com` | `Manager456!` | `Manager Dashboard`        | `Manager`             |
| `viewer@test.com`  | `Viewer789!`  | `Reports Dashboard`        | `Read Only`           |
| `billing@test.com` | `Billing000!` | `Billing Dashboard`        | `Billing Admin`       |

When this profile is attached to a test case and executed, the test repeats across the selected rows. The Parameter picker maps `username`, `password`, `expected_dashboard_title`, and `expected_role_label` to the corresponding input or verification steps.

### Attaching a profile to a test case

Profiles are selected on the test case, with a start and end row controlling the data range:

1. Open the test case and edit its configuration.
2. Select the execution environment. Only profiles assigned to that environment are available.
3. Enable data-driven execution, select the **Test Data Profile**, and choose the start and end row.
4. Save the test case.
5. In the step editor, select the actions that should repeat and choose **Loop → Test data profile**.
6. Confirm the environment, profile, and row range, then create the looped steps.
7. Open each input step and use the **Parameter** picker to map the correct profile column.

The test now reuses one workflow across the selected rows. Run it directly for a focused check or include it in a suite and plan when you need scheduled or multi-device execution.

### Importing Profile Data from a Spreadsheet

If you have existing test data in Excel or CSV format, you can import it directly:

1. In the Data Profile editor, click **Import from Spreadsheet**.
2. Ensure your spreadsheet has column headers matching the profile's column names.
3. Upload the file.
4. ContextQA maps the columns and imports the rows. Review the preview and confirm the import.

### Exporting and importing whole profiles

You can also export and import entire test data profiles — not just individual rows — from the **Test Data Profiles** tab in Environment Data Management, in JSON or Excel format. Export a profile to back it up or move it to another workspace, and import a profile from a file to recreate it. See [Importing and exporting data](/web-testing/environment-data-management.md#importing-and-exporting-data) for the full workflow, including how to handle duplicate rows during import.

***

## Environment Parameters

Environment parameters are key-value pairs stored in an environment configuration. They represent values that differ between deployment targets — base URLs, API keys, database hostnames, feature flag settings.

### Creating Environment Parameters

1. Navigate to **Environment & Data → Environments**.
2. Open an existing environment or select **New environment**.
3. Open **Environment variables** and select **Add variable**.
4. Enter the **Name** and **Value**.
5. Select the **Type** and permission:
   * **String** — plain text such as a base URL.
   * **Password** or **Vault** — masked secret data such as credentials or API keys.
   * **RO / RW** — controls whether the value is read-only or can be changed by tests.
6. Save the environment.

### Using Environment Parameters in Steps

Use the step editor's data picker to insert environment values. For example, an environment variable named `baseURL` is inserted as `*|baseURL|*`:

```
Navigate to *|baseURL|*/login
```

### Environment Parameter vs Global Variable

Both can store reusable string values. The distinction is:

* **Environment parameters** vary between environments (staging BASE\_URL is different from production BASE\_URL).
* **Global variables** are the same across all environments.

If a value is the same whether running against staging or production, use a global variable. If it differs by environment, use an environment parameter.

***

## Using API Response Data as Variables

REST API Call steps can capture response data and make it available to subsequent steps as variables. This is the primary mechanism for chaining API calls and mixing API interactions with UI interactions within a single test case.

### Storing an API Response

In a REST API Call step, set the **Store response in variable** field to a variable name. The entire response object is stored under that name:

```
Step: REST API Call
  Method: POST
  URL: ${ENV.BASE_URL}/api/auth/login
  Body: { "email": "${ENV.ADMIN_EMAIL}", "password": "${ENV.ADMIN_PASSWORD}" }
  Store response in variable: loginResponse
```

### Accessing Response Data

The stored variable exposes the following sub-properties:

| Expression                              | Description                | Example Value         |
| --------------------------------------- | -------------------------- | --------------------- |
| `${loginResponse.status}`               | HTTP status code           | `200`                 |
| `${loginResponse.body.token}`           | Top-level JSON body field  | `eyJhbGci...`         |
| `${loginResponse.body.user.id}`         | Nested JSON body field     | `42`                  |
| `${loginResponse.body.user.email}`      | Nested JSON body field     | `admin@test.com`      |
| `${loginResponse.headers.content-type}` | Response header            | `application/json`    |
| `${loginResponse.headers.set-cookie}`   | Cookie set by the response | `session=abc; Path=/` |

### Chaining Multiple API Calls

```
Step 1 (REST API): POST /api/auth/login
  Store response in: authResponse

Step 2 (REST API): POST /api/projects
  Headers: Authorization: Bearer ${authResponse.body.token}
  Body: { "name": "Test Project ${timestamp}" }
  Store response in: projectResponse

Step 3 (AI Agent): Navigate to ${ENV.BASE_URL}/projects/${projectResponse.body.id}

Step 4 (AI Verification): Verify the project name "Test Project" is displayed
  in the page heading

Step 5 (REST API): DELETE /api/projects/${projectResponse.body.id}
  Headers: Authorization: Bearer ${authResponse.body.token}
  (Cleanup: delete the test project)
```

This pattern — create test data via API, test the UI that displays it, clean up via API — produces tests that are fully self-contained and do not leave orphaned data in the test environment.

***

## Generating Random Test Data with Random Functions

Random functions generate a fresh value every time a test runs. Use them when a step needs data that must be unique or realistic without you maintaining a fixed list — a new signup email on each run, a current timestamp, a random order amount, or a plausible name and address for a form.

Unlike variables, a random function is not a stored value you define ahead of time. You insert the function directly into a step's test data, and ContextQA evaluates it at execution time. Two runs of the same test produce two different values.

{% hint style="info" %}
Random functions are evaluated at runtime, so the same test run never reuses a value across executions. This makes them ideal for fields that reject duplicates, such as email addresses or usernames.
{% endhint %}

### Inserting a Random Function

1. Open the test case and edit the step whose test data you want to randomize.
2. In the test data field, open the value picker.
3. Select the **Random** value source.
4. Browse the functions by category, or search by name.
5. Select a function. If the function accepts parameters, enter values for them (for example, a length, a minimum and maximum, or a date format).
6. Apply the selection.

ContextQA inserts the function into the step as a braced expression, for example `{cqaRandom.email('test.com', 'Jane', 'Smith')}`. At execution time, the expression resolves to a generated value such as `jane.smith47@test.com`.

The **Random** value source is available anywhere you set a step's test data, including action steps, condition steps, and loop steps.

### Syntax

Random functions use single braces and the `cqaRandom` prefix:

```
{cqaRandom.functionName(arguments)}
```

This syntax is distinct from the `${variableName}` reference used by local variables, global variables, and environment parameters. You do not need to type it by hand — the value picker inserts the correct expression — but recognizing it helps when you read a step's test data.

### Function Categories

ContextQA includes 167 random functions grouped into 18 categories. The value picker lists every function with a short description; the following table summarizes the categories and gives representative examples.

| Category              | Functions | Examples                                                                                    |
| --------------------- | --------- | ------------------------------------------------------------------------------------------- |
| Date & Time           | 11        | `cqaRandom.date(7)`, `cqaRandom.pastDate(2)`, `cqaRandom.weekday()`                         |
| Numbers               | 9         | `cqaRandom.int(1, 10)`, `cqaRandom.float(0, 1, 4)`, `cqaRandom.percentage()`                |
| Geo                   | 3         | `cqaRandom.latitude()`, `cqaRandom.longitude()`                                             |
| Identifiers & Strings | 8         | `cqaRandom.uuid()`, `cqaRandom.alphanum(10)`, `cqaRandom.numeric(6)`                        |
| Arrays                | 3         | `cqaRandom.sample(['a', 'b', 'c'])`, `cqaRandom.shuffle([1, 2, 3, 4])`                      |
| Lorem / Text          | 8         | `cqaRandom.word()`, `cqaRandom.sentence(10)`, `cqaRandom.slug()`                            |
| Person                | 12        | `cqaRandom.firstName()`, `cqaRandom.lastName()`, `cqaRandom.jobTitle()`                     |
| Internet / Contact    | 20        | `cqaRandom.email('test.com', 'Jane', 'Smith')`, `cqaRandom.phone('US')`, `cqaRandom.ipv4()` |
| Location / Address    | 12        | `cqaRandom.city()`, `cqaRandom.state()`, `cqaRandom.zipCode('#####')`                       |
| Company / Commerce    | 13        | `cqaRandom.companyName()`, `cqaRandom.productName()`, `cqaRandom.department()`              |
| Finance               | 17        | `cqaRandom.creditCardNumber('visa')`, `cqaRandom.iban(true)`, `cqaRandom.currencyCode()`    |
| Vehicle               | 8         | `cqaRandom.manufacturer()`, `cqaRandom.vin()`, `cqaRandom.vehicleColor()`                   |
| Database / System     | 4         | `cqaRandom.databaseType()`, `cqaRandom.column()`                                            |
| File System           | 10        | `cqaRandom.fileName(2)`, `cqaRandom.mimeType()`, `cqaRandom.semver()`                       |
| Music & Food          | 8         | `cqaRandom.songName()`, `cqaRandom.dish()`, `cqaRandom.fruit()`                             |
| Animals               | 11        | `cqaRandom.dog()`, `cqaRandom.cat()`, `cqaRandom.animalType()`                              |
| Color                 | 7         | `cqaRandom.colorName()`, `cqaRandom.rgb()`, `cqaRandom.hsl()`                               |
| Images                | 2         | `cqaRandom.image(800, 600)`, `cqaRandom.avatar()`                                           |

### Functions with Parameters

Many functions accept parameters that shape the generated value. The value picker prompts you for each parameter when you select the function.

| Function                                       | Parameters                    | Generates                                  |
| ---------------------------------------------- | ----------------------------- | ------------------------------------------ |
| `cqaRandom.date(7)`                            | Offset days, format           | A formatted date offset from today         |
| `cqaRandom.int(1, 10)`                         | Min, max                      | An integer within the range                |
| `cqaRandom.alphanum(10)`                       | Length                        | An alphanumeric string of the given length |
| `cqaRandom.email('test.com', 'Jane', 'Smith')` | Domain, first name, last name | An email address on the given domain       |
| `cqaRandom.phone('US')`                        | Country                       | A phone number in the country's format     |
| `cqaRandom.creditCardNumber('visa')`           | Provider                      | A test credit card number for the provider |
| `cqaRandom.image(800, 600)`                    | Width, height                 | An image URL at the given dimensions       |

Functions without parameters — such as `cqaRandom.uuid()` or `cqaRandom.firstName()` — generate a value with no further input.

### Example: Randomized Signup Test

Random functions make it possible to run a signup test repeatedly without duplicate-data conflicts:

```
Step 1 (AI Agent): Type {cqaRandom.firstName()} in the First Name field
Step 2 (AI Agent): Type {cqaRandom.lastName()} in the Last Name field
Step 3 (AI Agent): Type {cqaRandom.email('example.com', 'Test', 'User')} in the Email field
Step 4 (AI Agent): Type {cqaRandom.phone('US')} in the Phone Number field
Step 5 (AI Agent): Click the Create Account button
```

Each run submits a unique name, email, and phone number, so the account-creation form never rejects the input as already registered.

### Random Functions vs Variables

| Use                                                   | Choose                                   |
| ----------------------------------------------------- | ---------------------------------------- |
| A value that must be unique or fresh on every run     | Random function                          |
| A value that must stay the same across steps or runs  | Variable (local, global, or environment) |
| A value reused by many test cases                     | Global variable                          |
| A value that differs by environment                   | Environment parameter                    |
| A value captured from an earlier step or API response | Local variable                           |

***

## Tips & Best Practices

* **Use password-type parameters for all credentials and tokens.** Even in test environments, API keys, passwords, and session tokens should be stored as password-type parameters. This prevents them from appearing in screenshots, logs, or exported test data.
* **Build one data profile per functional scenario.** Do not mix different types of test data in one profile (e.g., valid credentials and invalid credentials in the same profile). Keep each profile focused on one scenario type so the profile name is self-describing and test results are easy to interpret.
* **Use API calls for test data setup, not manual data entry.** If a test requires a specific record to exist (a user, an order, a product), create it via a REST API Call step at the start of the test rather than relying on pre-existing test data that might be deleted or modified between runs.
* **Clean up after yourself with API teardown steps.** Add REST API Call steps at the end of tests to delete records created during the test. This keeps the test environment clean across repeated runs and prevents tests from interfering with each other.
* **Document global variable purpose in the description field.** As the workspace grows, it becomes hard to remember what each global variable is for. Add a clear description when creating global variables, including which test cases use them and when they should be updated.

## Troubleshooting

**A variable name fails to save and shows a validation error** Variable names must start with a letter or underscore, contain only letters, numbers, and underscores (no spaces or special characters), and must not match a reserved keyword such as `os`, `path`, or `get`. See [Variable naming rules](#variable-naming-rules) for the full rules and what each error message means.

**A variable token is visible in the result instead of its value** This means the selected value was not resolved at runtime. Check that:

1. The variable name in the step exactly matches the variable name as defined (case-sensitive).
2. For local variables set by a previous step, confirm the previous step passed — failed steps do not produce variable output.
3. For environment variables, confirm the environment was selected on the test case or executing plan.
4. Reinsert the value from the step editor's picker instead of typing the token manually.

**A REST API response variable is accessible in one step but not in a later step** Variable scope is sequential — a variable set by step N is available to all steps after step N. If you are referencing a variable before the step that sets it, reorder the steps.

**The data profile is attached but the intended steps do not repeat** Confirm that data-driven execution is enabled on the test case, the start/end row range is correct, and the actions are inside a **Test data profile** loop. Also confirm that every input step is mapped to the intended column with the Parameter picker.

**Password-type environment parameters are appearing in test step descriptions** Password values are masked in the UI and execution evidence, but literal text in a step description is not rewritten. Always insert the approved Password or Vault value through the picker—never hard-code credentials in step text.

## Related Pages

* [Tutorial: Data-Driven Testing](/web-testing/data-driven-testing-tutorial.md) — step-by-step tutorial for parameterized tests
* [Test Steps Editor](/web-testing/test-steps-editor.md)
* [Configuring Environments](/execution/environments.md)
* [Creating Test Cases](/web-testing/creating-test-cases.md)
* [Core Concepts](/getting-started/core-concepts.md)
* [Running Tests](/execution/running-tests.md)

{% hint style="info" %}
**70% less manual test maintenance with AI self-healing.** [**Book a Demo →**](https://contextqa.com/book-a-demo/) — See ContextQA create and maintain tests for your web application.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://learning.contextqa.com/web-testing/test-data-management.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
