# Welcome to DoesQA

Learn how to build and run website tests in DoesQA without writing code.

DoesQA helps you test a website without writing code. You build a **Flow** from **Test Steps**, run them in a real browser, and get results you can act on.

New Flows open in the **Scenario editor** as plain-language sentences. When you want more power or flexibility, open the same Flow in the **Flow Builder**. The two tabs share the same steps.

{% hint style="info" %}
**New here?** Start with [Create and run your first Flow](/getting-started/create-and-run-your-first-flow). You will open a page, touch a control, check a result, and read the Run in a few minutes.
{% endhint %}

## Getting Started

Start here if you are new to DoesQA.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>DoesQA concepts</strong></td><td>How Flows, Test Steps, Test Cases, and Runs fit together.</td><td><a href="/getting-started/doesqa-concepts">DoesQA concepts</a></td></tr><tr><td><strong>Create and run your first Flow</strong></td><td>Open a page, touch a control, check a result, and see the Run.</td><td><a href="/getting-started/create-and-run-your-first-flow">Create and run your first Flow</a></td></tr><tr><td><strong>Understand your results</strong></td><td>Read what passed, what failed, and what to do next.</td><td><a href="/getting-started/understand-your-results">Understand your results</a></td></tr><tr><td><strong>Terminology</strong></td><td>The words DoesQA uses for Flows, steps, Elements, Values, and Runs.</td><td><a href="/getting-started/terminology">Terminology</a></td></tr></tbody></table>

## Platform

The surfaces you build and run with, including optional DoesQA AI, Security, and Integrations.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Flow Builder</strong></td><td>Build branches, Step Groups, and full coverage on a visual canvas.</td><td><a href="/platform/flow-builder">Flow Builder</a></td></tr><tr><td><strong>Scenario editor</strong></td><td>Write a single-path Flow as plain-language sentences.</td><td><a href="/platform/scenario-editor">Scenario editor</a></td></tr><tr><td><strong>DoesQA AI</strong></td><td>Optional summaries, Suggestions, Assistant, and agent authoring.</td><td><a href="/platform/doesqa-ai">DoesQA AI</a></td></tr><tr><td><strong>Security</strong></td><td>UK hosting, encryption at rest, and answers for IT and security reviews.</td><td><a href="/platform/security">Security</a></td></tr><tr><td><strong>Integrations</strong></td><td>Start Runs from CI and automation tools, and send results to chat.</td><td><a href="/platform/integrations">Integrations</a></td></tr></tbody></table>

## Guides

Journey walkthroughs for jobs you will do often once the first Flow is working.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Email testing in DoesQA</strong></td><td>Built-in inboxes, per-Test-Case mail, and common email journeys.</td><td><a href="/guides/email-testing-in-doesqa">Email testing in DoesQA</a></td></tr><tr><td><strong>Test data in DoesQA</strong></td><td>Built-in Values, Value Store, API setup, and mock servers.</td><td><a href="/guides/test-data-in-doesqa">Test data in DoesQA</a></td></tr><tr><td><strong>Migrate to DoesQA</strong></td><td>Free team-led coverage migration, typically in a couple of days.</td><td><a href="/guides/migrate-to-doesqa">Migrate to DoesQA</a></td></tr><tr><td><strong>Interacting with emails</strong></td><td>Wait for messages, open them, and continue the journey.</td><td><a href="/guides/interacting-with-emails">Interacting with emails</a></td></tr><tr><td><strong>Test a forgotten-password flow</strong></td><td>Reset a password with email, then sign in with the new Value.</td><td><a href="/guides/test-a-forgotten-password-flow">Test a forgotten-password flow</a></td></tr><tr><td><strong>Test registration and email verification</strong></td><td>Sign up, verify the email, and confirm the account.</td><td><a href="/guides/test-registration-and-email-verification">Test registration and email verification</a></td></tr><tr><td><strong>Test MFA login</strong></td><td>Generate a time-based code and finish sign-in.</td><td><a href="/guides/test-mfa-login">Test MFA login</a></td></tr><tr><td><strong>Reuse a login session</strong></td><td>Log in once and pass the session into other Flows.</td><td><a href="/guides/reuse-a-login-session">Reuse a login session</a></td></tr><tr><td><strong>Test checkout and payments</strong></td><td>Automate cart, address, and payment through to confirmation.</td><td><a href="/guides/test-checkout-and-payments">Test checkout and payments</a></td></tr><tr><td><strong>Test APIs in a Flow</strong></td><td>Call an API, store the response, and assert JSON in the same Flow.</td><td><a href="/guides/test-apis-in-a-flow">Test APIs in a Flow</a></td></tr><tr><td><strong>Test file uploads and downloads</strong></td><td>Generate files, upload them, and reuse the last download.</td><td><a href="/guides/test-file-uploads-and-downloads">Test file uploads and downloads</a></td></tr><tr><td><strong>Test tabs, windows, and frames</strong></td><td>Move focus across tabs, popups, and iframes.</td><td><a href="/guides/test-tabs-windows-and-frames">Test tabs, windows, and frames</a></td></tr></tbody></table>

## Better Coverage

Skills and patterns that strengthen every journey.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Reuse steps with Step Groups</strong></td><td>Share a login or setup path across many Flows.</td><td><a href="/better-coverage/reuse-steps-with-step-groups">Reuse steps with Step Groups</a></td></tr><tr><td><strong>Choose durable selectors</strong></td><td>Build Elements that stay stable as the UI changes.</td><td><a href="/better-coverage/choose-durable-selectors">Choose durable selectors</a></td></tr><tr><td><strong>Share data with Values</strong></td><td>Create Values, insert them with $, and overwrite per Run.</td><td><a href="/better-coverage/share-data-with-values">Share data with Values</a></td></tr><tr><td><strong>Choose Flow Branch shapes</strong></td><td>Join starts, split later, or layer combinations in one Flow.</td><td><a href="/better-coverage/choose-flow-branch-shapes">Choose Flow Branch shapes</a></td></tr><tr><td><strong>Build smoke and regression coverage</strong></td><td>Tag Flow Branches and run packs with Run Recipes.</td><td><a href="/better-coverage/build-smoke-and-regression-coverage">Build smoke and regression coverage</a></td></tr><tr><td><strong>Run across environments</strong></td><td>Point the same Flows at staging or production with Values.</td><td><a href="/better-coverage/run-across-environments">Run across environments</a></td></tr><tr><td><strong>Add visual checks</strong></td><td>Catch visual and layout drift with Vision Test Steps.</td><td><a href="/better-coverage/add-visual-checks">Add visual checks</a></td></tr><tr><td><strong>Add accessibility checks</strong></td><td>Scan pages and assert roles and labels in the journey.</td><td><a href="/better-coverage/add-accessibility-checks">Add accessibility checks</a></td></tr><tr><td><strong>Test page performance</strong></td><td>Assert a Lighthouse performance score in the Flow.</td><td><a href="/better-coverage/test-page-performance">Test page performance</a></td></tr><tr><td><strong>Test SEO</strong></td><td>Assert a Lighthouse SEO score on key pages.</td><td><a href="/better-coverage/test-seo">Test SEO</a></td></tr><tr><td><strong>Check links</strong></td><td>Find broken or failing links on a page or Element.</td><td><a href="/better-coverage/check-links">Check links</a></td></tr></tbody></table>

## Look things up

Use these sections when you need a precise answer.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Test Steps</strong></td><td>Every step type, from Open and Touch to Checks, Mail, and Vision.</td><td><a href="/test-steps/starter">Starter</a></td></tr><tr><td><strong>Test Step Options</strong></td><td>Element states, Failed Status, timeouts, and comparison types.</td><td><a href="/test-step-options/element-states">Element states</a></td></tr><tr><td><strong>Elements</strong></td><td>Reusable page objects and the selectors that find them.</td><td><a href="/elements/creating-elements">Creating Elements</a></td></tr><tr><td><strong>Values</strong></td><td>Shared data for usernames, URLs, and other test inputs.</td><td><a href="/values/value-store">Value Store</a></td></tr><tr><td><strong>Runs</strong></td><td>Start Test Packs, read Run History, and open Run detail.</td><td><a href="/runs/runs">Runs</a></td></tr><tr><td><strong>Configuration</strong></td><td>Schedules, Run Recipes, CI/CD, concurrency, and notifications.</td><td><a href="/configuration/schedules">Schedules</a></td></tr></tbody></table>


# DoesQA concepts

Learn how Flows, Test Steps, Test Cases, and Runs fit together in DoesQA.

DoesQA helps you test a website without writing code. You describe what a user does, DoesQA runs those steps in a real browser, and you get clear results you can trust.

## How a test is built

| Piece         | What it is                                                                                                |
| ------------- | --------------------------------------------------------------------------------------------------------- |
| **Flow**      | Your test design. One Flow can cover several routes through your application.                             |
| **Test Step** | One building block in a Flow. Each step does a single job: open a page, touch a button, or check a value. |
| **Element**   | A reusable page object, such as a login button or email field.                                            |
| **Value**     | A piece of data used in a test, such as a username or URL.                                                |

You can build a Flow in two places that share the same Test Steps:

* The [**Scenario editor**](/platform/scenario-editor) turns each Test Step into a plain-language sentence. New Flows open here.
* The [**Flow Builder**](/platform/flow-builder) shows the same Test Steps on a visual canvas. Use it when you want more power or flexibility.

AI is optional and layered. See [DoesQA AI](/platform/doesqa-ai).

## How a test runs

| Piece           | What it is                                                                                      |
| --------------- | ----------------------------------------------------------------------------------------------- |
| **Flow Branch** | A join or split in a Flow that creates more than one possible path.                             |
| **Test Case**   | One specific path through a Flow. Each unique path becomes its own Test Case.                   |
| **Run**         | A group of Test Cases started together.                                                         |
| **Test Runner** | A machine that runs one Test Case. More runners means more Test Cases can run at the same time. |

```mermaid
flowchart TD
  open["Open URL"] --> touch["Touch Element"]
  touch --> check["Check element displayed"]
```

A simple Flow like this produces one Test Case. Add a Flow Branch later, and DoesQA creates a Test Case for each path while shared steps stay shared. See [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes) when you are ready to design those paths.

## Related

* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [Understand your results](/getting-started/understand-your-results)
* [DoesQA AI](/platform/doesqa-ai)
* [Flow Builder](/platform/flow-builder)
* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [Scenario editor](/platform/scenario-editor)
* [Terminology](/getting-started/terminology)


# Create and run your first Flow

Build your first Flow with Open, Touch, and Check, starting in the Scenario editor and finishing in the Flow Builder.

In a few minutes you can open a page, touch a control, check that something is displayed, and see the result. You start in the **Scenario editor**, because that is where DoesQA opens a new Flow. You then switch to the **Flow** tab to finish the same test in the **Flow Builder**, where creating Elements is clearest.

```mermaid
flowchart TD
  open["Open URL"] --> touch["Touch Element<br/>Automatic Description"]
  touch --> check["Check element displayed<br/>Manual CSS"]
```

## What you need

* A website URL you can reach from the internet, such as your staging site or a public page
* One clickable control on that page
* Something that should be displayed after the click, so you can check it

## Build the Flow

{% stepper %}
{% step %}

## Open a Flow

Select **Flows** in the left navigation.

If your account already has **My First Flow**, open it. Otherwise select **Create flow**, enter a **Title** and **Url**, then save.

DoesQA opens the Flow in the **Scenario** tab. That is the Scenario editor.
{% endstep %}

{% step %}

## Set the Open step

The first line is always [**Open**](/test-steps/starter/open). It should look like:

`Open https://your-site.example on Chrome`

If the URL is wrong, click the URL part of the sentence and update it. Changes save as you work.

<figure><img src="https://app.does.qa/screenshots/node/starter_open.png" alt="Open Test Step"><figcaption><p>Open</p></figcaption></figure>
{% endstep %}

{% step %}

## Open the Flow Builder

Select the **Flow** tab.

The Scenario editor and the Flow Builder share the same Test Steps. The canvas shows the Open step you already set, so you are not starting again. The next steps use the canvas so you can create Elements as you add them.
{% endstep %}

{% step %}

## Add Touch and create an Element from a Description

Drag [**Touch**](/test-steps/action/touch) from the step library onto the canvas, below **Open**, so the steps connect.

<figure><img src="https://app.does.qa/screenshots/node/action_touch_single.png" alt="Touch Test Step"><figcaption><p>Touch</p></figcaption></figure>

1. Open the Touch step.
2. Keep **Type** as **Element**.
3. Choose **+** next to **Element** to create one.
4. Set a clear **Title**, such as `Primary CTA`.
5. Set **Element configuration** to **Automatic**.
6. In **Description**, describe the control in plain language, for example `Yellow login button in the top right`.
7. Save the Element, then save the step.

DoesQA generates a Selector from your Description. You can switch the Element to **Manual** later if you want to edit the Selector yourself.
{% endstep %}

{% step %}

## Add Check displayed with a CSS Element

Drag [**Check displayed**](/test-steps/check/check-displayed) below **Touch**.

<figure><img src="https://app.does.qa/screenshots/node/check_is_displayed.png" alt="Check displayed Test Step"><figcaption><p>Check element displayed</p></figcaption></figure>

1. Open the Check displayed step.
2. Choose **+** next to **Element**.
3. Set a **Title**, such as `Welcome heading`.
4. Set **Element configuration** to **Manual**.
5. Set **Type** to **CSS**.
6. Enter a Selector for the Element that should appear after the touch, for example `#welcome` or `[data-testid="welcome"]`.
7. Save the Element, then save the step.
   {% endstep %}

{% step %}

## Run the Flow

Select **Run Flow** in the toolbar.

DoesQA saves the Flow, starts a Run, and opens the **Results** tab. Follow [Understand your results](/getting-started/understand-your-results) to read what came back.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Use **Preview Tests** from the toolbar menu while you are still editing. It is a fast way to check the Flow before a full Run.
{% endhint %}

## The finished Flow

![Open, Touch, and Check element displayed connected on the Flow Builder canvas](https://static.does.qa/assets/ui/light/first-flow-intro.png)

From here you can rearrange steps on the canvas, add [Flow Branches](/better-coverage/choose-flow-branch-shapes), and grow the Flow into fuller coverage.

## Related

* [DoesQA concepts](/getting-started/doesqa-concepts)
* [Flow Builder](/platform/flow-builder)
* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [Scenario editor](/platform/scenario-editor)
* [Understand your results](/getting-started/understand-your-results)
* [Open](/test-steps/starter/open)
* [Touch](/test-steps/action/touch)
* [Check displayed](/test-steps/check/check-displayed)
* [Choose durable selectors](/better-coverage/choose-durable-selectors)
* [Creating Elements](/elements/creating-elements)
* [Terminology](/getting-started/terminology)


# Understand your results

Read a first Run, open a Test Case, and decide what to change next.

After you select **Run**, DoesQA opens the Flow's **Results** tab. This is where you watch the Run and decide what to change next.

![Flow Results tab with passed and failed Runs](https://static.does.qa/assets/ui/light/working-flow-results.png)

For account-wide history, Test Packs, Recipes, and reruns, see [Runs](/runs/runs).

## What you see while it runs

Each Test Case moves through **Queued**, **Creating Runner**, and **Running**. The Run shows:

* the Run ID
* when it was created
* each Test Case card
* the browser, such as **Chrome (Desktop)**
* progress through the Test Steps

Open a Test Case to see the step timeline. Each step can show its status, a screenshot, when it started, and how long it took. When the Run finishes, you can also review the video.

![Passed Test Case with a step timeline](https://static.does.qa/assets/ui/light/working-test-passed.png)

## How to read a failure

Start with the first Test Step that did not pass.

1. Open that Test Case.
2. Find the failing Test Step in the timeline.
3. View the screenshot and the step response.
4. Go back to the **Scenario** or **Flow** tab and adjust that step.

When [DoesQA AI](/platform/doesqa-ai) is on, a failed Test Case can also show an **AI Summary** with a short title and next steps. Open **Assistant** from the summary to keep working on that failure in chat.

![Failed Test Case with AI Summary](https://static.does.qa/assets/ui/light/working-test-failed.png)

A failed **Check address** usually means the Open URL or the expected value needs updating. A failed **Check title** usually means the page did not load the way you expected.

## What to do next

Once one Flow is passing:

* Add more Checks or Actions for the journey you care about.
* Switch to the **Flow** tab when you want [Flow Branches](/better-coverage/choose-flow-branch-shapes) or a visual layout.
* Start a **Test Pack** from the Flows list when you want to run several Flows together.
* Set up a **Schedule** when the same Run should happen regularly.

## Related

* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [DoesQA concepts](/getting-started/doesqa-concepts)
* [DoesQA AI](/platform/doesqa-ai)
* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [Terminology](/getting-started/terminology)
* [Schedules](/configuration/schedules)


# Terminology

Learn the words DoesQA uses to describe flows, tests, and runs.

DoesQA has a small set of words that describe how tests are built and run.

For how these pieces fit together, see [DoesQA concepts](/getting-started/doesqa-concepts).

## Designing tests

| Term             | What it means                                                                                                                                                                  |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Flow**         | Your test design on an infinite canvas. One flow can cover several routes through your application.                                                                            |
| **Flow Builder** | The visual editor where you place and connect test steps to build a flow. See [Flow Builder](/platform/flow-builder).                                                          |
| **Test Step**    | One building block in a flow. Each step does a single job: open a page, touch a button, or check a value.                                                                      |
| **Step Group**   | A reusable set of test steps you can drop into any flow. Change the group once, and every flow that uses it updates.                                                           |
| **Flow Branch**  | A join or split in a flow that creates more than one possible path. See [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes).                               |
| **Element**      | A reusable page object, such as a login button or email field. Test steps use elements to find things on the page.                                                             |
| **Selector**     | The rule inside an element that finds it on the page, using CSS, XPath, visible text, or a test ID. The element and the selector are related, but they are not the same thing. |
| **Value**        | A piece of data used in a test, such as a username, URL, or order number. Think of it as a variable with a clear name.                                                         |
| **Value Store**  | Where your account keeps shared values, so many tests can reuse the same data.                                                                                                 |

## Running tests

| Term            | What it means                                                                                           |
| --------------- | ------------------------------------------------------------------------------------------------------- |
| **Test Case**   | One specific path through a flow. A flow with branches produces a test case for each path.              |
| **Run**         | A group of test cases started together.                                                                 |
| **Test Runner** | A machine that runs one test case. More runners means more tests can run at the same time.              |
| **Test Pack**   | A run you start yourself, choosing which flows and test cases to include.                               |
| **Run Recipe**  | A saved set of filters and value overwrites you can reuse. Find these under **Settings → Run Recipes**. |
| **Schedule**    | A recurring run. It can target all flows, flows with certain tags, or a run recipe.                     |

## Other ways to work

| Term                 | What it means                                                                                                                                                                      |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Scenario editor**  | A plain-language editor for supported single-path flows. Useful when you prefer writing steps as sentences. New Flows open here. See [Scenario editor](/platform/scenario-editor). |
| **Assistant**        | DoesQA's in-app AI for questions about your Flows, Runs, and coverage. See [DoesQA AI](/platform/doesqa-ai).                                                                       |
| **Simulated Device** | An Open option that runs the Test Case with a named device preset, such as an iPhone. It sets viewport, user agent, and touch behaviour for that device.                           |

## Related

* [DoesQA concepts](/getting-started/doesqa-concepts)
* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [Understand your results](/getting-started/understand-your-results)
* [DoesQA AI](/platform/doesqa-ai)
* [Flow Builder](/platform/flow-builder)
* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [Scenario editor](/platform/scenario-editor)
* [Reuse steps with Step Groups](/better-coverage/reuse-steps-with-step-groups)
* [Value Store](/values/value-store)
* [Run Recipes](/configuration/run-recipes)


# Flow Builder

Build and rearrange Flows on a visual canvas with the Flow Builder.

The **Flow Builder** is the visual editor for a [Flow](/getting-started/terminology). You place [Test Steps](/getting-started/terminology) on a canvas, connect them, and grow the design into full coverage.

After Getting Started, journey guides use the Flow Builder as the default way to build. The [Scenario editor](/platform/scenario-editor) shares the same Test Steps. Switching tabs shows the same Flow another way.

![Flow Builder canvas for a DoesQA Website journey](https://static.does.qa/assets/ui/light/working-flow-canvas.png)

## What you can do here

* Drag Test Steps from the step library onto the canvas, and filter the library when you search
* Connect steps so each [Test Case](/getting-started/terminology) path is clear
* Open a step to set Elements, Values, and other fields
* Add [Flow Branches](/getting-started/terminology) when one Flow should cover more than one path
* Gate a branch with [Condition](/test-steps/runner/condition) when a path should run only for a device, language, timezone, or Value
* Drop in [Step Groups](/better-coverage/reuse-steps-with-step-groups) for shared login or setup
* Select several steps, align them, duplicate them, or turn them into a Step Group
* Run or preview the Flow from the toolbar, then open **Results**

## Open the Flow Builder

{% stepper %}
{% step %}

## Open a Flow

Open a Flow from **Flows**, or create one.
{% endstep %}

{% step %}

## Select the Flow tab

Select the **Flow** tab.

New Flows open in the Scenario editor first. Use the **Flow** tab when you want the canvas, branches, or a clearer view of a growing Flow. See [Create and run your first Flow](/getting-started/create-and-run-your-first-flow).
{% endstep %}
{% endstepper %}

## Build on the canvas

1. Find a Test Step in the step library. Type in the search box to filter by name or family.
2. Drag the step onto the canvas below the step it should follow, so the connector joins them.
3. Open the step and set its fields.
4. Keep adding steps until the path matches the journey you want to prove.

{% hint style="info" %}
**Pro tip:** Hold **Shift** and drag to select several Test Steps at once. Then duplicate them, align them, or create a [Step Group](/better-coverage/reuse-steps-with-step-groups) from the selection.
{% endhint %}

## Useful canvas actions

| Action       | How                                                                                     |
| ------------ | --------------------------------------------------------------------------------------- |
| Undo / redo  | Toolbar controls, or **Cmd/Ctrl+Z** and **Cmd/Ctrl+Shift+Z**                            |
| Copy / paste | **Cmd/Ctrl+C** and **Cmd/Ctrl+V**                                                       |
| Duplicate    | **Cmd/Ctrl+D**, or **Duplicate Step(s)** on the context menu                            |
| Align        | Select two or more steps, then align left, right, top, or bottom from the context menu  |
| Delete       | **Backspace** or **Delete**. Neighbouring steps reconnect when a middle step is removed |
| Save         | Changes autosave. **Cmd/Ctrl+S** also saves                                             |

## Branches and Conditions

A Flow with more than one path uses Flow Branches. Design the shared steps once, then split into paths for smoke vs regression, mobile vs desktop, or staging vs production tags.

See [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes) for joined starts, a later split, join then split, and layered combinations.

Use [Condition](/test-steps/runner/condition) early on a branch when that path should run only for a matching Runner, device, language, timezone, or Run Value. Use [Tag Test](/test-steps/utility/tag-test) when a schedule, Recipe, or CI/CD call should pick the path by tag.

For tagging smoke and regression paths, see [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage).

## Run from the Flow Builder

Use **Run Flow** on the toolbar to start a Run while you edit. Overflow controls also let you **Run Tests** or **Preview Tests** when you want a narrower check. Open **Results** from the same place when the Run finishes. See [Understand your results](/getting-started/understand-your-results).

## When to prefer the Flow Builder

| Prefer the Flow Builder when                              | Prefer the Scenario editor when                           |
| --------------------------------------------------------- | --------------------------------------------------------- |
| You need Flow Branches or a multi-path design             | You want a single path as plain-language sentences        |
| You are rearranging or extending a larger Flow            | You are starting a simple Flow for the first time         |
| You want the step library and canvas layout               | You are happiest editing step text in a list              |
| You need Step Groups, align, or multi-select canvas tools | You are editing Values and Element names in sentence form |

## Related

* [Scenario editor](/platform/scenario-editor)
* [DoesQA AI](/platform/doesqa-ai)
* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [DoesQA concepts](/getting-started/doesqa-concepts)
* [Reuse steps with Step Groups](/better-coverage/reuse-steps-with-step-groups)
* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage)
* [Condition](/test-steps/runner/condition)
* [Terminology](/getting-started/terminology)


# Scenario editor

Build a single-path Flow as plain-language sentences in the Scenario editor.

The **Scenario editor** turns each [Test Step](/getting-started/terminology) into a plain-language sentence. New [Flows](/getting-started/terminology) open here so you can get a first success without learning the canvas first.

The Scenario editor and the [Flow Builder](/platform/flow-builder) share the same Test Steps. Switching tabs does not start a new Flow.

![Scenario editor with a short first Flow](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-45e4fe71cd58f70edf3dee349543538ebe5cbe4a%2Fscenario-editor-intro.png?alt=media)

## What you can do here

* Read and edit steps as sentences, such as Open, Touch, and Check
* Change Values and Element names by clicking parts of the sentence
* Add the next step with **What's the next test step?**
* Reorder steps in the list
* Run or preview the Flow from the toolbar
* Switch to the **Flow** tab to see the same steps in the Flow Builder

## Open the Scenario editor

{% stepper %}
{% step %}

## Open or create a Flow

Open a Flow from **Flows**, or create a Flow.
{% endstep %}

{% step %}

## Stay on the Scenario tab

Stay on the **Scenario** tab. That is the default for a new Flow.

The Scenario tab stays available while the Flow is a single path. When you add Flow Branches in the Flow Builder, continue editing on the **Flow** tab. See [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes).
{% endstep %}
{% endstepper %}

## Edit a sentence

1. Click the part of the sentence you want to change, such as a URL, Element name, or Value.
2. Choose or type the new value.
3. Changes save as you work.

Use **What's the next test step?** at the end of the list to add the next step. The picker suggests steps that fit the sentence you are building.

## Run from the Scenario editor

Use the toolbar to run or preview the Flow while you edit. Results open the same way as from the Flow Builder. See [Understand your results](/getting-started/understand-your-results).

## When to prefer the Scenario editor

| Prefer the Scenario editor when                  | Prefer the Flow Builder when                       |
| ------------------------------------------------ | -------------------------------------------------- |
| You want a single path written as sentences      | You need Flow Branches or a multi-path design      |
| You are new to DoesQA                            | You are rearranging a larger Flow on the canvas    |
| You are editing step wording quickly             | You want the full step library laid out visually   |
| You are changing Values and Element names inline | You need Step Groups, align, or multi-select tools |

For a first walkthrough that starts here and continues in the Flow Builder, see [Create and run your first Flow](/getting-started/create-and-run-your-first-flow).

{% hint style="info" %}
**Pro tip:** Build the happy path as sentences first. Switch to the Flow Builder when you want branches, Step Groups, or a clearer layout of a longer Flow.
{% endhint %}

## Related

* [Flow Builder](/platform/flow-builder)
* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [DoesQA AI](/platform/doesqa-ai)
* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [DoesQA concepts](/getting-started/doesqa-concepts)
* [Terminology](/getting-started/terminology)


# DoesQA AI

DoesQA AI speeds up testing across the product, stays in our UK datacentre, and stays optional.

## About DoesQA AI

DoesQA AI provides optional efficiency benefits across the product: faster failure triage, quicker Element setup, clearer next steps for coverage, in-product answers, and agent-driven authoring when you want it.

DoesQA was built to be easy **without** AI, so every Flow, Element, and Run still works with no AI features at all. DoesQA AI defaults to **On** for new accounts so those benefits are ready from day one. You can turn it off any time. See [Control](#control).

### Your data stays with DoesQA

* Models and data used for DoesQA AI stay **inside DoesQA**.
* Nothing leaves our ecosystem for DoesQA AI.
* DoesQA AI is hosted in our **UK datacentre**.

### How learning works

Learning is optional. When enabled, DoesQA AI gets sharper for you and for everyone on your account, so summaries, Suggestions, and the Assistant stay closer to how your team already tests.

When something useful applies more widely, other customers only benefit from **generic** learning, not from your private account detail.

| Learning         | Who it helps                                                        |
| ---------------- | ------------------------------------------------------------------- |
| **You**          | Notes and context that stay with how you work                       |
| **Your account** | Shared across everyone on that account                              |
| **Generic**      | Broad improvements that do not expose your account’s private detail |

You can opt out of Learning under [Control](#control).

## Layers

Each layer unlocks a different kind of speed. Use one, several, or all of them.

### Test and Run summaries

When a Test Case or Run fails, DoesQA can show an **AI Summary** on the result: a short title and a clear write-up of what went wrong and what to try next. Open **Assistant** from the summary to continue in chat with that failure already in context. Triage moves from scanning every step response and screenshot to reading the summary, then acting, so failure review stays short as suites grow.

![Failed Test Case with AI Summary and Assistant](https://static.does.qa/assets/ui/light/working-test-failed.png)

### Automatic element selection

When you create an [Element](/elements/creating-elements), set **Element configuration** to **Automatic** and write a plain-language **Description**, such as `Yellow login button in the top right`. DoesQA generates the Selector from that Description. You can switch to **Manual** later to edit the Selector yourself.

Describe the control the way a tester sees it, and DoesQA turns that into a Selector. First Flows land sooner, and when the page shifts you can refresh from the Description instead of rebuilding the Selector from scratch.

Your first Flow already uses this path. See [Create and run your first Flow](/getting-started/create-and-run-your-first-flow) and [Creating Elements](/elements/creating-elements).

### Suggestions

On the home page, DoesQA can show **Suggestions**: short ideas for what to improve next, such as coverage to add or Selectors to harden. Open **Assistant** from a suggestion, or use **Expand coverage**, to turn the idea into a guided chat. Suggestions pull practical work from how your account already tests, so your next move is already on the table and expanding coverage takes less planning time.

### Assistant

The [**Assistant**](/getting-started/terminology) is DoesQA’s in-app AI for questions about your Flows, Runs, and coverage. Open it from the main menu, or from a Flow, Test Case, or Run so the chat already knows what you are looking at. From home you can start topics such as expand coverage, get help, or ask anything.

The Assistant works with your account’s real context: the Flow or Run you opened from, how your team already tests, and the failures in front of you. Ask it to explain a failure, harden Selectors, or expand coverage, and it answers inside DoesQA with that context already loaded.

### CLI and MCP

The DoesQA **CLI** and **MCP** connect an AI coding agent to your account. The agent can create and update Flows and Elements, start Runs, read Test and Run summaries, and work from account memory, while you review each change in the DoesQA app. Authoring and triage happen beside the code you already ship: agents draft and adjust tests, and you stay in control with a review link for every change.

## How does DoesQA avoid AI hallucinations or unreliable results?

DoesQA was built so testing works **without** AI. Pass and fail for almost every Test Step come from real browsers, stored Selectors, and tried and tested Steps, not from generative guessing. DoesQA AI makes triage, setup, and authoring faster. It does not replace that execution model.

DoesQA AI is mature, stable, and trustworthy. It is tried and tested across **millions of Runs** on a wide range of platforms and systems. You can turn Automation Intelligence **off** any time and keep using Flows, Manual Elements, Runs, and Results as usual. See [Control](#control).

### Runs stay deterministic

When a Test Case runs, DoesQA executes the Steps you configured. Automatic waiting, fixed Selectors, and shared Step behaviour are the same platform story as [Maintenance and reliability](/choosing-a-test-automation-approach/maintenance-and-reliability). Generative AI is not what decides those outcomes.

The one intentional exception is [**AI Vision**](/test-steps/vision/ai-vision). That Step uses AI to judge a written visual expectation, so it can affect pass or fail when you add it. Use it when a plain-language visual Check is the right tool, and keep other Checks on ordinary Steps when you want a fully non-AI path.

### AI that speeds you up

| Layer                                                   | How trust works                                                                                                                                                                                                                                                                                                                                                                |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Test and Run summaries](#test-and-run-summaries)       | Summaries are correct and can be trusted for triage. They are built to explain the failure in front of you so you can act faster.                                                                                                                                                                                                                                              |
| [Automatic Elements](#automatic-element-selection)      | DoesQA generates a Selector from your Description as a starting point. The stored Selector is what Runs use. You stay in the loop when Selectors change. See [Creating Elements](/elements/creating-elements) and [Maintenance and reliability](/choosing-a-test-automation-approach/maintenance-and-reliability#how-resilient-are-doesqa-tests-when-the-application-changes). |
| [Suggestions](#suggestions) and [Assistant](#assistant) | Optional helpers grounded in your account and the Flow or Run you opened from. They speed planning and questions; they do not rewrite Run pass/fail.                                                                                                                                                                                                                           |
| [CLI and MCP](#cli-and-mcp)                             | Agents can draft and update work in your account. A human stays in the loop: you review changes in the DoesQA app.                                                                                                                                                                                                                                                             |

So: AI is optional acceleration on top of a deterministic product. Turn it off when you want. Keep AI Vision as an explicit Step when a visual expectation belongs in the Flow.

## Control

DoesQA AI is powerful but fully optional. All of DoesQA keeps working with DoesQA AI off: Flows, Manual Elements, Runs, and results stay fully usable.

**Automation Intelligence** is the account switch for summaries, Suggestions, and the Assistant. It defaults to **On** for new accounts.

To change it:

1. Open **Settings**.
2. Find **Automation Intelligence**.
3. Set **Enable Automation Intelligence** to **On** or **Off**.

**Automation Intelligence Learning** is also optional. Leave it on so Intelligence learns from your account and stays closer to how you test.

## Related

* [Flow Builder](/platform/flow-builder)
* [Scenario editor](/platform/scenario-editor)
* [Security](/platform/security)
* [Creating Elements](/elements/creating-elements)
* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [Understand your results](/getting-started/understand-your-results)
* [AI Vision](/test-steps/vision/ai-vision)
* [Add visual checks](/better-coverage/add-visual-checks)
* [Terminology](/getting-started/terminology)


# Security

How DoesQA protects customer data: what is stored, credentials, UK AWS hosting, encryption at rest, Cyber Essentials, access control, and retention.

DoesQA protects the data you use for testing with UK cloud hosting, encryption at rest, Cyber Essentials controls, and least-privilege access.

For the longer security programme questionnaire, see [Security on does.qa](https://does.qa/security).

## Certifications

| Programme             | Status             |
| --------------------- | ------------------ |
| Cyber Essentials      | Held               |
| Cyber Essentials Plus | In progress        |
| SOC 2                 | In progress        |
| ISO 27001             | Scheduled for 2027 |

Leadership reviews and approves security controls and documentation each year.

## Where data lives

DoesQA is fully cloud-based. Infrastructure runs on **AWS** in the UK (**eu-west-2**).

DoesQA LTD is registered in England and Wales:

Fulford House,\
Newbold Terrace,\
Leamington Spa,\
Warwickshire,\
United Kingdom,\
CV32 4EA

The team is remote and UK-based. Samuel Smith (Co-Founder) is the responsible person for IT systems.

## Does DoesQA store our data?

Yes. DoesQA stores only what you provide and connect for testing.

That includes the assets you build and the evidence your Runs produce:

| Stored            | Examples                                                                                                                 |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Test design       | Flows, Elements, Values, Step Groups                                                                                     |
| Run evidence      | Results, screenshots, and video                                                                                          |
| Account operation | Settings and user access needed to run the product                                                                       |
| Secrets you save  | [Private Values](/values/value-store#private-values) and [MFA](/configuration/mfa) secrets (hidden in the UI after save) |

You choose the URLs, credentials, and application data that enter DoesQA through your Flows and settings. Infrastructure location is under [Where data lives](#where-data-lives).

## How DoesQA handles credentials and secrets?

Put secrets in product controls built for them:

| Control                                              | Behaviour                                                                                                                                                                                                 |
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Private Values](/values/value-store#private-values) | Create under **Assets → Values** with **Private value** on. After save, the content stays hidden in the UI and still applies when Tests run. You cannot view or edit the secret content again after save. |
| [MFA](/configuration/mfa)                            | Save MFA secrets under **Settings → MFA**. Use them with [Set MFA](/test-steps/action/set-mfa). The secret is not viewable again after save.                                                              |

Avoid using production passwords or tokens. Account access on DoesQA uses unique users, approval for new access, and least-privilege staff access on the DoesQA side. Your team still decides which credentials enter the product. See [Shared responsibility](#shared-responsibility).

## How data is protected

Customer data is **encrypted at rest**.

Customer-facing services use authenticated access over HTTPS. Only essential inbound connections are allowed. Broader inbound rules need a documented business case and board-level approval.

## Who can access customer data

Staff access follows least privilege: people get only what they need for their role. Founders have access to everything when required for the business.

Accounts are unique and not shared. New access needs approval. Access is removed promptly when someone leaves. Admin accounts are separate, use MFA, and are not used for day-to-day email or browsing.

## How long we keep data

**Run evidence** (results, screenshots, video, and related Run artifacts) is retained for **60 days**.

**Account assets** such as Flows, Elements, Values, Step Groups, and settings stay for as long as the account is active.

DoesQA follows **UK GDPR** rights, including the right to removal. When removal is requested, DoesQA removes the personal data in scope so that everything covered by the request is taken out of the product.

## How Runs stay isolated

Each Test Case runs on a hosted Test Runner. Use product controls when your environments need extra boundaries:

| Control                                            | Where                                               |
| -------------------------------------------------- | --------------------------------------------------- |
| Allow runner and support IPs through your firewall | [Whitelisting IPs](/configuration/whitelisting-ips) |
| Block hostnames Runs should not reach              | [Block Hostnames](/configuration/block-hostnames)   |
| Keep optional AI inside the UK DoesQA footprint    | [DoesQA AI](/platform/doesqa-ai)                    |

## Shared responsibility

DoesQA secures the platform, infrastructure, and the controls described above.

Your team decides what test data enters DoesQA, who has access on your account, which environments you allowlist, and how Values and credentials are managed in Flows.

## Related

* [Security and trust](/choosing-a-test-automation-approach/security-and-trust)
* [Security on does.qa](https://does.qa/security)
* [Information Security Policy](https://does.qa/legal/information-security-policy)
* [Whitelisting IPs](/configuration/whitelisting-ips)
* [Block Hostnames](/configuration/block-hostnames)
* [DoesQA AI](/platform/doesqa-ai)


# Integrations

Connect DoesQA to CI, chat tools, agents, and automation platforms.

Integrations are how DoesQA talks to the rest of your stack. Use this section when you want to start Runs from another system, send results somewhere your team already watches, or work from an AI coding agent.

For the settings screens inside DoesQA, see [CI / CD](/configuration/ci-cd) and [Notifications](/configuration/notifications). Those pages document the options in the product. The pages here are organised by the tool or job you care about.

## Start Runs from elsewhere

Something outside DoesQA starts a Run: a pipeline, a button in another app, or an automation platform.

| Integration                                                   | What it is for                                               |
| ------------------------------------------------------------- | ------------------------------------------------------------ |
| [Universal Webhook](/platform/integrations/universal-webhook) | The HTTP hook any system can call to start a Run             |
| [GitHub](/platform/integrations/github)                       | Start a Run from GitHub Actions with PR Checks reporting     |
| [GitLab](/platform/integrations/gitlab)                       | Start a Run from GitLab CI with the DoesQA catalog component |
| [Bitbucket](/platform/integrations/bitbucket)                 | Start a Run from Bitbucket Pipelines                         |
| [Azure DevOps](/platform/integrations/azure-devops)           | Start a Run from Azure Pipelines                             |
| [Make](/platform/integrations/make)                           | Start a Run from a Make scenario                             |
| [Zapier](/platform/integrations/zapier)                       | Start a Run from a Zap                                       |
| [n8n](/platform/integrations/n8n)                             | Start a Run from an n8n workflow                             |

## Send results elsewhere

DoesQA posts when a Run finishes, so the team sees pass or fail where they already work.

| Integration                                               | What it is for                                                  |
| --------------------------------------------------------- | --------------------------------------------------------------- |
| [Slack](/platform/integrations/slack)                     | Post Run results into Slack, and send messages from a Flow      |
| [Microsoft Teams](/platform/integrations/microsoft-teams) | Post Run results into a Teams channel                           |
| Email                                                     | [Notifications → Email](/configuration/notifications/email)     |
| Outbound webhook                                          | [Notifications → Webhook](/configuration/notifications/webhook) |

## Work from an agent

| Integration                      | What it is for                                                          |
| -------------------------------- | ----------------------------------------------------------------------- |
| [DoesQA AI](/platform/doesqa-ai) | Optional AI across the product, including CLI and MCP for coding agents |

## Related settings in DoesQA

* [CI / CD](/configuration/ci-cd): keys and options under **Settings → CI/CD**
* [Notifications](/configuration/notifications): rules under **Settings → Notifications**
* [Integration Test Steps](/test-steps/integration): call APIs, SFTP, or Slack from inside a Flow


# Universal Webhook

Start a DoesQA Run from any system with an HTTP webhook.

The Universal Webhook is how almost any external system can start a DoesQA Run. Your pipeline, automation platform, or custom script sends an HTTP request. DoesQA selects Flows, starts the Run, and keeps going.

With this you can create an integration with any other service, or a script you own. One URL and key unlock Runs from GitHub, Bitbucket, Azure DevOps, Make, Zapier, n8n, and anything else that can send HTTP.

{% hint style="info" %}
This is the **inbound** hook that starts Runs. It is not the outbound notification webhook that posts results when a Run finishes. For outbound results, see [Notifications](/configuration/notifications).
{% endhint %}

## Why use it

* One URL and key work across CI tools and no-code platforms.
* You choose Flows with IDs, a [Run Recipe](/configuration/run-recipes), or tags.
* You can preview the selection with GET before you wire a pipeline.
* You can return immediately, or wait until the Run finishes.

Create and manage keys under **Settings → CI/CD**. Field-by-field detail for that screen lives on [CI / CD](/configuration/ci-cd).

## Before you call the hook

{% stepper %}
{% step %}

## Create a CI/CD key

In DoesQA, open **Settings → CI/CD**, create an **Active** key, and store the secret in your other system. DoesQA shows the secret once. See [CI / CD](/configuration/ci-cd).
{% endstep %}

{% step %}

## Copy your Account ID

Open **Settings** (Account Settings) and copy the **Account ID**. It is part of the hook URL.
{% endstep %}

{% step %}

## Decide how to select Flows

Pick one selection style per request. If more than one is present, DoesQA uses the first match in this order:

1. Flow IDs (`ids`)
2. A [Run Recipe](/configuration/run-recipes) (`recipe`)
3. Tags (`withAll` / `withoutAny`)
4. All Flows in the account

**Include tags** (`withAll`) mean the Flow must have every listed tag. **Exclude tags** (`withoutAny`) remove a Flow if it has any listed tag.
{% endstep %}
{% endstepper %}

## Preview which Flows would run

Send a **GET**. Nothing starts.

```
GET https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=smoke
```

Check the response count against the Flows you expect. Fix tags, recipe, or IDs before you add the call to CI or an automation.

## Start a Run

Send a **POST**:

```
POST https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=smoke&label=Build%201234
```

By default the hook accepts the request and returns quickly while the Run continues. To wait until the Run finishes before your job continues, add `mode=wait`.

### Request options

| Parameter     | Required | What it does                                                                                  |
| ------------- | -------- | --------------------------------------------------------------------------------------------- |
| `key`         | Yes      | Your CI/CD webhook key. You can also send it as the `x-api-key` header.                       |
| `label`       | No       | Label shown on the Run, such as a build number.                                               |
| `ids`         | No       | Comma-separated Flow IDs.                                                                     |
| `recipe`      | No       | Run Recipe ID.                                                                                |
| `withAll`     | No       | Comma-separated include tags. The Flow must have all of them.                                 |
| `withoutAny`  | No       | Comma-separated exclude tags. The Flow must have none of them.                                |
| `values`      | No       | URL-encoded JSON object of Value overrides.                                                   |
| `testsTagged` | No       | Only Test Cases that have this tag.                                                           |
| `mode`        | No       | `fast` (default) returns as soon as the Run is accepted. `wait` holds until the Run finishes. |

Authenticate with the query `key`, or with header `x-api-key: YOUR_KEY`.

Optional **Value** overrides replace matching items from the [Value Store](/values/value-store) for that Run.

### Example with Value overrides

```
POST https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=staging&label=PR-88&values=%7B%22BASE_URL%22%3A%22https%3A%2F%2Fstaging.example.com%22%7D
```

Decoded, `values` is:

```json
{
  "BASE_URL": "https://staging.example.com"
}
```

### Minimal curl example

```bash
curl -X POST \
  "https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=smoke&label=manual-check"
```

## Ready-made examples

| Tool         | Page                                                |
| ------------ | --------------------------------------------------- |
| GitHub       | [GitHub](/platform/integrations/github)             |
| GitLab       | [GitLab](/platform/integrations/gitlab)             |
| Bitbucket    | [Bitbucket](/platform/integrations/bitbucket)       |
| Azure DevOps | [Azure DevOps](/platform/integrations/azure-devops) |
| Make         | [Make](/platform/integrations/make)                 |
| Zapier       | [Zapier](/platform/integrations/zapier)             |
| n8n          | [n8n](/platform/integrations/n8n)                   |

Prefer a ready-made flow when one exists. Otherwise paste the [curl example](#minimal-curl-example) into the service or script you already use, and you are connected.

## After the Run starts

To post results to Slack, Teams, email, or an outbound webhook, create a notification rule and include the **CI/CD Webhook** run type. See [Notifications](/configuration/notifications).

## Related

* [Integrations](/platform/integrations)
* [CI / CD](/configuration/ci-cd)
* [Notifications](/configuration/notifications)
* [Run Recipes](/configuration/run-recipes)
* [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage)


# GitHub

Start DoesQA Runs from GitHub Actions with the DoesQA GitHub Action.

Connect GitHub Actions to DoesQA so every pull request and deploy can start a Run, wait for the result, and show the outcome in Checks. The DoesQA GitHub Action wraps the [Universal Webhook](/platform/integrations/universal-webhook) with PR-friendly reporting built in.

{% embed url="<https://github.com/Does-QA/action>" %}

## Why use it

* Start DoesQA from the same workflow that builds and deploys your app.
* See pass or fail on the PR Checks tab, with a link straight into the DoesQA report.
* Get a Job Summary on the Actions run page without extra setup.
* Reuse the same key, tags, and Recipes you already use with the Universal Webhook.

## Before you start

1. Create an Active CI/CD webhook key under **Settings → CI/CD**. See [CI / CD](/configuration/ci-cd).
2. Copy your **Account ID** from Account Settings.
3. Store them as GitHub Actions secrets, for example `DOESQA_KEY` and `DOESQA_ACCOUNT_ID`.

## Add the Action

Create a workflow (for example `.github/workflows/doesqa.yml`):

```yaml
name: DoesQA Test Run

on:
  pull_request:

permissions:
  checks: write

jobs:
  doesqa-test-run:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger DoesQA Test Run
        uses: Does-QA/action@v1
        with:
          key: ${{ secrets.DOESQA_KEY }}
          accountId: ${{ secrets.DOESQA_ACCOUNT_ID }}
          label: 'PR #${{ github.event.pull_request.number }}'
          withAll: 'smoke,staging'
          withoutAny: 'wip'
          values: '{"BASE_URL": "https://staging.example.com"}'
          wait: 'true'
          timeout: '1800'
          recipe: '4sJz2'
          testsTagged: 'priority'
```

{% hint style="info" %}
**Pro tip:** Keep `permissions: checks: write` so the Action can post a Check Run on the commit. That is what shows pass or fail in the PR Checks tab.
{% endhint %}

## Inputs

| Input          | Required | What it does                                                                                                           |
| -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `key`          | Yes      | CI/CD webhook key                                                                                                      |
| `accountId`    | Yes      | Account ID from Account Settings                                                                                       |
| `label`        | No       | Label shown on the Run                                                                                                 |
| `withAll`      | No       | Include tags. The Flow must have all of them.                                                                          |
| `withoutAny`   | No       | Exclude tags. The Flow must have none of them. Defaults to `wip`.                                                      |
| `values`       | No       | JSON object of Value overrides                                                                                         |
| `wait`         | No       | Wait for the Run to finish before the job continues. Defaults to `true`.                                               |
| `timeout`      | No       | How long to wait, in seconds, when waiting is enabled. Defaults to `1200`.                                             |
| `concurrency`  | No       | Cap how many Test Cases from this Run run at once                                                                      |
| `recipe`       | No       | Run Recipe ID                                                                                                          |
| `testsTagged`  | No       | Only Test Cases with this tag                                                                                          |
| `github-token` | No       | Token used to create the Check Run. Defaults to the workflow token. Set to an empty string to skip Check Run creation. |

## Outputs

| Output       | What it is                                                                      |
| ------------ | ------------------------------------------------------------------------------- |
| `status`     | Final status of the Run, such as `passed`, `failed`, `terminated`, or `timeout` |
| `report-url` | Link to the DoesQA report for this Run                                          |

## What you see in GitHub

### Job Summary

Every run adds a markdown summary on the GitHub Actions page: status, counts, duration, and a link to the full DoesQA report.

### Check Run

With `checks: write`, the Action creates a Check Run on the commit. It shows as in progress while DoesQA runs, then updates with the final result and a Details link into DoesQA.

## Related

* [Integrations](/platform/integrations)
* [Universal Webhook](/platform/integrations/universal-webhook)
* [GitLab](/platform/integrations/gitlab)
* [CI / CD](/configuration/ci-cd)
* [Run Recipes](/configuration/run-recipes)
* [Max Concurrency](/configuration/max-concurrency)
* [Notifications](/configuration/notifications)


# GitLab

Start DoesQA Runs from GitLab CI with the DoesQA catalog component.

Connect GitLab CI to DoesQA so every pipeline can start a Run, wait for the result, and keep shipping with confidence. The DoesQA catalog component wraps the [Universal Webhook](/platform/integrations/universal-webhook) in a drop-in GitLab include.

{% embed url="<https://gitlab.com/explore/catalog/doesqa/doesqa-gitlab-cicd>" %}

## Why use it

* Start DoesQA from the same `.gitlab-ci.yml` that builds and deploys your app.
* Wait for the Run to finish before the job continues, when you want the pipeline to reflect the result.
* Reuse the same key, tags, Recipes, and Value overrides you already use with the Universal Webhook.

## Before you start

1. Create an Active CI/CD webhook key under **Settings → CI/CD**. See [CI / CD](/configuration/ci-cd).
2. Copy your **Account ID** from Account Settings.
3. Store `DOESQA_KEY` and `DOESQA_ACCOUNT_ID` as GitLab CI/CD variables.

## Add the component

Include the component in `.gitlab-ci.yml`. Check [DoesQA GitLab releases](https://gitlab.com/doesqa/doesqa-gitlab-cicd/-/releases) for the latest production tag, and use the same value for the component version and `DOESQA_COMPONENT_VERSION`.

```yaml
include:
  - component: gitlab.com/doesqa/doesqa-gitlab-cicd/doesqa-run@2.0.0
    inputs:
      DOESQA_COMPONENT_VERSION: "2.0.0"
      DOESQA_KEY: "$DOESQA_KEY"
      DOESQA_ACCOUNT_ID: "$DOESQA_ACCOUNT_ID"
      DOESQA_LABEL: "Nightly Test Run"
      DOESQA_WITHALL: "smoke,staging"
      DOESQA_WITHOUTANY: "wip"
      DOESQA_VALUES: '{"BASE_URL": "https://staging.example.com"}'
      DOESQA_WAIT: "true"
      DOESQA_TIMEOUT: "1800"
      DOESQA_RECIPE: "4sJz2"
      DOESQA_TESTSTAGGED: "priority"
```

{% hint style="info" %}
**Pro tip:** Keep `DOESQA_COMPONENT_VERSION` identical to the `@` tag on the include line so GitLab and the component stay on the same release.
{% endhint %}

## Inputs

| Input                      | Required | What it does                                          |
| -------------------------- | -------- | ----------------------------------------------------- |
| `DOESQA_KEY`               | Yes      | CI/CD webhook key                                     |
| `DOESQA_ACCOUNT_ID`        | Yes      | Account ID from Account Settings                      |
| `DOESQA_COMPONENT_VERSION` | Yes      | Must match the component tag you include              |
| `DOESQA_LABEL`             | No       | Label shown on the Run                                |
| `DOESQA_WITHALL`           | No       | Include tags. The Flow must have all of them.         |
| `DOESQA_WITHOUTANY`        | No       | Exclude tags. The Flow must have none of them.        |
| `DOESQA_VALUES`            | No       | JSON object of Value overrides                        |
| `DOESQA_WAIT`              | No       | Wait for the Run to finish before the job continues   |
| `DOESQA_TIMEOUT`           | No       | How long to wait, in seconds, when waiting is enabled |
| `DOESQA_RECIPE`            | No       | Run Recipe ID                                         |
| `DOESQA_TESTSTAGGED`       | No       | Only Test Cases with this tag                         |
| `DOESQA_CONCURRENCY`       | No       | Cap how many Test Cases from this Run run at once     |

## Related

* [Integrations](/platform/integrations)
* [Universal Webhook](/platform/integrations/universal-webhook)
* [CI / CD](/configuration/ci-cd)
* [Run Recipes](/configuration/run-recipes)
* [Max Concurrency](/configuration/max-concurrency)
* [Notifications](/configuration/notifications)
* [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage)


# Bitbucket

Start DoesQA Runs from Bitbucket Pipelines with the Universal Webhook.

Connect Bitbucket Pipelines to DoesQA so every push and pull request can start a Run as part of the same pipeline that builds your app. Bitbucket calls the [Universal Webhook](/platform/integrations/universal-webhook) with a short `curl` step.

## Why use it

* Keep end-to-end coverage next to the code that changed.
* Reuse the same CI/CD key, tags, and Recipes you already use elsewhere.
* Preview Flow selection with GET before you wire the pipeline for real.

## Before you start

1. Create an Active CI/CD webhook key under **Settings → CI/CD**. See [CI / CD](/configuration/ci-cd).
2. Copy your **Account ID** from Account Settings.
3. Add repository variables in Bitbucket, for example `DOESQA_KEY` and `DOESQA_ACCOUNT_ID`. Mark the key as secured.

## Add a pipeline step

In `bitbucket-pipelines.yml`:

```yaml
pipelines:
  default:
    - step:
        name: DoesQA Run
        script:
          - |
            curl -sS -X POST \
              "https://app.does.qa/api/hook/${DOESQA_ACCOUNT_ID}?key=${DOESQA_KEY}&withAll=smoke&label=bitbucket-${BITBUCKET_BUILD_NUMBER}&mode=wait"
```

{% hint style="info" %}
**Pro tip:** Start with `mode=wait` so the pipeline step stays green or red with the Run. Use the default fast mode when you only need to fire the Run and move on.
{% endhint %}

### Select Flows and Values

Append the same query options as the [Universal Webhook](/platform/integrations/universal-webhook): `withAll`, `withoutAny`, `recipe`, `ids`, `testsTagged`, and URL-encoded `values`.

Example with a staging URL Value:

```yaml
script:
  - |
    VALUES=$(python3 -c 'import urllib.parse; print(urllib.parse.quote("{\"BASE_URL\":\"https://staging.example.com\"}"))')
    curl -sS -X POST \
      "https://app.does.qa/api/hook/${DOESQA_ACCOUNT_ID}?key=${DOESQA_KEY}&withAll=staging&label=bitbucket-${BITBUCKET_BUILD_NUMBER}&values=${VALUES}&mode=wait"
```

## Related

* [Integrations](/platform/integrations)
* [Universal Webhook](/platform/integrations/universal-webhook)
* [GitHub](/platform/integrations/github)
* [GitLab](/platform/integrations/gitlab)
* [Azure DevOps](/platform/integrations/azure-devops)
* [CI / CD](/configuration/ci-cd)
* [Notifications](/configuration/notifications)


# Azure DevOps

Start DoesQA Runs from Azure Pipelines with the Universal Webhook.

Connect Azure Pipelines to DoesQA so builds and releases can start a Run without leaving your Azure DevOps project. A pipeline task calls the [Universal Webhook](/platform/integrations/universal-webhook) over HTTP.

## Why use it

* Run DoesQA from the same pipeline that compiles, deploys, or gates a release.
* Share one CI/CD key across Azure, GitHub, and GitLab.
* Choose Flows with tags or a [Run Recipe](/configuration/run-recipes), then wait for the result when the gate matters.

## Before you start

1. Create an Active CI/CD webhook key under **Settings → CI/CD**. See [CI / CD](/configuration/ci-cd).
2. Copy your **Account ID** from Account Settings.
3. Store them as secret pipeline variables, for example `DOESQA_KEY` and `DOESQA_ACCOUNT_ID`.

## Add a pipeline task

In `azure-pipelines.yml`:

```yaml
trigger:
  - main

pool:
  vmImage: ubuntu-latest

steps:
  - bash: |
      curl -sS -X POST \
        "https://app.does.qa/api/hook/$(DOESQA_ACCOUNT_ID)?key=$(DOESQA_KEY)&withAll=smoke&label=azure-$(Build.BuildId)&mode=wait"
    displayName: DoesQA Run
    env:
      DOESQA_KEY: $(DOESQA_KEY)
      DOESQA_ACCOUNT_ID: $(DOESQA_ACCOUNT_ID)
```

{% hint style="info" %}
**Pro tip:** Map `DOESQA_KEY` as a secret variable in the pipeline or variable group. Azure masks it in logs when the name is marked secret.
{% endhint %}

### Select Flows and Values

Use the same query options as the [Universal Webhook](/platform/integrations/universal-webhook). Example with a Recipe and Value override:

```yaml
steps:
  - bash: |
      VALUES=$(python3 -c 'import urllib.parse; print(urllib.parse.quote("{\"BASE_URL\":\"https://staging.example.com\"}"))')
      curl -sS -X POST \
        "https://app.does.qa/api/hook/$(DOESQA_ACCOUNT_ID)?key=$(DOESQA_KEY)&recipe=4sJz2&label=azure-$(Build.BuildId)&values=${VALUES}&mode=wait"
    displayName: DoesQA Run
    env:
      DOESQA_KEY: $(DOESQA_KEY)
      DOESQA_ACCOUNT_ID: $(DOESQA_ACCOUNT_ID)
```

## Related

* [Integrations](/platform/integrations)
* [Universal Webhook](/platform/integrations/universal-webhook)
* [GitHub](/platform/integrations/github)
* [GitLab](/platform/integrations/gitlab)
* [Bitbucket](/platform/integrations/bitbucket)
* [CI / CD](/configuration/ci-cd)
* [Notifications](/configuration/notifications)


# Make

Start DoesQA Runs from Make with the Universal Webhook.

Connect Make to DoesQA so scenarios, schedules, and other apps can start a Run when your business process says it is time. Make’s HTTP module calls the [Universal Webhook](/platform/integrations/universal-webhook).

## Why use it

* Trigger DoesQA from the same automation that deploys, opens a ticket, or updates a sheet.
* Keep one CI/CD key and Flow selection model across Make and your pipelines.
* Hand results to Slack or Teams with [Notifications](/configuration/notifications) while Make continues the scenario.

## Before you start

1. Create an Active CI/CD webhook key under **Settings → CI/CD**. See [CI / CD](/configuration/ci-cd).
2. Copy your **Account ID** from Account Settings.
3. Store the key in Make as a connection secret or scenario variable.

## Add an HTTP module

1. Add an **HTTP → Make a request** module to your scenario.
2. Set **Method** to `POST`.
3. Set **URL** to:

```
https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=smoke&label=make-scenario
```

4. Leave the body empty unless you prefer to send `key` as header `x-api-key` instead of a query parameter.
5. Run the module once to confirm DoesQA accepts the Run.

{% hint style="info" %}
**Pro tip:** Keep the default fast mode in Make so the scenario does not sit waiting on a long Run. Use [Notifications](/configuration/notifications) when the team needs the result in Slack or Teams.
{% endhint %}

### Select Flows and Values

Add the same query options as the [Universal Webhook](/platform/integrations/universal-webhook). URL-encode JSON `values` if you pass Value overrides, for example:

```
...&values=%7B%22BASE_URL%22%3A%22https%3A%2F%2Fstaging.example.com%22%7D
```

## Related

* [Integrations](/platform/integrations)
* [Universal Webhook](/platform/integrations/universal-webhook)
* [Zapier](/platform/integrations/zapier)
* [n8n](/platform/integrations/n8n)
* [CI / CD](/configuration/ci-cd)
* [Notifications](/configuration/notifications)


# Zapier

Start DoesQA Runs from Zapier with the Universal Webhook.

Connect Zapier to DoesQA so Zaps can start a Run from the apps your team already uses. A Webhooks by Zapier step calls the [Universal Webhook](/platform/integrations/universal-webhook).

## Why use it

* Start DoesQA from CRM updates, form submits, deploy events, or any Zapier trigger.
* Keep the same key, tags, and Recipes you use in CI.
* Let DoesQA [Notifications](/configuration/notifications) deliver results while the Zap moves on.

## Before you start

1. Create an Active CI/CD webhook key under **Settings → CI/CD**. See [CI / CD](/configuration/ci-cd).
2. Copy your **Account ID** from Account Settings.
3. Keep the key in a Zapier storage field or vault your team already trusts.

## Add a Webhooks step

1. Add **Webhooks by Zapier → Custom Request** (or **POST**).
2. Set **Method** to `POST`.
3. Set **URL** to:

```
https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=smoke&label=zapier
```

4. Leave the body blank for a simple start, or send `x-api-key` as a header with your CI/CD key and omit `key` from the query string.
5. Test the step and open DoesQA to confirm the Run appeared.

{% hint style="info" %}
**Pro tip:** Map dynamic Zap fields into `label` or URL-encoded `values` so each Run shows which Zap and record started it.
{% endhint %}

### Select Flows and Values

Use the same query options as the [Universal Webhook](/platform/integrations/universal-webhook). Example with a Recipe:

```
https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&recipe=4sJz2&label=zapier-release
```

## Related

* [Integrations](/platform/integrations)
* [Universal Webhook](/platform/integrations/universal-webhook)
* [Make](/platform/integrations/make)
* [n8n](/platform/integrations/n8n)
* [CI / CD](/configuration/ci-cd)
* [Notifications](/configuration/notifications)


# n8n

Start DoesQA Runs from n8n with the Universal Webhook.

Connect n8n to DoesQA so workflows can start a Run whenever your automation graph says go. An HTTP Request node calls the [Universal Webhook](/platform/integrations/universal-webhook).

## Why use it

* Trigger DoesQA from self-hosted or cloud n8n workflows next to the rest of your ops graph.
* Share one CI/CD key with GitHub, GitLab, and no-code tools.
* Continue the workflow after DoesQA accepts the Run, and use [Notifications](/configuration/notifications) for the human-facing result.

## Before you start

1. Create an Active CI/CD webhook key under **Settings → CI/CD**. See [CI / CD](/configuration/ci-cd).
2. Copy your **Account ID** from Account Settings.
3. Store the key in n8n credentials or an environment variable.

## Add an HTTP Request node

1. Add an **HTTP Request** node.
2. Set **Method** to `POST`.
3. Set **URL** to:

```
https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=smoke&label=n8n
```

4. Optionally move the key to header `x-api-key` and drop it from the query string.
5. Execute the node once and confirm the Run in DoesQA.

{% hint style="info" %}
**Pro tip:** Pass expression values into `label` or `values` so each Run carries the workflow name and the record that triggered it.
{% endhint %}

### Select Flows and Values

Use the same query options as the [Universal Webhook](/platform/integrations/universal-webhook). Example waiting for the Run inside the workflow:

```
https://app.does.qa/api/hook/ACCOUNT_ID?key=YOUR_KEY&withAll=smoke&label=n8n&mode=wait
```

Raise the node timeout when you use `mode=wait`, or keep the default fast mode and let Notifications carry the result.

## Related

* [Integrations](/platform/integrations)
* [Universal Webhook](/platform/integrations/universal-webhook)
* [Make](/platform/integrations/make)
* [Zapier](/platform/integrations/zapier)
* [CI / CD](/configuration/ci-cd)
* [Notifications](/configuration/notifications)


# Slack

Connect Slack to DoesQA for Run alerts and in-Flow messages.

Bring DoesQA into the channels your team already watches. Connect Slack once, then post Run results automatically and send messages from inside a Flow when the journey needs it.

## Why use it

* See pass and fail where the team already works, without opening DoesQA for every Run.
* Alert on CI, schedules, or Runs started in the app, using the same notification rules.
* Send a Slack message mid-Flow with the [Slack Send](/test-steps/integration/slack-send) Test Step when a journey should notify a channel.

## Connect Slack

{% stepper %}
{% step %}

## Open Integrations

In DoesQA, go to **Settings → Integrations**.
{% endstep %}

{% step %}

## Connect Slack

Choose Slack and complete the connection. Confirm the integration shows as **Active**.
{% endstep %}
{% endstepper %}

You only need to connect Slack once per account. Notification rules and Slack Send both use that connection.

## Send Run results to a channel

Create a Slack notification under **Settings → Notifications**.

{% stepper %}
{% step %}

## Add a Slack rule

Select **Add**, then choose **Slack**.
{% endstep %}

{% step %}

## Configure the rule

1. Enter a **Title**.
2. Choose the **Run Types** that should post to Slack.
3. Select the **Slack Channel**.
4. If the rule uses **CI/CD Webhook** with **Select Keys**, confirm the Key list.
5. Save the rule.
   {% endstep %}
   {% endstepper %}

{% hint style="info" %}
**Pro tip:** New Slack rules often start with **CI/CD Webhook** and **Schedule** selected. Add **User** when you also want alerts from Runs started in DoesQA.
{% endhint %}

Field-by-field detail for notification rules lives on [Notifications → Slack](/configuration/notifications/slack) and [Notifications](/configuration/notifications).

## Send a message from a Flow

Add [Slack Send](/test-steps/integration/slack-send) to a Flow when a journey should post to a channel during the test, not only when the Run finishes.

## Related

* [Integrations](/platform/integrations)
* [Microsoft Teams](/platform/integrations/microsoft-teams)
* [Notifications](/configuration/notifications)
* [Notifications → Slack](/configuration/notifications/slack)
* [Slack Send](/test-steps/integration/slack-send)
* [GitHub](/platform/integrations/github)
* [Universal Webhook](/platform/integrations/universal-webhook)


# Microsoft Teams

Connect Microsoft Teams to DoesQA for Run alerts in channel.

Bring DoesQA results into Microsoft Teams so engineering and QA see pass and fail next to the rest of their work. Connect Teams once, then post Run results into the channel you choose.

## Why use it

* Keep release confidence visible in Teams without chasing reports in another tab.
* Alert on CI, schedules, or Runs started in the app with the same notification model as Slack.
* Limit CI alerts to specific [CI / CD](/configuration/ci-cd) keys when one team owns one pipeline.

## Connect Microsoft Teams

{% stepper %}
{% step %}

## Open Integrations

In DoesQA, go to **Settings → Integrations**.
{% endstep %}

{% step %}

## Connect Teams

Choose Microsoft Teams and complete the connection. Confirm the integration shows as **Active**.
{% endstep %}
{% endstepper %}

You only need to connect Teams once per account. Notification rules use that connection.

## Send Run results to a channel

Create a Teams notification under **Settings → Notifications**.

{% stepper %}
{% step %}

## Add a Teams rule

Select **Add**, then choose **Teams**.
{% endstep %}

{% step %}

## Configure the rule

1. Enter a **Title**.
2. Choose the **Run Types** that should post to Teams.
3. Select the **Teams Integration**.
4. If the rule uses **CI/CD Webhook** with **Select Keys**, confirm the Key list.
5. Save the rule.
   {% endstep %}
   {% endstepper %}

Field-by-field detail for notification rules lives on [Notifications → Microsoft Teams](/configuration/notifications/teams) and [Notifications](/configuration/notifications).

## Related

* [Integrations](/platform/integrations)
* [Slack](/platform/integrations/slack)
* [Notifications](/configuration/notifications)
* [Notifications → Microsoft Teams](/configuration/notifications/teams)
* [GitHub](/platform/integrations/github)
* [Universal Webhook](/platform/integrations/universal-webhook)


# Email testing in DoesQA

Built-in test inboxes, per-Test-Case mail isolation, and Mail Test Steps for registration, password reset, and passwordless login journeys.

Many products send email during signup, login, checkout, or account changes. DoesQA includes test inboxes and [Mail Test Steps](/test-steps/mail) so those journeys stay inside one Flow. You do not wire a separate mail service into your tests.

## Two inbox types

| Inbox         | Value                                                                                         | Use it when                                                                  |
| ------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| **Test Case** | [`$testEmail`](/values/built-in-values) or [`$testEmailShort`](/values/built-in-values)       | The message belongs to one Test Case, such as registration or password reset |
| **Account**   | [`$accountEmail`](/values/built-in-values) or [`$accountEmailShort`](/values/built-in-values) | Several Test Cases should share one mailbox                                  |

Prefer **Test Case** for signup and reset flows. Each Test Case gets its own address for that Run, so parallel Runs do not read each other's mail.

## What you can do in a Flow

A typical email journey looks like this:

```mermaid
flowchart TD
  enter["Set value with $testEmail"] --> trigger["Submit the form"]
  trigger --> wait["Wait for email"]
  wait --> openMail["Open email"]
  openMail --> act["Touch, Check, or Validator steps"]
  act --> close["Close inbox"]
```

* [**Wait for email**](/test-steps/mail/wait-for-email) pauses until the message arrives.
* [**Open email**](/test-steps/mail/open-email) opens the message so the body is the active page.
* Use normal [Action](/test-steps/action), [Check](/test-steps/check), and [Validator](/test-steps/validator) Test Steps on the open message. Click links, assert copy, or run checks such as [accessibility](/better-coverage/add-accessibility-checks) on the email content.
* [**Close inbox**](/test-steps/mail/close-inbox) returns to the application window.

Open **Mail** in the left navigation to inspect the Account inbox or a Test Case inbox while you build a Flow, or after a Run to review what arrived.

## Common journeys

| Journey                          | Guide                                                                                        |
| -------------------------------- | -------------------------------------------------------------------------------------------- |
| Register and verify email        | [Test registration and email verification](/guides/test-registration-and-email-verification) |
| Forgotten password               | [Test a forgotten-password flow](/guides/test-a-forgotten-password-flow)                     |
| Passwordless or magic-link login | [Test passwordless login](/guides/test-passwordless-login)                                   |
| Hands-on Mail steps              | [Interacting with emails](/guides/interacting-with-emails)                                   |

## Compared with coded frameworks

Teams using Playwright, Cypress, or Selenium often add a third-party mail API and custom code to receive messages, parse links, and keep parallel tests isolated. DoesQA ships inboxes, wait and open steps, and hosted runners as one product. See [DoesQA compared](/choosing-a-test-automation-approach/doesqa-compared#journey-capabilities).

## Related

* [Interacting with emails](/guides/interacting-with-emails)
* [Mail Test Steps](/test-steps/mail)
* [Built-in Values](/values/built-in-values)
* [Test registration and email verification](/guides/test-registration-and-email-verification)


# Test data in DoesQA

Value Store, built-in dynamic Values, API steps, and external mock servers for test data and backend setup in DoesQA.

DoesQA brings **Values**, the **Value Store**, and **Integration API steps** into the same Flow as your UI steps. Generate realistic user data, share environment config, and call your APIs to prepare a journey without a separate fixture library.

The most reliable tests use data from a working backend. The browser exercises your application while Integration steps create and verify state on real HTTP endpoints in the same Flow. When a third party must return canned responses, point Integration steps at **Mockoon** or **WireMock** and store the base URL in a Value.

## At a glance

| You need                                | DoesQA approach                                                                       |
| --------------------------------------- | ------------------------------------------------------------------------------------- |
| Names, emails, numbers in forms         | [Built-in Values](/values/built-in-values) (`$testFirstName`, `$randomNumber`, …)     |
| Shared secrets and environment URLs     | [Account Values](/values/creating-values) under **Assets → Values**                   |
| Data that changes during the Test Case  | [Value Store](/values/value-store) at runtime (Store, Set, Calculate, …)              |
| Create or check backend state before UI | [Integration API steps](/test-steps/integration/post) (GET, POST, PUT, PATCH, DELETE) |
| Canned responses from a third party     | Mockoon or WireMock + Values for its base URL                                         |
| Unique inbox per Test Case              | [`$testEmail`](/values/built-in-values) and [Mail Test Steps](/test-steps/mail)       |

Heavy reliance on mocked responses can drift from production behaviour and add flake. DoesQA keeps setup on **Values** and **API steps** against your test environment so UI steps use data that matches what the application actually serves.

## Built-in Values

Built-in Values generate realistic test data when you type `$` in supported fields. The output is similar to what libraries such as **Faker** produce for names, emails, and numbers. Built-ins are native to DoesQA: pick a Value from the list when you build the Flow.

Two rules matter for every Flow:

| Prefix        | Behaviour                                                                          |
| ------------- | ---------------------------------------------------------------------------------- |
| **`test*`**   | Same value for the whole Test Case (for example `$testEmail`, `$testFirstName`)    |
| **`random*`** | New value each time you reference it (for example `$randomNumber`, `$randomEmail`) |

`$randomEmail` addresses use `@mock.does.qa` for form fill. For registration and mail journeys use [`$testEmail`](/values/built-in-values), which opens a real Test Case inbox.

Full lists and examples: [Built-in Values](/values/built-in-values).

## Account Values every test can use

Create shared data under **Assets → Values**:

* **String** for URLs, usernames, tokens
* **Number** and **Boolean** for flags and limits
* **Object** for JSON fixtures (feature flags, default payloads)

Overwrite Values per environment with [Run Recipes](/configuration/run-recipes), **Start Run**, [CI/CD](/configuration/ci-cd), or [DoesQA Run](/test-steps/express/doesqa-run). See [Run across environments](/better-coverage/run-across-environments) and [Value Store](/values/value-store) for which source wins when names match.

## Value Store as in-Flow fixture memory

During a Test Case, Data steps write to the Value Store. Common patterns:

* **Store** element text, attributes, cookies, or storage into a named key
* **Set Value** to build or overwrite data mid-journey
* **Calculate** or **Replace** to transform stored text
* **Check Value Store** or [**Check JSON Value**](/test-steps/check/check-json-value) to assert

Captured data stays available for the rest of that Test Case under the name you chose.

## API steps in the same Flow

[Integration API steps](/test-steps/integration/post) call HTTP endpoints from the hosted runner. Typical pattern:

1. **POST** to create a user or order. Set **Response Storage Name** to `createdUser`.
2. **Open** the app and fill the UI using `$testEmail` or fields from the stored response.
3. **GET** or **Check JSON Value** to confirm backend state.
4. **DELETE** to clean up when the journey finishes.

Walkthrough: [Test APIs in a Flow](/guides/test-apis-in-a-flow). Setup and teardown patterns: [Seed and clean up with API steps](/guides/seed-and-clean-up-with-api-steps).

### Fields inside stored JSON

When a step stores a JSON body, the Value is an **Object**. Later steps can use:

* **Dot notation** in supported fields, for example `$createdUser.id` in a URL or text field
* **`{{storageName}}`** in JSON bodies and headers for a whole stored Value
* [**Check JSON Value**](/test-steps/check/check-json-value) to assert part of the response
* [**Set Value**](/test-steps/data/set-value) to copy a nested field into a simpler name you reuse often

Pass tokens in **Headers** on the Integration step when the backend requires them.

## External mock servers (Mockoon, WireMock)

For dependencies that need canned JSON, run **Mockoon** or **WireMock** and store its base URL in an Account Value such as `$MOCK_API_URL`. Point Integration step URLs at that host, or point your application's API URL Value at the mock for test builds configured that way.

DoesQA calls the mock like any other HTTP API. You maintain stub definitions in the mock tool. Guide: [Use mock servers with DoesQA](/guides/use-mock-servers-with-doesqa).

## Related capabilities

| Feature                                                  | Use for                                             |
| -------------------------------------------------------- | --------------------------------------------------- |
| [Block Hostnames](/configuration/block-hostnames)        | Control which third-party hosts load in the browser |
| [Set Header](/test-steps/runner/set-header)              | Add headers on the browser session                  |
| [Generate File](/test-steps/runner/generate-file)        | Upload files with `{{value}}` in JSON contents      |
| [HAR recording](/test-steps/utility/start-har-recording) | Review browser network traffic after a Run          |

## One Flow for data and UI

**Dynamic data**, **shared config**, and **API setup** live in the same product as the browser steps. Values and Integration steps prepare the journey; the UI path runs on the data your backend (or mock server) returns. For third-party dependencies, pair DoesQA with Mockoon or WireMock and keep stub definitions in the tool your team already uses.

## Guides

| Topic                               | Guide                                                                        |
| ----------------------------------- | ---------------------------------------------------------------------------- |
| Share Values in the Flow Builder    | [Share data with Values](/better-coverage/share-data-with-values)            |
| API login, store token, assert      | [Test APIs in a Flow](/guides/test-apis-in-a-flow)                           |
| Create and delete test data via API | [Seed and clean up with API steps](/guides/seed-and-clean-up-with-api-steps) |
| Mockoon or WireMock                 | [Use mock servers with DoesQA](/guides/use-mock-servers-with-doesqa)         |
| Email as dynamic test data          | [Email testing in DoesQA](/guides/email-testing-in-doesqa)                   |

## Related

* [Value Store](/values/value-store)
* [Built-in Values](/values/built-in-values)
* [Creating Values](/values/creating-values)
* [Data Test Steps](/test-steps/data)
* [DoesQA compared](/choosing-a-test-automation-approach/doesqa-compared)


# Migrate to DoesQA

How migration to DoesQA works: free team-led coverage rebuild, typical timelines, and what to expect after the move.

DoesQA migrates your existing automation **coverage** into Flows. The DoesQA team does the work for free. A suite built over more than six months typically moves in a couple of days.

You do not rewrite the pack yourself. You keep shipping product while we rebuild the journeys that matter.

## What “migrated” means

We review your tests and migrate the **same coverage** into DoesQA: the product paths, environments, and checks that protect releases.

DoesQA uses [Flows](/getting-started/doesqa-concepts), shared [Elements](/elements/creating-elements), [Step Groups](/better-coverage/reuse-steps-with-step-groups), and [Flow Branches](/better-coverage/choose-flow-branch-shapes). The result is coverage expressed the way the product works, so [maintenance](/choosing-a-test-automation-approach/maintenance-and-reliability) stays low after you land.

## Typical timeline

Migration is typically very fast. Packs that took more than six months to build usually move in a couple of days once we have access to what you already use.

Exact timing depends on suite size and how quickly we can reach your environments. The team confirms scope when the request starts.

## How to start

1. Have a DoesQA account (or [start a trial](https://does.qa/signup/) / [book a demo](https://does.qa/demo/)).
2. Open **Help** in DoesQA and choose **Create new ticket**.
3. Say you want a migration. Tell us what automation you use today and what materials you can share (repo, exports, recordings, priority journeys, or a walkthrough). Bring whatever you have. Nothing special is required beyond that.

We migrate from Playwright, Cypress, Selenium, WDIO, and any other test automation framework or service. The support team replies over email and agrees the next steps.

Help article: [How do I request a free migration to DoesQA?](https://help.does.qa/support/kb/articles/vWykZyQb)

## After the move

* Review Flows with your team against the journeys you care about.
* Point [Run Recipes](/configuration/run-recipes) and Values at each environment.
* Use hosted Runs and Results as your release gate.
* Keep maintenance on shared Elements and Step Groups rather than scattered copies.

Website overview: [Migration](https://does.qa/migration/).

## Related

* [DoesQA compared](/choosing-a-test-automation-approach/doesqa-compared)
* [Maintenance and reliability](/choosing-a-test-automation-approach/maintenance-and-reliability)
* [Coverage and speed](/choosing-a-test-automation-approach/coverage-and-speed)
* [No lock-in](https://does.qa/no-lock-in/)
* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)


# Interacting with emails

Use DoesQA inboxes and Mail Test Steps to test registration, password reset, and other email journeys.

DoesQA includes test inboxes and [Mail Test Steps](/test-steps/mail) for journeys that send email. Your Flow can enter a DoesQA address in the application, wait for the message, open it, and continue from a link or code inside the email.

For the full picture on inbox types, parallel isolation, and common journeys, see [Email testing in DoesQA](/guides/email-testing-in-doesqa).

```mermaid
flowchart TD
  enter["Set value with $testEmail"] --> wait["Wait for email"]
  wait --> openMail["Open email"]
  openMail --> act["Touch or Check in the message"]
  act --> close["Close inbox"]
```

Use the **Flow Builder** for this walkthrough.

## Choose the address and inbox

| Value                                           | Inbox     | Use it when                                                                 |
| ----------------------------------------------- | --------- | --------------------------------------------------------------------------- |
| [`$testEmail`](/values/built-in-values)         | Test Case | The email belongs to this Test Case, such as registration or password reset |
| [`$testEmailShort`](/values/built-in-values)    | Test Case | You need the same Test Case inbox with a shorter address                    |
| [`$accountEmail`](/values/built-in-values)      | Account   | Several Test Cases share one mailbox                                        |
| [`$accountEmailShort`](/values/built-in-values) | Account   | You need the shared Account inbox with a shorter address                    |

Prefer [`$testEmail`](/values/built-in-values) with the **Test Case** inbox for journeys that send one email to one test. Use [`$accountEmail`](/values/built-in-values) only when you deliberately want a shared mailbox.

[`$randomEmail`](/values/built-in-values) is a generated address outside DoesQA mailboxes. Use a DoesQA [Value](/values/value-store) when the Flow will wait for or open the message.

## Build the Flow

{% stepper %}
{% step %}

## Enter the DoesQA address

In the step that fills the application's email field, use [`$testEmail`](/values/built-in-values) with [**Set value**](/test-steps/action/set-value).

<figure><img src="https://app.does.qa/screenshots/node/action_input_setValue.png" alt="Set value Test Step"><figcaption><p>Set value</p></figcaption></figure>

That sends the application to the Test Case inbox for this Run.
{% endstep %}

{% step %}

## Trigger the email

Continue the journey until the application should send the message, such as submitting registration or requesting a password reset. For full walkthroughs, see [Test registration and email verification](/guides/test-registration-and-email-verification) and [Test a forgotten-password flow](/guides/test-a-forgotten-password-flow).
{% endstep %}

{% step %}

## Wait for the email

Add [**Wait for email**](/test-steps/mail/wait-for-email) from the [**Mail**](/test-steps/mail) family.

<figure><img src="https://app.does.qa/screenshots/node/mail_wait_forMessage.png" alt="Wait for email Test Step"><figcaption><p>Wait for email</p></figcaption></figure>

1. Set **Inbox** to **Test Case**.
2. Leave **Type** as **New** when any new message is enough.
3. Or set **Type** to **Custom**, choose **Subject** or **From**, and match wording your application actually sends.
4. In advanced settings, check **End Offset**. The default is five minutes. Raise it when the application usually takes longer to send.
   {% endstep %}

{% step %}

## Open the email

Add [**Open email**](/test-steps/mail/open-email).

<figure><img src="https://app.does.qa/screenshots/node/mail_message_open.png" alt="Open email Test Step"><figcaption><p>Open email</p></figcaption></figure>

1. Set **Inbox** to **Test Case**.
2. Choose **Latest** for the newest matching message, or **Custom** with **Subject** or **From** when you need a specific one.
   {% endstep %}

{% step %}

## Continue from the message

After [**Open email**](/test-steps/mail/open-email), the message body is the active page. Use normal [Action](/test-steps/action), [Check](/test-steps/check), and [Validator](/test-steps/validator) Test Steps to click a link, assert text, run [accessibility checks](/better-coverage/add-accessibility-checks) on the message, or store a code into the [Value Store](/values/value-store).

<figure><img src="https://app.does.qa/screenshots/node/action_touch_single.png" alt="Touch Test Step"><figcaption><p>Touch</p></figcaption></figure>

When you are finished with the message, add [**Close inbox**](/test-steps/mail/close-inbox) to return to the application window.

<figure><img src="https://app.does.qa/screenshots/node/mail_inbox_close.png" alt="Close inbox Test Step"><figcaption><p>Close inbox</p></figcaption></figure>
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Open **Mail** in the left navigation to inspect the Account inbox or a Test Case inbox while you build the Flow, or after a Run to review messages that arrived during the test.
{% endhint %}

## The finished Flow

![Set value, Wait for email, Open email, Touch, and Close inbox connected as a simple Flow](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-41bad466a6ae4a4c883f4a92bdf4bc3b6f014261%2Femail-flow-approx.png?alt=media)

## Match the right message

| Setting          | What it does                                                                                        |
| ---------------- | --------------------------------------------------------------------------------------------------- |
| **Type: New**    | Waits for any email that arrives in the time window                                                 |
| **Type: Custom** | Waits until **Subject**, **From**, or another property matches your Value                           |
| **End Offset**   | How long [**Wait for email**](/test-steps/mail/wait-for-email) keeps checking, up to twenty minutes |
| **Start Offset** | How far back the wait looks, such as from Test Start                                                |

Use **Subject** or **From** filters when the inbox may receive more than one message. Keep the comparison close to the real email text.

## Related

* [Email testing in DoesQA](/guides/email-testing-in-doesqa)
* [Test passwordless login](/guides/test-passwordless-login)
* [Test a forgotten-password flow](/guides/test-a-forgotten-password-flow)
* [Test registration and email verification](/guides/test-registration-and-email-verification)
* [Mail Test Steps](/test-steps/mail)
* [Wait For Email](/test-steps/mail/wait-for-email)
* [Open Email](/test-steps/mail/open-email)
* [Close Inbox](/test-steps/mail/close-inbox)
* [Set Value](/test-steps/action/set-value)
* [Built-in Values](/values/built-in-values)
* [Value Store](/values/value-store)


# Test a forgotten-password flow

Test a forgotten-password journey with DoesQA email and the Flow Builder.

A forgotten-password journey is a good early Flow. It covers form fill, email delivery, a reset link, and a new password, all without writing code.

```mermaid
flowchart TD
  open["Open reset page"] --> email["Set value with $testEmail"]
  email --> request["Touch submit"]
  request --> wait["Wait for email"]
  wait --> openMail["Open email"]
  openMail --> link["Touch reset link"]
  link --> password["Set value NEW_PASSWORD"]
  password --> save["Touch save"]
  save --> check["Check text or login"]
```

Use the **Flow Builder** for this walkthrough.

## What you need

* A website URL you can reach from the internet, with a working forgotten-password page
* An account in that application that can receive a reset email
* A [Value](/values/value-store) for the new password, such as `NEW_PASSWORD`

Prefer [`$testEmail`](/values/built-in-values) so the reset message lands in this Test Case inbox. See [Interacting with emails](/guides/interacting-with-emails) for inbox choices.

## Build the Flow

{% stepper %}
{% step %}

## Open the forgotten-password page

Start with [**Open**](/test-steps/starter/open). Point it at your forgotten-password URL on the browser you want to use.

<figure><img src="https://app.does.qa/screenshots/node/starter_open.png" alt="Open Test Step"><figcaption><p>Open</p></figcaption></figure>
{% endstep %}

{% step %}

## Enter the DoesQA address

Add [**Set value**](/test-steps/action/set-value) on the email field. Use [`$testEmail`](/values/built-in-values).

<figure><img src="https://app.does.qa/screenshots/node/action_input_setValue.png" alt="Set value Test Step"><figcaption><p>Set value</p></figcaption></figure>

That sends the application to the Test Case inbox for this Run.
{% endstep %}

{% step %}

## Request the reset

Add [**Touch**](/test-steps/action/touch) on the submit control that requests the reset email.

<figure><img src="https://app.does.qa/screenshots/node/action_touch_single.png" alt="Touch Test Step"><figcaption><p>Touch</p></figcaption></figure>

Add a short [**Check text**](/test-steps/check/check-text) afterward if the page shows confirmation text, so a silent failure is easy to spot.
{% endstep %}

{% step %}

## Wait for the reset email

Add [**Wait for email**](/test-steps/mail/wait-for-email) from the [**Mail**](/test-steps/mail) family.

<figure><img src="https://app.does.qa/screenshots/node/mail_wait_forMessage.png" alt="Wait for email Test Step"><figcaption><p>Wait for email</p></figcaption></figure>

1. Set **Inbox** to **Test Case**.
2. Prefer **Type** **Custom** with **Subject** or **From** wording your application sends.
3. Raise **End Offset** in advanced settings when the application usually takes longer than five minutes to send.
   {% endstep %}

{% step %}

## Open the email and follow the link

Add [**Open email**](/test-steps/mail/open-email) with the same **Test Case** inbox. Choose **Latest**, or **Custom** when you need a specific Subject or From.

<figure><img src="https://app.does.qa/screenshots/node/mail_message_open.png" alt="Open email Test Step"><figcaption><p>Open email</p></figcaption></figure>

The message body becomes the active page. Add [**Touch**](/test-steps/action/touch) on the reset link.

When the application opens in a new window or tab, add [**Switch window**](/test-steps/runner/switch-window) from the [**Runner**](/test-steps/runner) family so later steps land on the reset form. When you are finished with the message, add [**Close inbox**](/test-steps/mail/close-inbox).
{% endstep %}

{% step %}

## Set the new password

On the reset form, add [**Set value**](/test-steps/action/set-value) for the new password and confirmation fields. Use the same [Value](/values/value-store), such as `NEW_PASSWORD`, in both places.

Add [**Touch**](/test-steps/action/touch) on the control that saves the password.
{% endstep %}

{% step %}

## Confirm the outcome

Add Checks that match your product:

* Confirmation text on the success page with [**Check text**](/test-steps/check/check-text), or
* A login with the new password, using [**Set value**](/test-steps/action/set-value) and [**Touch**](/test-steps/action/touch) on the sign-in form

<figure><img src="https://app.does.qa/screenshots/node/check_text.png" alt="Check text Test Step"><figcaption><p>Check text</p></figcaption></figure>

If login is shared across Flows, turn that path into a [Step Group](/better-coverage/reuse-steps-with-step-groups) after this Flow works.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Keep the reset email filter tight with **Subject** or **From**. An open inbox that receives other messages is easier to debug when [**Wait for email**](/test-steps/mail/wait-for-email) matches one clear string.
{% endhint %}

## The finished Flow

![Open through Check text for a forgotten-password Flow](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-9a4083c0d2dd4f4ba2d5cc20945cdd7dd9d3310f%2Fforgotten-password-flow-approx.png?alt=media)

## Reuse what you built

| Piece             | Next step                                                                                                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Mail steps        | Reuse the same pattern for invite emails. See [Interacting with emails](/guides/interacting-with-emails) and [Test registration and email verification](/guides/test-registration-and-email-verification). |
| Login after reset | Save it as a [Step Group](/better-coverage/reuse-steps-with-step-groups).                                                                                                                                  |
| New password      | Store it in the [Value Store](/values/value-store) so other Flows can sign in.                                                                                                                             |

## Related

* [Interacting with emails](/guides/interacting-with-emails)
* [Reuse steps with Step Groups](/better-coverage/reuse-steps-with-step-groups)
* [Wait For Email](/test-steps/mail/wait-for-email)
* [Open Email](/test-steps/mail/open-email)
* [Close Inbox](/test-steps/mail/close-inbox)
* [Set Value](/test-steps/action/set-value)
* [Touch](/test-steps/action/touch)
* [Check Text](/test-steps/check/check-text)
* [Switch Window](/test-steps/runner/switch-window)
* [Open](/test-steps/starter/open)
* [Value Store](/values/value-store)
* [Built-in Values](/values/built-in-values)


# Test registration and email verification

Register a new account, verify the email, and confirm the user is signed in.

A registration Flow covers the form, the verification email, and the first signed-in screen. DoesQA supplies a unique inbox per Test Case, so each Run can complete signup without sharing mailboxes.

```mermaid
flowchart TD
  open["Open registration"] --> fill["Set value with $testEmail"]
  fill --> submit["Touch submit"]
  submit --> wait["Wait for email"]
  wait --> openMail["Open email"]
  openMail --> verify["Touch verify link"]
  verify --> check["Check text"]
```

Use the **Flow Builder** for this walkthrough.

## What you need

* A registration URL you can reach from the internet
* A password [Value](/values/value-store), such as `NEW_PASSWORD`
* Any other form Values your app requires (name, username, and similar)

Prefer [`$testEmail`](/values/built-in-values) so the verification message lands in this Test Case inbox. See [Interacting with emails](/guides/interacting-with-emails) for inbox choices.

## Build the Flow

{% stepper %}
{% step %}

## Open the registration page

Start with [**Open**](/test-steps/starter/open). Point it at your registration URL.
{% endstep %}

{% step %}

## Fill the form

Add [**Set value**](/test-steps/action/set-value) for each field.

Use [`$testEmail`](/values/built-in-values) in the email field. Use `$NEW_PASSWORD` (or your Value title) for the password. Fill any other required fields the same way.
{% endstep %}

{% step %}

## Submit registration

Add [**Touch**](/test-steps/action/touch) on the submit control. The application should send the verification email.
{% endstep %}

{% step %}

## Wait for the verification email

Add [**Wait for email**](/test-steps/mail/wait-for-email) from the [**Mail**](/test-steps/mail) family.

1. Set **Inbox** to **Test Case**.
2. Leave **Type** as **New**, or set **Custom** with **Subject** or **From** to match your verification message.
   {% endstep %}

{% step %}

## Open the email and follow the link

Add [**Open email**](/test-steps/mail/open-email) with **Inbox** set to **Test Case**.

The message body becomes the active page. Add [**Touch**](/test-steps/action/touch) on the verify link. Add [**Close inbox**](/test-steps/mail/close-inbox) when you leave the message.
{% endstep %}

{% step %}

## Confirm the account is verified

Add [**Check text**](/test-steps/check/check-text) (or another Check) on the success screen, dashboard, or “email verified” message your product shows.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** If verification opens in a new window, add [**Switch window**](/test-steps/runner/switch-window) after the link click, then continue your Checks there. See [Test tabs, windows, and frames](/guides/test-tabs-windows-and-frames).
{% endhint %}

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-c83668ef40a2e8545919c92c7a71dff1270025a6%2Fregistration-email-flow-approx.png?alt=media" alt="Registration and email verification Flow"><figcaption><p>Example registration and email verification Flow</p></figcaption></figure>

## Related

* [Interacting with emails](/guides/interacting-with-emails)
* [Test a forgotten-password flow](/guides/test-a-forgotten-password-flow)
* [Wait for email](/test-steps/mail/wait-for-email)
* [Open email](/test-steps/mail/open-email)
* [Close inbox](/test-steps/mail/close-inbox)
* [Share data with Values](/better-coverage/share-data-with-values)
* [Built-in Values](/values/built-in-values)


# Test passwordless login

Test passwordless or magic-link login with DoesQA inboxes and Mail Test Steps.

Passwordless login sends the user a link or code by email. The pattern matches registration verification and forgotten-password flows: enter a DoesQA address, wait for the message, open it, and continue from the link.

```mermaid
flowchart TD
  open["Open login page"] --> email["Set value with $testEmail"]
  email --> request["Touch send link"]
  request --> wait["Wait for email"]
  wait --> openMail["Open email"]
  openMail --> link["Touch magic link"]
  link --> check["Check signed in"]
```

Use the **Flow Builder** for this walkthrough.

## What you need

* A login page that offers passwordless or magic-link sign-in
* A URL your Test Runners can reach from the internet

Prefer [`$testEmail`](/values/built-in-values) so the link lands in this Test Case inbox. See [Email testing in DoesQA](/guides/email-testing-in-doesqa) for inbox choices.

## Build the Flow

{% stepper %}
{% step %}

## Open the login page

Start with [**Open**](/test-steps/starter/open) on your passwordless login URL.
{% endstep %}

{% step %}

## Enter the DoesQA address

Add [**Set value**](/test-steps/action/set-value) on the email field. Use [`$testEmail`](/values/built-in-values).
{% endstep %}

{% step %}

## Request the link

Add [**Touch**](/test-steps/action/touch) on the control that sends the magic link or passwordless email.
{% endstep %}

{% step %}

## Wait for the email

Add [**Wait for email**](/test-steps/mail/wait-for-email). Set **Inbox** to **Test Case**. Filter on **Subject** or **From** when the inbox may hold more than one message.
{% endstep %}

{% step %}

## Open the email and follow the link

Add [**Open email**](/test-steps/mail/open-email), then [**Touch**](/test-steps/action/touch) on the sign-in link in the message. Add [**Close inbox**](/test-steps/mail/close-inbox) when you return to the application.

Add a [**Check**](/test-steps/check) step on the signed-in screen your product shows after a successful link.
{% endstep %}
{% endstepper %}

## Related

* [Email testing in DoesQA](/guides/email-testing-in-doesqa)
* [Interacting with emails](/guides/interacting-with-emails)
* [Test registration and email verification](/guides/test-registration-and-email-verification)
* [Test a forgotten-password flow](/guides/test-a-forgotten-password-flow)


# Test MFA login

Automate a login that asks for a time-based MFA code.

Many apps ask for a one-time code after the password. DoesQA can generate that code from a saved MFA secret and type it into the page, so the Flow can finish sign-in without a phone.

```mermaid
flowchart TD
  open["Open login"] --> creds["Set value username and password"]
  creds --> submit["Touch submit"]
  submit --> mfa["Set MFA"]
  mfa --> finish["Touch MFA submit"]
  finish --> check["Check text"]
```

Use the **Flow Builder** for this walkthrough.

## What you need

* A website URL with MFA on login
* Username and password [Values](/values/value-store)
* The MFA secret for that account (the same secret you would scan into an authenticator app)

## Save the MFA secret

{% stepper %}
{% step %}

## Open MFA settings

Go to [**Settings → MFA**](/configuration/mfa).
{% endstep %}

{% step %}

## Create an MFA entry

Choose **Create**, set a **Title**, and paste the **MFA Secret**.

Confirm the live code against your authenticator app, then save. You will not be able to view or edit the secret again after it is saved.
{% endstep %}
{% endstepper %}

## Build the login Flow

{% stepper %}
{% step %}

## Open the sign-in page

Start with [**Open**](/test-steps/starter/open). Point it at your login URL.

<figure><img src="https://app.does.qa/screenshots/node/starter_open.png" alt="Open Test Step"><figcaption><p>Open</p></figcaption></figure>
{% endstep %}

{% step %}

## Enter username and password

Add [**Set value**](/test-steps/action/set-value) for the username and password fields. Use Values from the [Value Store](/values/value-store).

<figure><img src="https://app.does.qa/screenshots/node/action_input_setValue.png" alt="Set value Test Step"><figcaption><p>Set value</p></figcaption></figure>

Add [**Touch**](/test-steps/action/touch) on the control that submits the password step.

<figure><img src="https://app.does.qa/screenshots/node/action_touch_single.png" alt="Touch Test Step"><figcaption><p>Touch</p></figcaption></figure>
{% endstep %}

{% step %}

## Wait for the MFA field

When the code field appears, add a [**Wait**](/test-steps/runner/wait-for-element-to-be-displayed) or [**Check**](/test-steps/check/check-displayed) if your app needs a moment to show it.
{% endstep %}

{% step %}

## Enter the MFA code

Add [**Set MFA**](/test-steps/action/set-mfa).

<figure><img src="https://app.does.qa/screenshots/node/action_input_setMFA.png" alt="Set MFA Test Step"><figcaption><p>Set MFA</p></figcaption></figure>

1. Set **Mode** to **Saved**.
2. Choose the **MFA Key** you created under Settings.
3. Choose the **Element** for the code input.

DoesQA generates a fresh time-based code and types it into that Element.
{% endstep %}

{% step %}

## Finish sign-in

Add [**Touch**](/test-steps/action/touch) on the control that submits the MFA step.

Add [**Check text**](/test-steps/check/check-text) or another Check that proves the session landed where you expect.

<figure><img src="https://app.does.qa/screenshots/node/check_text.png" alt="Check text Test Step"><figcaption><p>Check text</p></figcaption></figure>
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** After the login works, save it as a [Step Group](/better-coverage/reuse-steps-with-step-groups) so other Flows can reuse the same MFA path.
{% endhint %}

## The finished Flow

![Open through Check text for an MFA login Flow](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-fa059caf0dd9e60c16661b1ffa05862c7938a731%2Fmfa-login-flow-approx.png?alt=media)

## Mode: Saved or New

| Mode      | Use it when                                                              |
| --------- | ------------------------------------------------------------------------ |
| **Saved** | The secret lives under [Settings → MFA](/configuration/mfa) (usual path) |
| **New**   | You need to pass a secret only for this step                             |

Prefer **Saved** so secrets stay in one place and Flows stay easy to share.

## Related

* [MFA](/configuration/mfa)
* [Set MFA](/test-steps/action/set-mfa)
* [Reuse steps with Step Groups](/better-coverage/reuse-steps-with-step-groups)
* [Reuse a login session](/guides/reuse-a-login-session)
* [Set Value](/test-steps/action/set-value)
* [Touch](/test-steps/action/touch)
* [Value Store](/values/value-store)


# Reuse a login session

Log in once, store the session, and pass it into other Flows with DoesQA Run.

Logging in on every Test Case slows a suite and can trip rate limits on the application. Log in once in a parent Flow, store the session data, then pass it into other Flows so they start already signed in.

```mermaid
flowchart TD
  child["Child: Open then Set cookie or storage"] --> parent["Parent: login then Store session"]
  parent --> run["DoesQA Run with Values"]
  run --> childApply["Child applies session and continues"]
```

Use the **Flow Builder** for this walkthrough.

To reuse the same login *steps* in many Flows without sharing a live session, use a [Step Group](/better-coverage/reuse-steps-with-step-groups) instead.

## What you need

* A login URL and credentials as [Values](/values/value-store)
* At least one child Flow that should start signed in (create it before the parent calls it)
* The cookie or storage key your application uses after login

## Build the child Flow first

Each child Run gets a fresh browser. It must apply the session data the parent will pass in.

{% stepper %}
{% step %}

## Open the application

Start with [**Open**](/test-steps/starter/open). Point it at a page in your application.
{% endstep %}

{% step %}

## Set the session data

Add the matching **Data** step for how your app keeps the session:

| After login, the app uses | Set it with                                                   |
| ------------------------- | ------------------------------------------------------------- |
| A cookie                  | [**Set cookie**](/test-steps/data/set-cookie)                 |
| `localStorage`            | [**Set localStorage**](/test-steps/data/set-localstorage)     |
| `sessionStorage`          | [**Set sessionStorage**](/test-steps/data/set-sessionstorage) |

In the value field, type `$` and pick the Value name the parent will pass, such as `$auth_token`.
{% endstep %}

{% step %}

## Continue the journey

Add the steps that assume a signed-in user, such as opening a dashboard and checking content.
{% endstep %}
{% endstepper %}

## Build the parent Flow

{% stepper %}
{% step %}

## Open the sign-in page

Start with [**Open**](/test-steps/starter/open). Point it at your login URL.
{% endstep %}

{% step %}

## Complete login

Add [**Set value**](/test-steps/action/set-value) and [**Touch**](/test-steps/action/touch) (or your usual login steps) until the session is established.
{% endstep %}

{% step %}

## Store the session data

Add the matching **Store** step:

| Source           | Step                                                              |
| ---------------- | ----------------------------------------------------------------- |
| Cookie           | [**Store cookie**](/test-steps/data/store-cookie)                 |
| `localStorage`   | [**Store localStorage**](/test-steps/data/store-localstorage)     |
| `sessionStorage` | [**Store sessionStorage**](/test-steps/data/store-sessionstorage) |

Set **Value Store Key** to a clear name, such as `cookieValue`. That key holds the data for this Run so [**DoesQA Run**](/test-steps/express/doesqa-run) can pass it on.
{% endstep %}

{% step %}

## Start the child Flows

Add [**DoesQA Run**](/test-steps/express/doesqa-run) from **Express**.

1. Set a **Run Label**.
2. Choose **Flow Selection**: pick the child Flows, a [Run Recipe](/configuration/run-recipes), or tag filters.
3. In **Values**, map the stored key into the name the child expects:

```json
{
  "auth_token": "{{cookieValue}}"
}
```

`{{cookieValue}}` pulls the parent’s stored key. The child then reads `$auth_token` in its Set step.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Use **Await & Match Results** on DoesQA Run when the parent should fail if a child Run fails. Use **Trigger Only** when the parent only needs to start the children.
{% endhint %}

{% hint style="warning" %}
A child Run cannot start another DoesQA Run. Keep session handoff to one parent level.
{% endhint %}

## Related

* [DoesQA Run](/test-steps/express/doesqa-run)
* [Store cookie](/test-steps/data/store-cookie)
* [Set cookie](/test-steps/data/set-cookie)
* [Reuse steps with Step Groups](/better-coverage/reuse-steps-with-step-groups)
* [Share data with Values](/better-coverage/share-data-with-values)
* [Run Recipes](/configuration/run-recipes)


# Test checkout and payments

Automate cart, address, and payment steps through to order confirmation.

A checkout Flow proves the path from cart to confirmation. Fill ordinary fields with Action steps. For payment widgets, use the Express Adyen steps when you are on Adyen, or switch into the payment iframe and fill it like any other form.

```mermaid
flowchart TD
  open["Open storefront"] --> cart["Touch and Set value"]
  cart --> address["Set value for shipping"]
  address --> pay{"Payment UI"}
  pay -->|Adyen| adyen["Adyen Widget"]
  pay -->|iframe| frame["Switch frame then Set value"]
  frame --> parent["Switch to parent frame"]
  parent --> submit["Touch pay"]
  adyen --> confirm["Check confirmation"]
  submit --> confirm
```

Use the **Flow Builder** for this walkthrough.

## What you need

* A storefront URL and products you can buy in a test environment
* Address and customer [Values](/values/value-store) where the form repeats
* Payment test data from your provider's published test cards (not live customer cards)

## Build the cart and address steps

{% stepper %}
{% step %}

## Open the storefront

Start with [**Open**](/test-steps/starter/open). Point it at the product, cart, or checkout URL your journey starts from.
{% endstep %}

{% step %}

## Add items and reach checkout

Use [**Touch**](/test-steps/action/touch) and [**Set value**](/test-steps/action/set-value) to add products, choose options, and open checkout.
{% endstep %}

{% step %}

## Fill shipping and contact details

Add [**Set value**](/test-steps/action/set-value) for name, address, and email fields. Prefer Values from the [Value Store](/values/value-store) so the same Flow can run across environments.
{% endstep %}
{% endstepper %}

## Complete payment

### Adyen Drop-in or widget

When the page uses Adyen, add [**Adyen Widget**](/test-steps/express/adyen-widget) from **Express**.

1. Enter the provider’s test card number, expiry, CVC, and name (or pull them from Values).
2. Set **Complete Checkout** to **Purchase** to fill and submit, or **Fields Only** when a later step should press pay.
3. Choose the purchase button [Element](/elements/creating-elements) when **Purchase** is selected.

For PayPal through Adyen, use [**Adyen PayPal**](/test-steps/express/adyen-paypal).

### Payment fields inside an iframe

Many providers render card fields in an iframe. Switch into that frame, fill the fields, then return to the parent page.

{% stepper %}
{% step %}

## Switch into the payment frame

Add [**Switch frame**](/test-steps/runner/switch-frame). Choose the [Element](/elements/creating-elements) for the iframe.
{% endstep %}

{% step %}

## Fill the card fields

Add [**Set value**](/test-steps/action/set-value) (and [**Touch**](/test-steps/action/touch) if needed) for number, expiry, and CVC inside the frame.
{% endstep %}

{% step %}

## Return to the page and submit

Add [**Switch to parent frame**](/test-steps/runner/switch-to-parent-frame), then [**Touch**](/test-steps/action/touch) the pay or place-order button on the parent page.
{% endstep %}
{% endstepper %}

See [Test tabs, windows, and frames](/guides/test-tabs-windows-and-frames) for nested frames and hosted checkouts that open a new window.

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-96e34dfbe5fb0f25018d08c7e10d5469d509b913%2Fcheckout-iframe-pay-approx.png?alt=media" alt="Switch frame, Set value, parent frame, Touch"><figcaption><p>Example iframe payment path</p></figcaption></figure>

### Ordinary card fields on the page

If the card inputs sit in the main document, fill them with [**Set value**](/test-steps/action/set-value) and submit with [**Touch**](/test-steps/action/touch). No frame switch is required.

## Confirm the order

Add [**Check text**](/test-steps/check/check-text) or another Check on the confirmation screen, order number, or success message. Add a URL Check when the success page has a stable path.

{% hint style="info" %}
**Pro tip:** Keep provider test card numbers in Values when several Flows share them. Use the provider’s published test cards for the environment you are targeting.
{% endhint %}

## Related

* [Adyen Widget](/test-steps/express/adyen-widget)
* [Adyen PayPal](/test-steps/express/adyen-paypal)
* [Switch frame](/test-steps/runner/switch-frame)
* [Switch to parent frame](/test-steps/runner/switch-to-parent-frame)
* [Test tabs, windows, and frames](/guides/test-tabs-windows-and-frames)
* [Share data with Values](/better-coverage/share-data-with-values)
* [Run across environments](/better-coverage/run-across-environments)


# Test APIs in a Flow

Call an API from a Flow, store the response as a Value, and assert JSON.

API calls belong in the same Flow as your browser steps. Use them to seed data, fetch a token, assert backend state, or clean up after a UI journey.

```mermaid
flowchart TD
  open["Open app"] --> post["POST login API"]
  post --> check["Check JSON Value"]
  check --> next["UI or more APIs"]
```

Use the **Flow Builder** for this walkthrough.

## What you need

* A fully qualified API URL (or a [Value](/getting-started/terminology) that expands to one)
* Optional credentials or tokens as [Values](/values/value-store)
* A Flow open in the Flow Builder

## Build a login-token Flow

This example calls a login API, stores the JSON response, then asserts it. The same pattern works for any GET, POST, PUT, PATCH, or DELETE.

{% stepper %}
{% step %}

## Open the app

Start with [**Open**](/test-steps/starter/open). Point it at your application URL so the Test Case has a browser context, even when the next steps are API calls.
{% endstep %}

{% step %}

## Add the API call

Add [**POST**](/test-steps/integration/post) from the Integration family.

1. Set **URL** to the login endpoint. Use `$BASE_URL` plus a path when the host changes per environment.
2. Set **Body Content-Type** to **JSON**.
3. Enter a JSON body that uses Values for credentials, for example username and password from Assets.
4. Set **Response Storage Name** to something clear, such as `authResponse`.
   {% endstep %}

{% step %}

## Expect the right status

Open advanced options on the POST step. **Expected Response Status Codes** defaults to **2xx**. Change it when the API should return a specific code, such as **201**.

Statuses in the **5xx** range fail the step as errors.
{% endstep %}

{% step %}

## Send auth on later calls

For APIs that need a Bearer token or API key, open **Headers** on the Integration step and pass JSON such as:

```json
{
  "Authorization": "Bearer $API_TOKEN"
}
```

Keep `$API_TOKEN` (or similar) in [Assets → Values](/values/creating-values), or overwrite it for a Run with a [Run Recipe](/configuration/run-recipes). Integration steps read Headers you set on the step. They do not reuse browser cookies from Open.
{% endstep %}

{% step %}

## Assert the JSON response

Add [**Check JSON Value**](/test-steps/check/check-json-value).

1. Set **Input Item** to the same name you stored, such as `authResponse`.
2. Choose **Match Mode** **Contains** or **Equals**.
3. Set the expected JSON with **Custom**, or compare against another Value Store item.

Use [**Check JSON Schema**](/test-steps/check/check-json-schema) when you want a schema assert, or [**Check Value Store**](/test-steps/check/check-value-store) for a single stored field.
{% endstep %}

{% step %}

## Continue with UI or more APIs

Add further Integration steps that reuse `$BASE_URL` and Headers, or continue with Action and Check steps on the page. The stored response stays available for the rest of the Test Case under the **Response Storage Name**.

When the response is JSON, reference nested fields in later steps with dot notation, for example `$authResponse.token` in a URL or text field. See [Test data in DoesQA](/guides/test-data-in-doesqa#fields-inside-stored-json).
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Store API hosts and secrets as Assets Values or Recipe overwrites. Keep response storage names specific (`authResponse`, `order`) so later Checks stay readable.
{% endhint %}

A finished login-token path looks like this:

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-362b9ba584f61f6956ec7345a41df4617170dcc5%2Fapi-login-token-flow-approx.png?alt=media" alt="Open, POST, and Check JSON Value"><figcaption><p>Example API login-token Flow</p></figcaption></figure>

## Choose GET, POST, PUT, PATCH, or DELETE

| Test Step                                | Typical use                                       |
| ---------------------------------------- | ------------------------------------------------- |
| [GET](/test-steps/integration/get)       | Read a resource                                   |
| [POST](/test-steps/integration/post)     | Create a resource or submit a form-style API body |
| [PUT](/test-steps/integration/put)       | Replace a resource                                |
| [PATCH](/test-steps/integration/patch)   | Update part of a resource                         |
| [DELETE](/test-steps/integration/delete) | Remove a resource                                 |

Switch **Method** on an Integration API step to change between these without rebuilding the rest of the step.

## What gets stored

| Response Object    | Stored under the Response Storage Name |
| ------------------ | -------------------------------------- |
| **Body** (default) | Response body                          |
| **Headers**        | Response headers                       |
| **Complete**       | Body and headers together              |

The storage name must start with a letter and use only letters, numbers, and underscores.

## Environments

Use the same Flow across staging and production by keeping the host in a Value:

* [Share data with Values](/better-coverage/share-data-with-values) for Assets Values and `$` insertion
* [Run across environments](/better-coverage/run-across-environments) for tags and overwrites
* [CI / CD](/configuration/ci-cd) to pass Value overrides from the pipeline

## Browser timing is a different check

[**Check API Response Time**](/test-steps/check/check-api-response-time) measures how long a **browser** network request takes during the Test Case. It does not time Integration API steps. Use it when you care about page network performance, not when you are asserting an Integration response.

## Related

* [Test data in DoesQA](/guides/test-data-in-doesqa)
* [Seed and clean up with API steps](/guides/seed-and-clean-up-with-api-steps)
* [Integration](/test-steps/integration)
* [POST](/test-steps/integration/post)
* [Check JSON Value](/test-steps/check/check-json-value)
* [Value Store](/values/value-store)
* [Share data with Values](/better-coverage/share-data-with-values)


# Seed and clean up with API steps

Create test data with Integration API steps before UI steps, then delete it after.

Many UI journeys need a user, order, or record that already exists in the backend. Instead of clicking through setup every time, call your API from the same Flow, store the response in the [Value Store](/values/value-store), run the UI path, then remove the data when you finish.

```mermaid
flowchart TD
  create["POST create resource"] --> store["Response in Value Store"]
  store --> ui["UI journey"]
  ui --> assert["GET or Check JSON Value"]
  assert --> delete["DELETE cleanup"]
```

## What you need

* API endpoints for create, read, and delete (or reset)
* Credentials or API keys as [Account Values](/values/creating-values)
* A [Value](/values/creating-values) for the API host, such as `$BASE_URL`

See [Test APIs in a Flow](/guides/test-apis-in-a-flow) for the first POST and token pattern.

## Seed before the UI

{% stepper %}
{% step %}

## Create the resource

Add [**POST**](/test-steps/integration/post) (or **PUT** when your API uses it).

1. Set **URL** to the create endpoint. Use `$BASE_URL` plus a path when the host changes per environment.
2. Set **Body Content-Type** to **JSON**. Use Account Values for fields the API expects.
3. Set **Response Storage Name** to a clear name, such as `createdUser` or `orderResponse`.
   {% endstep %}

{% step %}

## Use stored fields in the UI

Open the app with [**Open**](/test-steps/starter/open). Fill forms with built-ins or stored data:

* `$testEmail` for a unique inbox per Test Case
* `$createdUser.email` when the API returned an object and you need one field in a text input
* `$createdUser.id` in a URL when the app deep-links by ID

For headers on later API calls, pass JSON such as `{"Authorization": "Bearer $API_TOKEN"}` on the Integration step.
{% endstep %}

{% step %}

## Assert backend state (optional)

Add [**GET**](/test-steps/integration/get) or [**Check JSON Value**](/test-steps/check/check-json-value) to confirm the resource exists or matches what the UI should show.
{% endstep %}
{% endstepper %}

## Clean up after the UI

Add [**DELETE**](/test-steps/integration/delete) (or a reset endpoint your team provides) at the end of the Test Case. Use the stored ID in the URL, for example `$BASE_URL/api/users/$createdUser.id`.

If delete is not available, document the workaround your team accepts (dedicated test tenant, nightly reset, or a support-only cleanup script). Prefer real cleanup in the Flow when the API allows it.

{% hint style="info" %}
**Pro tip:** Keep storage names specific (`createdUser`, `authResponse`). Generic names such as `response` make later steps harder to read when a Flow has more than one API call.
{% endhint %}

## When a mock server fits better

When the API is a third-party service you cannot seed directly, point Integration steps at a [mock server](/guides/use-mock-servers-with-doesqa) and store the mock base URL in Assets. The seed and cleanup pattern is the same. Stub definitions stay in Mockoon or WireMock.

## Related

* [Test data in DoesQA](/guides/test-data-in-doesqa)
* [Test APIs in a Flow](/guides/test-apis-in-a-flow)
* [Value Store](/values/value-store)
* [Built-in Values](/values/built-in-values)


# Use mock servers with DoesQA

Point Integration API steps and Values at Mockoon or WireMock when you need stubbed HTTP responses.

When a dependency must return canned JSON, run a **mock server** and call it from [Integration API steps](/test-steps/integration/post) in your Flow. DoesQA sends HTTP requests to whatever URL you configure. You maintain stub routes and responses in Mockoon, WireMock, or a similar tool.

For APIs your team owns, [seed data with Integration steps](/guides/seed-and-clean-up-with-api-steps) against a test environment first. Mock servers fit third-party services and contract-style stubs.

## When to use a mock server

| Situation                                 | Mock server helps                        |
| ----------------------------------------- | ---------------------------------------- |
| Third-party API (payments, CRM, weather)  | Stable responses without live accounts   |
| Backend not ready                         | UI tests against agreed contracts        |
| Parallel tests must not share one backend | Isolated stubs per environment or tenant |
| Error paths                               | Return 4xx or 5xx on demand              |

## Pattern in DoesQA

1. Run **Mockoon** or **WireMock** however your team prefers (desktop, CLI, Docker, or their cloud offerings).
2. Create an Account Value for the mock base URL, for example `$MOCK_API_URL`.
3. Add Integration steps whose **URL** uses that Value: `$MOCK_API_URL/v1/orders`
4. Store responses in the [Value Store](/values/value-store) when later UI or API steps need fields from the stub.
5. Run the browser steps against your application as usual.

[Hosted DoesQA Runs](/runs/start-a-run) call `$MOCK_API_URL` from DoesQA infrastructure, so the URL must be one those runners can reach.

Overwrite `$MOCK_API_URL` per environment with a [Run Recipe](/configuration/run-recipes) or CI [Values](/configuration/ci-cd) when staging uses a real API and another Recipe points at a mock.

```mermaid
flowchart LR
  flow["DoesQA Flow"] --> browser["Browser → your app"]
  flow --> api["Integration API steps"]
  api --> mock["Mockoon or WireMock"]
```

## Mockoon

[Mockoon](https://mockoon.com/) runs as a desktop app, through the [CLI](https://mockoon.com/cli/) and [Docker image](https://hub.docker.com/r/mockoon/cli), or on [Mockoon Cloud](https://mockoon.com/cloud/). Pick the option that fits how you work.

Typical setup:

1. Define routes and JSON bodies in Mockoon.
2. Set `$MOCK_API_URL` to the mock's base URL.
3. Call routes from **GET** or **POST** steps. Assert with [**Check JSON Value**](/test-steps/check/check-json-value).

## WireMock

[WireMock](https://wiremock.org/) serves stubs from mappings (JSON or Java), self-hosted or on [WireMock Cloud](https://wiremock.io/cloud/). From DoesQA, Integration steps target the WireMock base URL.

Typical setup:

1. Deploy WireMock with your stub mappings.
2. Store the base URL in `$MOCK_API_URL` or per-service Values.
3. Use Integration steps for setup calls the UI depends on, or configure your application (via Account Values) to call WireMock when running against a test build.

## Browser and API traffic

**Integration API steps** call the mock directly. This suits setup, webhooks, or backends your UI calls server-side.

The **browser** loads your application URL from **Open**. When the app must call the mock from the browser, set the application's API base URL Value for that environment so traffic reaches the mock during the Run.

{% hint style="info" %}
**Pro tip:** Keep mock base URLs in Account Values or Recipe overwrites so staging can point at a real API while a dev Recipe points at a mock.
{% endhint %}

## Related

* [Test data in DoesQA](/guides/test-data-in-doesqa)
* [Seed and clean up with API steps](/guides/seed-and-clean-up-with-api-steps)
* [Test APIs in a Flow](/guides/test-apis-in-a-flow)
* [Run across environments](/better-coverage/run-across-environments)


# Test file uploads and downloads

Generate files, upload them into inputs, and reuse the last download in a Flow.

DoesQA can create files inside a Flow, upload them into a file input, and reuse a file the browser just downloaded. You do not upload files from your laptop into the step.

```mermaid
flowchart TD
  open["Open upload page"] --> gen["Generate file or image"]
  gen --> file["File step Generated File"]
  file --> check["Check upload succeeded"]
```

Use the **Flow Builder** for this walkthrough.

## Upload a generated file

{% stepper %}
{% step %}

## Open the page

Start with [**Open**](/test-steps/starter/open). Point it at the page that has the upload control, or at the start of the journey that leads there.
{% endstep %}

{% step %}

## Generate the file

Add [**Generate file**](/test-steps/runner/generate-file) or [**Generate image**](/test-steps/runner/generate-image) from the [**Runner**](/test-steps/runner) family.

Set a **Filename**, choose the type, and fill the contents or image settings you need.
{% endstep %}

{% step %}

## Reach the upload control

Continue with [**Touch**](/test-steps/action/touch) and other steps until the file input is ready.
{% endstep %}

{% step %}

## Upload with File

Add [**File**](/test-steps/action/file).

1. Choose the file input [Element](/elements/creating-elements).
2. Set **File** to **Generated File**.
3. Pick the file you generated earlier in this Flow.
   {% endstep %}

{% step %}

## Confirm the upload

Add [**Check text**](/test-steps/check/check-text) or another Check that proves the application accepted the file.
{% endstep %}
{% endstepper %}

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-3368a183a473b28f3db0fa174f46b355c4b55d39%2Fgenerate-file-upload-miniflow-approx.png?alt=media" alt="Generate file then File upload"><figcaption><p>Example generate-and-upload path</p></figcaption></figure>

## Reuse the last download

When the application downloads a file during the Run, later steps can use it.

1. Trigger the download with [**Touch**](/test-steps/action/touch) or another step.
2. Add [**File**](/test-steps/action/file) or [**Open file**](/test-steps/browser/open-file).
3. Set **File** to **Last Downloaded**.

[**Open file**](/test-steps/browser/open-file) opens that file in the browser. [**File**](/test-steps/action/file) uploads it into a file input.

{% hint style="info" %}
**Pro tip:** Generate the file in the same Flow (or [Step Group](/better-coverage/reuse-steps-with-step-groups)) that uploads it. The Generated File picker only lists files created earlier in that path.
{% endhint %}

## Related

* [File](/test-steps/action/file)
* [Open file](/test-steps/browser/open-file)
* [Generate file](/test-steps/runner/generate-file)
* [Generate image](/test-steps/runner/generate-image)
* [Choose durable selectors](/better-coverage/choose-durable-selectors)
* [Touch](/test-steps/action/touch)


# Test tabs, windows, and frames

Move between tabs, windows, and iframes while a Flow runs.

Some journeys open a new tab, a popup window, or content inside an iframe. DoesQA keeps focus on one place at a time, so you add a step when the Flow should move.

```mermaid
flowchart TD
  touch["Touch opens popup or tab"] --> window["Switch window or Next tab"]
  window --> work["Set value Touch Check"]
  work --> frame["Switch frame when content is in an iframe"]
  frame --> parent["Switch to parent frame"]
```

Use the **Flow Builder** for this walkthrough.

## Switch to a popup window

{% stepper %}
{% step %}

## Open the popup

Use [**Touch**](/test-steps/action/touch) (or another step) on the control that opens the new window.
{% endstep %}

{% step %}

## Switch window

Add [**Switch window**](/test-steps/runner/switch-window) from the [**Runner**](/test-steps/runner) family.

Enter part of the window **Domain / Title**. DoesQA matches that text against the page title, then the URL.
{% endstep %}

{% step %}

## Continue in the new window

Add [**Set value**](/test-steps/action/set-value), [**Touch**](/test-steps/action/touch), or Checks as usual.
{% endstep %}

{% step %}

## Return if you need the original window

Add another [**Switch window**](/test-steps/runner/switch-window) with Domain / Title text from the first window.
{% endstep %}
{% endstepper %}

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-5a5f96257a02e7c10f53215bb60bdcee97f9dbea%2Fswitch-window-flow-approx.png?alt=media" alt="Touch, Switch window, Set value"><figcaption><p>Example popup window path</p></figcaption></figure>

## Move between tabs

| Test Step                                                  | What it does              |
| ---------------------------------------------------------- | ------------------------- |
| [Next tab](/test-steps/browser/next-tab)                   | Moves to the next tab     |
| [Previous tab](/test-steps/browser/previous-tab)           | Moves to the previous tab |
| [Close current tab](/test-steps/browser/close-current-tab) | Closes the tab you are on |

These steps are relative to the current tab. There is no tab index field.

## Work inside an iframe

{% stepper %}
{% step %}

## Switch into the frame

Add [**Switch frame**](/test-steps/runner/switch-frame).

Choose the [Element](/elements/creating-elements) that represents the iframe.
{% endstep %}

{% step %}

## Interact inside the frame

Add Action and Check steps against Elements inside that frame.
{% endstep %}

{% step %}

## Leave the frame

Add [**Switch to parent frame**](/test-steps/runner/switch-to-parent-frame) when later steps belong to the page around the iframe.
{% endstep %}
{% endstepper %}

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-58408cacff9c6986d30dec7fd106d6e1b803acec%2Fswitch-frame-miniflow-approx.png?alt=media" alt="Switch frame and Switch to parent frame"><figcaption><p>Example iframe path</p></figcaption></figure>

{% hint style="info" %}
**Pro tip:** Keep Domain / Title text short but distinctive, such as part of the host name or a unique page title word, so [**Switch window**](/test-steps/runner/switch-window) lands on the right target.
{% endhint %}

## Related

* [Switch window](/test-steps/runner/switch-window)
* [Switch frame](/test-steps/runner/switch-frame)
* [Switch to parent frame](/test-steps/runner/switch-to-parent-frame)
* [Next tab](/test-steps/browser/next-tab)
* [Previous tab](/test-steps/browser/previous-tab)
* [Close current tab](/test-steps/browser/close-current-tab)
* [Choose durable selectors](/better-coverage/choose-durable-selectors)


# Reuse steps with Step Groups

Create reusable Step Groups so shared journeys stay in sync across Flows.

A Step Group is a reusable set of [Test Steps](/getting-started/terminology). Build a login, consent, or setup journey once, drop the group into other Flows, and keep every usage in sync when you edit it.

```mermaid
flowchart TD
  select["Select login steps"] --> group["Create Group"]
  group --> name["Name the Step Group"]
  name --> reuse["Drop the group into other Flows"]
```

Use the **Flow Builder** for this walkthrough.

## Create a Step Group

{% stepper %}
{% step %}

## Select the steps to reuse

Open a Flow in the Flow Builder and select the Test Steps that should travel together.

Hold **Shift** and drag to box-select, or hold **Ctrl** (Windows) or **Cmd** (Mac) and click to add steps. Start from the steps after [**Open**](/test-steps/starter/open). Open stays at the start of the Flow.

A typical login selection looks like set credentials, submit, and MFA when you need it:

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-4be6e8f20d5cc3dc7bb5a7d50c3cc96106564986%2Fstep-group-login-steps-approx.png?alt=media" alt="Login Test Steps ready to group"><figcaption><p>Example steps to select before grouping</p></figcaption></figure>
{% endstep %}

{% step %}

## Group the selection

Right-click the selection and choose **Create Group**. You can also press **Ctrl+G** or **Cmd+G**.

DoesQA replaces the selected steps with one [Step Group](/test-steps/step-group) on the canvas.

<figure><img src="https://app.does.qa/screenshots/node/special_group.png" alt="Step Group Test Step"><figcaption><p>Step Group</p></figcaption></figure>
{% endstep %}

{% step %}

## Name the group

Double-click the Step Group, set the **Name**, and save.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Hold **Shift** while dragging to select several Test Steps at once, then press **Ctrl+G** or **Cmd+G** to group them.
{% endhint %}

## Edit a Step Group

Double-click a Step Group to change its **Name** or the Test Steps inside it.

{% hint style="warning" %}
Saving a Step Group updates every Flow that uses it. That is the point of reuse: fix the group once, and every journey that depends on it stays aligned.
{% endhint %}

Removing a Step Group from one Flow only removes that instance. The shared group remains available for other Flows.

## Use a Step Group in another Flow

1. Open the destination Flow in the Flow Builder.
2. Open the Test Step library.
3. Find the group under **Step Groups**.
4. Drag it onto the canvas where the shared journey should run.

A Flow that reuses login often looks like Open, then the Step Group, then a Check:

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-b6de4dec6913c195cde1b3e6b9e62ae514706496%2Fstep-group-reuse-flow-approx.png?alt=media" alt="Open, Step Group, and Check on a Flow"><figcaption><p>Example Flow after dropping a Step Group</p></figcaption></figure>

## Manage Step Groups

Open **Assets → Groups** to review every Step Group in the account.

From there you can:

* Edit a group
* **Duplicate Step Group** to create a copy
* **Delete Step Group** when nothing still uses it
* See which Flows use a group

You can also open the same list from the Flow Builder with **Manage Step Groups**.

Prefer a Step Group when you need the same *steps*. Prefer [DoesQA Run](/test-steps/express/doesqa-run) when you need to share a live *session* into child Runs. See [Reuse a login session](/guides/reuse-a-login-session).

## Related

* [Step Group](/test-steps/step-group)
* [Reuse a login session](/guides/reuse-a-login-session)
* [DoesQA concepts](/getting-started/doesqa-concepts)
* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [Flow Builder](/platform/flow-builder)


# Choose durable selectors

Choose Element Selectors that stay stable as the page design changes.

An [Element](/getting-started/terminology) is the reusable page object your Test Steps use. A [Selector](/getting-started/terminology) is the rule inside that Element that finds it on the page. Durable Selectors keep Flows working when styles and layout change.

To create an Element (from **Assets → Elements** or **+** on a Test Step), including **Automatic** with a **Description**, see [Creating Elements](/elements/creating-elements). This guide is about choosing Selectors that last.

```mermaid
flowchart TD
  start["Need a durable Selector"] --> tid{"Test ID available?"}
  tid -->|Yes| useTid["Prefer Test ID"]
  tid -->|No| css{"Stable id name or attribute?"}
  css -->|Yes| useCss["Prefer CSS"]
  css -->|No| text{"Stable visible label?"}
  text -->|Yes| useText["Prefer Visible Text"]
  text -->|No| xpath["Use XPath for DOM relationships"]
```

## Prefer Selectors built for testing

| Selector type                                         | Prefer it when                                                  |
| ----------------------------------------------------- | --------------------------------------------------------------- |
| [Test ID](/elements/selector-types/test-id)           | The application exposes a dedicated test attribute              |
| [CSS](/elements/selector-types/css)                   | You have a stable id, name, or attribute that names the control |
| [Visible Text](/elements/selector-types/visible-text) | The user-visible label is the clearest identity                 |
| [XPath](/elements/selector-types/xpath)               | You need a DOM relationship the other types do not cover        |

Start with a [Test ID](/elements/selector-types/test-id) when your team can add one. It describes the control for testing, so styling and copy changes are less likely to break the Flow.

**Automatic** Elements generate a Selector from a **Description**. That is a fast way to start. When you need a Selector you can edit and harden, switch the Element to **Manual** and apply the preferences above. See [Creating Elements](/elements/creating-elements).

## Set a Manual Selector

{% stepper %}
{% step %}

## Open the Element

Open the Element from **Assets → Elements**, or edit it from the Test Step that uses it. For the full create flow, see [Creating Elements](/elements/creating-elements).
{% endstep %}

{% step %}

## Use Manual configuration

Set **Element configuration** to **Manual**, then pick a **Type**:

* [Test ID](/elements/selector-types/test-id)
* [CSS](/elements/selector-types/css)
* [Visible Text](/elements/selector-types/visible-text)
* [XPath](/elements/selector-types/xpath)
  {% endstep %}

{% step %}

## Enter a tight Selector

Fill **Selector**, **Text**, or **Test ID** for that type. Keep the expression tight to the control you mean to use, not a large layout wrapper.

Turn on **Dynamic Selector** only when the expression itself must include a [Value](/values/value-store).
{% endstep %}

{% step %}

## Reuse it in Test Steps

In [**Touch**](/test-steps/action/touch), [**Set value**](/test-steps/action/set-value), [**Check text**](/test-steps/check/check-text), or another step, choose the Element you saved. One Element can power many steps and Flows.
{% endstep %}
{% endstepper %}

## Habits that keep Elements durable

* Name the control, not its colour or position on the day you wrote the test.
* Prefer attributes your team owns for testing over auto-generated class names.
* When the control lives inside Shadow DOM, use a Manual [CSS](/elements/selector-types/css) Selector with a `>>>` prefix. See [Shadow DOM](/elements/selector-types/shadow-dom).
* When a step fails to find the Element, open the Element and update the Selector before you add extra [Wait](/test-steps/runner) steps.
* Reuse one Element across Flows instead of recreating the same Selector in each Flow.
* After an **Automatic** Description gets you moving, switch to **Manual** when you are ready to lock in a durable Selector.

{% hint style="info" %}
**Pro tip:** If [**Touch**](/test-steps/action/touch) reports the Element as overlapped or not clickable, fix the Selector or the page state first. Touch already waits and scrolls for the Element.
{% endhint %}

## Related

* [Creating Elements](/elements/creating-elements)
* [Selector Types](/elements/selector-types)
* [Create and run your first Flow](/getting-started/create-and-run-your-first-flow)
* [Test ID](/elements/selector-types/test-id)
* [CSS](/elements/selector-types/css)
* [Shadow DOM](/elements/selector-types/shadow-dom)
* [Visible Text](/elements/selector-types/visible-text)
* [XPath](/elements/selector-types/xpath)
* [Terminology](/getting-started/terminology)
* [Touch](/test-steps/action/touch)


# Share data with Values

Create Values, insert them with $, and pass data between steps and Runs.

A [Value](/getting-started/terminology) is a named piece of data, such as a username, URL, or order number. The [Value Store](/values/value-store) holds shared Values for your account. Flows can also store data while a Run is in progress.

```mermaid
flowchart TD
  assets["Create Assets Values"] --> insert["Insert with $ in steps"]
  insert --> capture["Store page data during the Run"]
  capture --> overwrite["Overwrite Values per Recipe or CI"]
```

Use the **Flow Builder** for this walkthrough.

![Assets Values list with shared Values](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-035b93746f2336d27bb82e6f37fd9451472ad50f%2Fvalues-store-intro.png?alt=media)

## Create a shared Value

{% stepper %}
{% step %}

## Open Values

Go to **Assets → Values**.
{% endstep %}

{% step %}

## Create the Value

Choose **Create new value**. Set a **Title**, **Type**, and **Value**.

Turn on **Private value** when the content should stay hidden after save. Private Values stay hidden in the UI after you save them.
{% endstep %}
{% endstepper %}

For field detail, see [Creating Values](/values/creating-values).

## Insert a Value in a step

In supported fields, type `$` to open dynamic values. Pick an account Value by **Title**, or a [built-in Value](/values/built-in-values) such as `$testEmail` or `$randomNumber`.

Example: [**Set value**](/test-steps/action/set-value) (Action) on a username field with `$USERNAME` from Assets.

## Capture data during the Run

Use Data Test Steps when the page itself produces the data you need next.

| Test Step                                                           | Use it to                                                        |
| ------------------------------------------------------------------- | ---------------------------------------------------------------- |
| [Set value](/test-steps/data/set-value) (Data)                      | Write a Value into storage under a **Storage Name**              |
| [Store element text](/test-steps/data/store-element-text)           | Save visible text from an [Element](/elements/creating-elements) |
| [Store element value](/test-steps/data/store-element-value)         | Save an input value                                              |
| [Store element attribute](/test-steps/data/store-element-attribute) | Save an attribute                                                |
| [Alias value](/test-steps/data/alias-value)                         | Give an existing storage name a second name                      |

[**Set value**](/test-steps/data/set-value) in the **Data** family writes to storage. [**Set value**](/test-steps/action/set-value) in the **Action** family fills a form field. They share a label and do different jobs.

## Overwrite Values for a Run

| Place                                     | What it does                                        |
| ----------------------------------------- | --------------------------------------------------- |
| [Run Recipes](/configuration/run-recipes) | Save filters and **Value Overwrites** you can reuse |
| Start Run dialog                          | Paste **Value Overwrites** for that Run             |
| [CI / CD](/configuration/ci-cd)           | Pass Values on the webhook request                  |
| [Schedules](/configuration/schedules)     | Choose a Recipe that already includes overwrites    |

Use overwrites for environment URLs, credentials, and other inputs that change per Run without editing the Flow. See [Value Store](/values/value-store) for which source wins when the same name appears more than once.

{% hint style="info" %}
**Pro tip:** Keep environment URLs and credentials as Assets Values or Recipe overwrites, and keep one-off captures from the page in Data storage names. That split makes Flows easier to reuse.
{% endhint %}

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-19d9532ee98a31709c1f639d950ca025f731aace%2Fvalues-capture-flow-approx.png?alt=media" alt="Set value, Store element text, Check text"><figcaption><p>Example capture and reuse path</p></figcaption></figure>

## Related

* [Value Store](/values/value-store)
* [Creating Values](/values/creating-values)
* [Built-in Values](/values/built-in-values)
* [Set value (Data)](/test-steps/data/set-value)
* [Set value (Action)](/test-steps/action/set-value)
* [Store element text](/test-steps/data/store-element-text)
* [Run Recipes](/configuration/run-recipes)
* [CI / CD](/configuration/ci-cd)


# Choose Flow Branch shapes

Choose how Flow Branches join and split when one Flow should cover more than one path.

One [Flow](/getting-started/terminology) can cover several routes through your application. Shared [Test Steps](/getting-started/terminology) stay in one place. A [Flow Branch](/getting-started/terminology) is the join or split that creates those extra paths. Each unique path becomes its own [Test Case](/getting-started/terminology).

Most Flows use a later split: one [Open](/test-steps/starter/open), shared steps, then two or more onward paths. Other shapes help when the same journey should run in more than one browser, or when you want combinations in one Flow.

Use the **Flow Builder** for this walkthrough.

## Pick a shape

| Shape                    | What you build                                 | Use it when                                                             |
| ------------------------ | ---------------------------------------------- | ----------------------------------------------------------------------- |
| **Joined starts**        | Several Opens meet, then share steps           | The same journey should run in more than one browser                    |
| **Later split**          | One Open, then a split lower down              | One start, then two or more onward paths. This is the most common shape |
| **Join then split**      | Several Opens meet, then the Flow splits again | Two browsers, then two or more onward paths                             |
| **Layered combinations** | Join then split more than once                 | You want permutations, such as browser and journey together             |

[Condition](/test-steps/runner/condition) and [Tag Test](/test-steps/utility/tag-test) sit on a branch. They do not change the shape. Use Condition when a path should run only for a matching Runner, device, language, timezone, or Run Value. Use Tag Test when a Recipe, Schedule, or CI/CD call should pick the path by tag.

## Joined starts

Joined starts use more than one [Open](/test-steps/starter/open). The paths meet at a shared step, then continue together.

Use joined starts when the same checks should run in Chrome and Firefox.

![Open Chrome and Open Firefox joining at Touch, then Check displayed](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-dbbc9af31c586e4b434fbea839b9fb079664b5bf%2Fjoined-starts.png?alt=media)

1. Add an [Open](/test-steps/starter/open). Set **Runner** to `Chrome`.
2. Add a second Open with the same URL. Set **Runner** to `Firefox`.
3. Connect both Opens to the same next step, such as [Touch](/test-steps/action/touch).
4. Continue the shared path with [Check Displayed](/test-steps/check/check-displayed).

Each Open still starts its own Test Case. The shared steps run on every path. The same shape works for two starting URLs.

## Later split

A later split is one [Open](/test-steps/starter/open), shared steps, then a split. This is the most common Flow Branch shape.

Use it for smoke versus regression, account versus checkout, or any two journeys that share a start.

```mermaid
flowchart TD
  openChrome["Open Chrome"] --> touchGo["Touch go"]
  touchGo --> checkReady["Check displayed"]
  checkReady --> touchAccount["Touch account"]
  checkReady --> touchCart["Touch cart"]
```

1. Start with one Open. Set **Runner** to `Chrome`.
2. Build the shared steps.
3. Connect the last shared step to two next steps.

See [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage) for tagging those paths.

{% hint style="info" %}
**Pro tip:** Start a multi-path Flow as a later split. Add a second [Open](/test-steps/starter/open) later and set **Runner** to `Firefox` when you need that browser too. That turns it into join then split.
{% endhint %}

## Join then split

Join then split is joined starts plus a later split. [Open](/test-steps/starter/open) in Chrome and Firefox meet, then the Flow splits again.

Use it when both browsers should share some steps, then follow different journeys.

```mermaid
flowchart TD
  openChrome["Open Chrome"] --> touchGo["Touch go"]
  openFirefox["Open Firefox"] --> touchGo
  touchGo --> checkReady["Check displayed"]
  checkReady --> touchAccount["Touch account"]
  checkReady --> touchCart["Touch cart"]
```

1. Build joined starts first: Open Chrome and Open Firefox into one shared [Touch](/test-steps/action/touch).
2. After the shared steps, connect two onward paths.

## Layered combinations

Layered combinations use join then split more than once. Paths meet and split again further down the Flow.

Use this shape when you want permutations in one Flow, such as two browsers, two journeys, and valid versus invalid details.

```mermaid
flowchart TD
  openChrome["Open Chrome"] --> touchGo["Touch go"]
  openFirefox["Open Firefox"] --> touchGo
  touchGo --> touchAccount["Touch account"]
  touchGo --> touchCart["Touch cart"]
  touchAccount --> checkShared["Check displayed"]
  touchCart --> checkShared
  checkShared --> enterValid["Enter valid details"]
  checkShared --> enterInvalid["Enter invalid details"]
```

Each unique path from an Open to an end is a Test Case. Shared steps stay shared, so you edit the common part once.

## Several shapes in one Flow

Flows often mix shapes. The steps stay common so the joins and splits stay easy to see. Open Chrome and Open Firefox are the joined starts.

```mermaid
flowchart TD
  openChrome["Open Chrome"] --> touchNav["Touch nav"]
  openFirefox["Open Firefox"] --> touchNav
  touchNav --> checkHeading["Check heading"]
  checkHeading --> touchAccount["Touch account"]
  checkHeading --> touchCart["Touch cart"]
  touchAccount --> checkProfile["Check profile"]
  touchCart --> checkCart["Check cart"]
  checkCart --> touchPay["Touch pay"]
  checkCart --> checkEmpty["Check empty"]
  touchPay --> checkPaid["Check paid"]
```

What each part is doing:

* Open Chrome and Open Firefox joining at Touch nav are **joined starts**.
* The split after Check heading is a **later split**. Together with the joined starts, that is **join then split**.
* The second split after Check cart is another later split. The Flow now holds joined starts, join then split, and a further split together.

Keep [Open](/test-steps/starter/open) at the start of every path. Use [Touch](/test-steps/action/touch) and [Check Displayed](/test-steps/check/check-displayed) for the steps you care about. Add [Condition](/test-steps/runner/condition) or [Tag Test](/test-steps/utility/tag-test) on a branch when that path needs a rule or a label.

## Related

* [Flow Builder](/platform/flow-builder)
* [DoesQA concepts](/getting-started/doesqa-concepts)
* [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage)
* [Reuse steps with Step Groups](/better-coverage/reuse-steps-with-step-groups)
* [Condition](/test-steps/runner/condition)
* [Tag Test](/test-steps/utility/tag-test)
* [Open](/test-steps/starter/open)
* [Touch](/test-steps/action/touch)
* [Check Displayed](/test-steps/check/check-displayed)
* [Terminology](/getting-started/terminology)


# Build smoke and regression coverage

Tag Flow Branches and use Run Recipes to run smoke or regression coverage.

Smoke coverage is a short path that proves the core journey still works. Regression coverage runs the longer paths. In DoesQA, both can live in one Flow: share the early steps, split with a [Flow Branch](/getting-started/terminology), then mark each path with [**Tag Test**](/test-steps/utility/tag-test). That pattern is usually a later split: one Open, shared steps, then the smoke and regression paths. See [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes).

```mermaid
flowchart TD
  open["Open and shared steps"] --> branch{"Flow Branch"}
  branch --> smoke["Smoke path + Tag Test smoke"]
  branch --> regress["Regression path + Tag Test regression"]
  smoke --> recipe["Run Recipe Include Tags"]
  regress --> recipe
```

Use the **Flow Builder** for this walkthrough.

## What you need

* A Flow with a journey you can split into a short path and a longer path
* Tag names you will reuse in recipes, such as `smoke` and `regression`

## Mark each path with Tag Test

{% stepper %}
{% step %}

## Open the start of the journey

Start with [**Open**](/test-steps/starter/open). Add any shared steps both packs need, such as login.
{% endstep %}

{% step %}

## Add a Flow Branch

Split the Flow so one path stays short (smoke) and another continues into fuller coverage (regression). Shared steps stay above the branch so you maintain them once.
{% endstep %}

{% step %}

## Tag the smoke path

On the short path, add [**Tag Test**](/test-steps/utility/tag-test) from **Utilities**.

Choose or create the `smoke` tag. Finish the path with the checks that prove the core journey.
{% endstep %}

{% step %}

## Tag the regression path

On the longer path, add another [**Tag Test**](/test-steps/utility/tag-test) with the `regression` tag. Continue with the extra steps that pack should own.
{% endstep %}
{% endstepper %}

Each tagged path becomes a [Test Case](/getting-started/terminology). A path can carry more than one tag if you place more than one Tag Test on it.

{% hint style="info" %}
**Pro tip:** **Manual Run Mode** on Tag Test only affects the play button in the Flow Builder. **Ignore Test Case** skips that path on a manual run. Recipe, Schedule, and CI Runs always use your recipe filters instead.
{% endhint %}

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-e3d930de3309765a550bdb7b40279432edbd3bb5%2Fsmoke-tag-flow-approx.png?alt=media" alt="Open, Touch, and Tag Test"><figcaption><p>Example path with Tag Test</p></figcaption></figure>

## Create Run Recipes for each pack

Go to [**Settings → Run Recipes**](/configuration/run-recipes).

{% stepper %}
{% step %}

## Smoke recipe

Create a recipe titled for smoke coverage.

Under **Test Case Filters → Include Tags**, select `smoke`. Leave Flow Filters empty unless you also organise whole Flows with tags.
{% endstep %}

{% step %}

## Regression recipe

Create a second recipe. Under **Test Case Filters → Include Tags**, select `regression`.
{% endstep %}

{% step %}

## Run a pack

Open the recipe and start it with the play control. Only Test Cases that carry every include tag (and none of the exclude tags) run.
{% endstep %}
{% endstepper %}

Include tags mean **all** selected tags must be present. If you set include tags, paths with no matching Tag Test are left out. So a smoke path tagged only `smoke` does not run in a regression recipe unless that path also has the `regression` tag.

## Related

* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [Tag Test](/test-steps/utility/tag-test)
* [Run Recipes](/configuration/run-recipes)
* [Run across environments](/better-coverage/run-across-environments)
* [Schedules](/configuration/schedules)
* [Trigger Runs from CI/CD](/configuration/ci-cd)


# Run across environments

Point the same Flows at staging or production with Values, recipes, and tags.

Most suites need the same journeys on more than one environment. Keep one Flow, drive URLs and credentials with [Values](/values/value-store), then change those Values per Run with a [Run Recipe](/configuration/run-recipes). Use tags only when the journey itself differs between environments.

```mermaid
flowchart TD
  values["Assets Values for URL and credentials"] --> flow["Flow uses dollar Values"]
  flow --> recipe["Recipe overwrites per environment"]
  recipe --> run["Schedule or CI starts the Recipe"]
```

Use the **Flow Builder** for this walkthrough.

## Put environment data in Values

Create [Values](/better-coverage/share-data-with-values) for anything that changes by environment, such as:

* `BASE_URL`
* `USERNAME` and `PASSWORD`
* Feature flags or region codes your steps read

Keep the Flow free of hard-coded staging or production URLs.

## Use those Values in the Flow

{% stepper %}
{% step %}

## Open with the environment URL

Start with [**Open**](/test-steps/starter/open). In the URL field, type `$` and pick `BASE_URL` (or your Value title).
{% endstep %}

{% step %}

## Fill credentials from Values

Add [**Set value**](/test-steps/action/set-value) for username and password fields. Use `$USERNAME` and `$PASSWORD` from the [Value Store](/values/value-store).
{% endstep %}

{% step %}

## Finish the shared journey

Continue with the same steps you would run on every environment.
{% endstep %}
{% endstepper %}

<figure><img src="https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-126d0348f9a98f2e3db3ea205146295879f2d265%2Fenvironments-values-flow-approx.png?alt=media" alt="Open, Set value, and Touch using Values"><figcaption><p>Example Flow driven by environment Values</p></figcaption></figure>

## Overwrite Values per environment

Go to [**Settings → Run Recipes**](/configuration/run-recipes). Create one recipe per environment, or one recipe that iterates over several value sets.

In **Value Overwrites**, replace the defaults for that Run:

```json
{
  "BASE_URL": "https://staging.example.com",
  "USERNAME": "staging_user",
  "PASSWORD": "staging_secret"
}
```

For several environments in one recipe, use an array of objects. Add `primaryValue` so results show which set ran:

```json
[
  {
    "primaryValue": "Staging",
    "BASE_URL": "https://staging.example.com",
    "USERNAME": "staging_user"
  },
  {
    "primaryValue": "Production",
    "BASE_URL": "https://www.example.com",
    "USERNAME": "prod_user"
  }
]
```

{% hint style="info" %}
**Pro tip:** Prefer recipe overwrites for environment URLs and accounts. Tags mark which *paths* run. They do not store credentials or URLs.
{% endhint %}

## When the journey differs by environment

Some steps exist only in one environment, such as a cookie-consent banner on production.

1. After shared setup, add a [Flow Branch](/getting-started/terminology).
2. On each path, add [**Tag Test**](/test-steps/utility/tag-test) with an environment tag, such as `production` or `nonprod`.
3. Put environment-only steps on the matching path.
4. In each recipe, set **Test Case Filters → Include Tags** to that environment tag, and keep the **Value Overwrites** for that environment’s URL and credentials.

For packs that share paths but differ only by data, skip the branch and use overwrites alone. See [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage) for tag and filter detail.

## Related

* [Share data with Values](/better-coverage/share-data-with-values)
* [Run Recipes](/configuration/run-recipes)
* [Tag Test](/test-steps/utility/tag-test)
* [Build smoke and regression coverage](/better-coverage/build-smoke-and-regression-coverage)
* [Reuse a login session](/guides/reuse-a-login-session)


# Add visual checks

Catch visual and layout changes with Vision Test Steps in the Flow Builder.

Vision Test Steps watch what is on screen. Use them when a Check on text or attributes is not enough, such as branding, charts, or layout drift.

Use the **Flow Builder** for this walkthrough.

## Choose the right Vision step

| Test Step                                               | Use it to                                                |
| ------------------------------------------------------- | -------------------------------------------------------- |
| [Element Snapshot](/test-steps/vision/element-snapshot) | Compare the page or an Element to a saved visual control |
| [Element Position](/test-steps/vision/element-position) | Confirm an Element has not moved                         |
| [AI Vision](/test-steps/vision/ai-vision)               | Check a written expectation in plain language            |

Start with [**Element Snapshot**](/test-steps/vision/element-snapshot) for regression on a fixed design. Use [**AI Vision**](/test-steps/vision/ai-vision) when you can describe the outcome more clearly than you can pin a pixel baseline.

## Add an Element Snapshot

{% stepper %}
{% step %}

## Reach the screen you care about

Build the journey with [**Open**](/test-steps/starter/open), [**Touch**](/test-steps/action/touch), and other steps until the page shows the UI you want to protect.
{% endstep %}

{% step %}

## Add Element Snapshot

From the [**Vision**](/test-steps/vision) family, add [**Element Snapshot**](/test-steps/vision/element-snapshot).

1. Set **Mode** to **Element** for one control, or **Page** for the full view.
2. Choose the [Element](/elements/creating-elements) when Mode is **Element**.
3. Set **Acceptable change allowed** if a small difference should still pass.
   {% endstep %}

{% step %}

## Run once to create the control

The first successful Run stores the current look as the control. Later Runs compare against that control.
{% endstep %}

{% step %}

## Read the result

Open the step in the Run result. Review **Control** and **Actual**, and the comparison views between them, to see what changed.
{% endstep %}

{% step %}

## Update the control when the change is intentional

When the new design is correct, use **Update Snapshot Control** on that step in the result so future Runs use the new baseline.
{% endstep %}
{% endstepper %}

## Check position

Add [**Element Position**](/test-steps/vision/element-position) when layout drift matters more than pixels inside the control. Choose the [Element](/elements/creating-elements), run once to establish the control, then compare on later Runs.

## Describe an expectation with AI Vision

Add [**AI Vision**](/test-steps/vision/ai-vision) when you can write what should be true.

1. Set **Mode** to **Page** or **Element**.
2. Choose the Element when Mode is **Element**.
3. Write an **Expectation** in plain language, optionally with [Values](/values/value-store).

{% hint style="info" %}
**Pro tip:** Prefer Mode **Element** for [**AI Vision**](/test-steps/vision/ai-vision) and [**Element Snapshot**](/test-steps/vision/element-snapshot) when the check is about one component. A tighter target keeps failures easier to read.
{% endhint %}

## Related

* [Vision](/test-steps/vision)
* [Element Snapshot](/test-steps/vision/element-snapshot)
* [Element Position](/test-steps/vision/element-position)
* [AI Vision](/test-steps/vision/ai-vision)
* [Choose durable selectors](/better-coverage/choose-durable-selectors)
* [Creating Elements](/elements/creating-elements)
* [Check Text](/test-steps/check/check-text)


# Add accessibility checks

Add Axe, Pa11y, Lighthouse Accessibility, and computed role or label Checks.

Accessibility Checks catch role, label, and WCAG issues in the same journey as your functional steps. Mix page-level Validators with Checks on the controls that matter most.

Use the **Flow Builder** for this walkthrough.

## Choose the right step

| Test Step                                                      | Use it to                                |
| -------------------------------------------------------------- | ---------------------------------------- |
| [Axe](/test-steps/validator/axe)                               | Run a WCAG conformance scan on the page  |
| [Pa11y](/test-steps/validator/pa11y)                           | Run a WCAG conformance scan with Pa11y   |
| [Accessibility](/test-steps/validator/accessibility)           | Assert a Lighthouse accessibility score  |
| [Check computed role](/test-steps/check/check-computed-role)   | Assert the accessible role of an Element |
| [Check computed label](/test-steps/check/check-computed-label) | Assert the accessible name of an Element |

Start with [**Axe**](/test-steps/validator/axe) or [**Pa11y**](/test-steps/validator/pa11y) for a page scan. Add computed role and label Checks on buttons, links, headings, and form fields that users must understand.

## Scan the page

{% stepper %}
{% step %}

## Open the page

Start with [**Open**](/test-steps/starter/open). Continue with [**Touch**](/test-steps/action/touch) and other steps until the screen you want to audit is showing.
{% endstep %}

{% step %}

## Add Axe or Pa11y

From the [**Validator**](/test-steps/validator) family, add [**Axe**](/test-steps/validator/axe) or [**Pa11y**](/test-steps/validator/pa11y).

Set **Conformance Level** to the WCAG level your team expects. Axe defaults to **WCAG 2.1 - AA**.
{% endstep %}

{% step %}

## Optional: assert a Lighthouse score

Add [**Accessibility**](/test-steps/validator/accessibility) when you want a score threshold as well as a conformance scan.

Choose a [Comparison Type](/test-step-options/comparison-type) and a **Value**, such as greater than or equal to `85`.
{% endstep %}
{% endstepper %}

## Check role and label on key Elements

{% stepper %}
{% step %}

## Reach the control

Stay on the same screen, or navigate to the control with Action steps.
{% endstep %}

{% step %}

## Assert computed role

Add [**Check computed role**](/test-steps/check/check-computed-role).

Choose the [Element](/elements/creating-elements), a [Comparison Type](/test-step-options/comparison-type), and the expected role, such as `button` or `link`.
{% endstep %}

{% step %}

## Assert computed label

Add [**Check computed label**](/test-steps/check/check-computed-label) on the same or another Element. Set the expected accessible name, such as `Create account`.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Put accessibility Validators after the screen is fully loaded and after any consent or overlay steps, so the scan sees the same UI a user would.
{% endhint %}

You can add [**Performance**](/test-steps/validator/performance), [**SEO**](/test-steps/validator/seo), and other Lighthouse Validators on the same screen when you want several scores in one journey. See [Test page performance](/better-coverage/test-page-performance) and [Test SEO](/better-coverage/test-seo).

## Related

* [Axe](/test-steps/validator/axe)
* [Pa11y](/test-steps/validator/pa11y)
* [Accessibility](/test-steps/validator/accessibility)
* [Check computed role](/test-steps/check/check-computed-role)
* [Check computed label](/test-steps/check/check-computed-label)
* [Test page performance](/better-coverage/test-page-performance)
* [Test SEO](/better-coverage/test-seo)
* [Add visual checks](/better-coverage/add-visual-checks)
* [Choose durable selectors](/better-coverage/choose-durable-selectors)


# Test page performance

Assert a Lighthouse performance score on a page in your Flow.

Performance Checks score the page with Lighthouse while the journey is already open. Use them on key screens so slow loads fail the Run the same way a broken button would.

Use the **Flow Builder** for this walkthrough.

## Add a Performance Check

{% stepper %}
{% step %}

## Open the page

Start with [**Open**](/test-steps/starter/open). Continue with [**Touch**](/test-steps/action/touch) and other steps until the screen you care about is showing.
{% endstep %}

{% step %}

## Add Performance

From the [**Validator**](/test-steps/validator) family, add [**Performance**](/test-steps/validator/performance).

1. Choose a [Comparison Type](/test-step-options/comparison-type). The default is greater than or equal to.
2. Set **Value** to the score your team expects. The default is `85`.
   {% endstep %}

{% step %}

## Run and read the result

Start the Run. Open the Performance step in the result to see the score against your threshold.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Put Performance after the page has finished loading and after any login or consent steps. A score on a half-loaded screen is hard to trust.
{% endhint %}

You can add [**SEO**](/test-steps/validator/seo), [**Accessibility**](/test-steps/validator/accessibility), and other Lighthouse Validators on the same screen when you want several scores in one journey. See [Add accessibility checks](/better-coverage/add-accessibility-checks) and [Test SEO](/better-coverage/test-seo).

## Related

* [Performance](/test-steps/validator/performance)
* [SEO](/test-steps/validator/seo)
* [Accessibility](/test-steps/validator/accessibility)
* [Best Practices](/test-steps/validator/best-practices)
* [Add accessibility checks](/better-coverage/add-accessibility-checks)
* [Test SEO](/better-coverage/test-seo)


# Test SEO

Assert a Lighthouse SEO score on a page in your Flow.

SEO Checks score the page with Lighthouse during the Run. Use them on landing pages, marketing pages, and other screens where search readiness matters alongside the functional journey.

Use the **Flow Builder** for this walkthrough.

## Add an SEO Check

{% stepper %}
{% step %}

## Open the page

Start with [**Open**](/test-steps/starter/open). Navigate to the page you want to score if it is not the first screen.
{% endstep %}

{% step %}

## Add SEO

From the [**Validator**](/test-steps/validator) family, add [**SEO**](/test-steps/validator/seo).

1. Choose a [Comparison Type](/test-step-options/comparison-type). The default is greater than or equal to.
2. Set **Value** to the score your team expects. The default is `85`.
   {% endstep %}

{% step %}

## Run and read the result

Start the Run. Open the SEO step in the result to compare the score with your threshold.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
**Pro tip:** Pair SEO with [**Check links**](/test-steps/check/check-links) on the same page when broken links are part of what you want to catch. See [Check links](/better-coverage/check-links).
{% endhint %}

## Related

* [SEO](/test-steps/validator/seo)
* [Performance](/test-steps/validator/performance)
* [Accessibility](/test-steps/validator/accessibility)
* [Check links](/better-coverage/check-links)
* [Test page performance](/better-coverage/test-page-performance)
* [Add accessibility checks](/better-coverage/add-accessibility-checks)


# Check links

Find broken or failing links on a page or inside an Element.

Broken links waste journeys and hide content. [**Check links**](/test-steps/check/check-links) requests the links on the page (or inside an Element) and fails when their responses do not match the status rule you set.

Use the **Flow Builder** for this walkthrough.

## Add Check links

{% stepper %}
{% step %}

## Open the page

Start with [**Open**](/test-steps/starter/open). Continue until every link you want checked is on screen.
{% endstep %}

{% step %}

## Add Check links

From the [**Check**](/test-steps/check) family, add [**Check links**](/test-steps/check/check-links).

1. Set **Links Types** to **All Links**, **Internal**, or **External**.
2. Set **Target Area** to **Entire Page**, or **Inside Element** when you only want links in one region (choose the [Element](/elements/creating-elements)).
3. Set **Status** to the rule that should pass. The default is **No Errors (400-599)**.
   {% endstep %}

{% step %}

## Run and review failures

Start the Run. Open the step in the result to see which links failed the status rule.
{% endstep %}
{% endstepper %}

### Status options

| Status                     | Passes when                                         |
| -------------------------- | --------------------------------------------------- |
| All OK (200)               | Every link returns `200`                            |
| All Successful (200-299)   | Every link returns a `2xx` response                 |
| No 404 Errors              | No link returns `404`                               |
| No 400 or 404 Errors       | No link returns `400` or `404`                      |
| No Client Errors (400-499) | No link returns a `4xx` response                    |
| No Server Errors (500-599) | No link returns a `5xx` response                    |
| No Errors (400-599)        | No link returns a `4xx` or `5xx` response (default) |

{% hint style="info" %}
**Pro tip:** Use **Inside Element** on nav, footer, or a content block when the full page has third-party links you do not own.
{% endhint %}

## Related

* [Check links](/test-steps/check/check-links)
* [Test SEO](/better-coverage/test-seo)
* [Test page performance](/better-coverage/test-page-performance)
* [Choose durable selectors](/better-coverage/choose-durable-selectors)


# Starter

Open a browser and start every Flow with the Starter Test Step.

Every Flow begins with a Starter Test Step. It opens the browser, loads the first URL, and sets the starting point for the journey that follows.

## Test Steps in this family

| Test Step                        | Use it to                                      |
| -------------------------------- | ---------------------------------------------- |
| [Open](/test-steps/starter/open) | Start the Flow on a URL and choose the browser |

Open is always the first Test Step. Add Browser, Action, and Check steps after it to cover the rest of the journey.


# Open

Open a URL to start every Test Case, and choose the browser or Simulated Device.

Open is the first [Test Step](/getting-started/terminology) in every Flow. It starts the browser (or [Simulated Device](/getting-started/terminology)), loads your URL, and sets the environment for every step that follows.

Use Open when a Test Case needs a fresh page. Use [Go to absolute URL](/test-steps/browser/go-to-absolute-url) or [Go to relative path](/test-steps/browser/go-to-relative-path) later in the Flow when you need to move to another address without restarting the browser.

![Open Test Step](https://app.does.qa/screenshots/node/starter_open.png)

## When to use it

* Start every Flow with Open so each Test Case has a clear entry URL.
* Choose **Simulated Device** when you need a named phone or tablet preset (viewport, user agent, and touch).
* Prefer Chrome, Firefox, or Edge with a Desktop or Tablet Variant for ordinary desktop and tablet layouts.

## Configure

### Basics

| Field       | What to set                                                                                         |
| ----------- | --------------------------------------------------------------------------------------------------- |
| **URL**     | Fully qualified address, or a [Value](/values/value-store) that expands to one                      |
| **Runner**  | `Chrome` (default), `Firefox`, `Edge`, or `Simulated Device`                                        |
| **Variant** | Desktop and tablet sizes for Chrome/Firefox/Edge, or a named device when Runner is Simulated Device |

### Advanced

| Field                       | What to set                                          |
| --------------------------- | ---------------------------------------------------- |
| **Language**                | Browser language for the session                     |
| **Timezone**                | Timezone for the session (`UTC` by default)          |
| **Throttle**                | Network speed simulation, or `No throttle` (default) |
| **Basic Auth**              | Turn on when the site needs HTTP Basic Auth          |
| **Username** / **Password** | Credentials when Basic Auth is on (supports Values)  |
| **Authentication Mode**     | `URL` or `Header` for how Basic Auth is applied      |
| **Headers**                 | Extra request headers as JSON                        |

{% hint style="info" %}
**Pro tip:** Keep environment hosts in Assets Values (for example `$BASE_URL`) so one Flow can target staging and production without editing Open each time.
{% endhint %}

## Related

* [Simulated Device](/getting-started/terminology)
* [Whitelisting IPs](/configuration/whitelisting-ips)
* [Go to absolute URL](/test-steps/browser/go-to-absolute-url)
* [Condition](/test-steps/runner/condition)
* [Choose Flow Branch shapes](/better-coverage/choose-flow-branch-shapes)
* [Starter](/test-steps/starter)

**Tags:** `starter`, `open`, `goto`, `browser`, `navigate`, `simulated device`


# Browser

Move between pages, tabs, and files, or run custom browser script during a Flow.

Browser Test Steps control navigation inside the open browser. Use them when the journey needs a new URL, a reload, another tab, or a short script in the page.

## Navigate

| Test Step                                                      | Use it to                     |
| -------------------------------------------------------------- | ----------------------------- |
| [Go To Absolute URL](/test-steps/browser/go-to-absolute-url)   | Open a full URL               |
| [Go To Relative Path](/test-steps/browser/go-to-relative-path) | Move within the current site  |
| [Reload](/test-steps/browser/reload)                           | Refresh the current page      |
| [Back](/test-steps/browser/back)                               | Go back in browser history    |
| [Forward](/test-steps/browser/forward)                         | Go forward in browser history |

## Tabs and files

| Test Step                                                  | Use it to                        |
| ---------------------------------------------------------- | -------------------------------- |
| [Next Tab](/test-steps/browser/next-tab)                   | Switch to the next tab           |
| [Previous Tab](/test-steps/browser/previous-tab)           | Switch to the previous tab       |
| [Close Current Tab](/test-steps/browser/close-current-tab) | Close the tab you are on         |
| [Open File](/test-steps/browser/open-file)                 | Open a local file in the browser |

## Custom script

| Test Step                                                    | Use it to                                  |
| ------------------------------------------------------------ | ------------------------------------------ |
| [Run Browser Script](/test-steps/browser/run-browser-script) | Run JavaScript in the page during the Flow |


# Go To Absolute URL

Navigate the browser to a full URL.

Go To Absolute URL loads a full address in the active browser. Use it when the Flow must leave the current site or open a specific environment URL mid-journey.

For the first step in every Test Case, use [Open](/test-steps/starter/open) instead.

![Go to absolute url Test Step](https://app.does.qa/screenshots/node/action_goTo_absolute.png)

## When to use it

* Jump to an admin console, partner site, or deep link after login on another host.
* Open staging or production using a [Value](/values/value-store) for the host.
* Prefer [Go to relative path](/test-steps/browser/go-to-relative-path) when the path stays on the same origin as the current page.

## Configure

### Basics

| Field   | What to set                                                                    |
| ------- | ------------------------------------------------------------------------------ |
| **URL** | Fully qualified address, or a [Value](/values/value-store) that expands to one |

### Advanced

| Field                                 | What to set                                               |
| ------------------------------------- | --------------------------------------------------------- |
| **Basic Auth**                        | Turn on when the destination needs HTTP Basic Auth        |
| **Username** / **Password**           | Credentials when Basic Auth is on (supports Values)       |
| **Authentication Mode**               | `URL` (default) or `Header` for how Basic Auth is applied |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)         |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`                       |

{% hint style="info" %}
**Pro tip:** Keep environment hosts in Asset Values (for example `$BASE_URL`) so one Flow can target staging and production without editing each navigation step.
{% endhint %}

## Related

* [Go to relative path](/test-steps/browser/go-to-relative-path)
* [Open](/test-steps/starter/open)
* [Browser](/test-steps/browser)

**Tags:** `action`, `goTo`, `absolute`, `goto`, `go`, `to`, `path`, `browser`, `open`, `navigate`, `website`


# Go To Relative Path

Navigate the browser to a path on the current site.

Go To Relative Path loads a path on the same origin as the current page. Use it for in-site navigation without repeating the full host name.

For the first step in every Test Case, use [Open](/test-steps/starter/open) instead.

![Go to relative path Test Step](https://app.does.qa/screenshots/node/action_goTo_relative.png)

## When to use it

* Open `/account`, `/checkout`, or another app route after login.
* Follow internal links using a [Value](/values/value-store) for dynamic paths.
* Prefer [Go to absolute URL](/test-steps/browser/go-to-absolute-url) when the Flow must leave the current host.

## Configure

### Basics

| Field    | What to set                                                                 |
| -------- | --------------------------------------------------------------------------- |
| **Path** | Relative path (for example `/dashboard`), or a [Value](/values/value-store) |

### Advanced

| Field                                 | What to set                                               |
| ------------------------------------- | --------------------------------------------------------- |
| **Basic Auth**                        | Turn on when the destination needs HTTP Basic Auth        |
| **Username** / **Password**           | Credentials when Basic Auth is on (supports Values)       |
| **Authentication Mode**               | `URL` (default) or `Header` for how Basic Auth is applied |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)         |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`                       |

## Related

* [Go to absolute URL](/test-steps/browser/go-to-absolute-url)
* [Open](/test-steps/starter/open)
* [Browser](/test-steps/browser)

**Tags:** `action`, `goTo`, `relative`, `goto`, `go`, `to`, `path`, `browser`, `open`, `navigate`, `website`


# Reload

Reload the current page in the browser.

Reload refreshes the current page in the browser. Use it when the Flow must re-fetch the same URL after a background change or to confirm state survives a refresh.

![Reload Test Step](https://app.does.qa/screenshots/node/action_goTo_reload.png)

## When to use it

* Confirm data persists after the user refreshes the page.
* Re-load the current URL after a step that updates content outside the visible UI.
* Prefer [Back](/test-steps/browser/back) or [Forward](/test-steps/browser/forward) when the journey should use browser history instead of a full refresh.

## Configure

### Basics

This step has no required fields. It reloads the active page.

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

## Related

* [Back](/test-steps/browser/back)
* [Forward](/test-steps/browser/forward)
* [Browser](/test-steps/browser)

**Tags:** `action`, `goTo`, `reload`, `refresh`, `f5`, `browser`, `open`, `navigate`, `website`


# Back

Navigate back.

Back moves the browser one step back in history, like the browser back button. Use it when the Flow should return to a previous page without reloading the current URL.

![Back Test Step](https://app.does.qa/screenshots/node/action_goTo_back.png)

## When to use it

* Return to a list page after viewing a detail page opened from it.
* Undo a navigation step and confirm the earlier page still shows expected state.
* Prefer [Reload](/test-steps/browser/reload) when the same URL should refresh instead of using history.

## Configure

### Basics

This step has no required fields. It navigates back in browser history.

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

## Related

* [Forward](/test-steps/browser/forward)
* [Reload](/test-steps/browser/reload)
* [Browser](/test-steps/browser)

**Tags:** `action`, `goTo`, `back`, `refresh`, `browser`, `open`, `navigate`, `website`


# Forward

Navigate forward.

Forward moves the browser one step forward in history, like the browser forward button. Use it after [Back](/test-steps/browser/back) when the Flow should return to a page the user had already visited.

![Forward Test Step](https://app.does.qa/screenshots/node/action_goTo_forward.png)

## When to use it

* Revisit a detail page after stepping back to a list.
* Continue a multi-page journey that relies on browser history order.
* Prefer [Reload](/test-steps/browser/reload) when the current URL should refresh instead of using history.

## Configure

### Basics

This step has no required fields. It navigates forward in browser history.

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

## Related

* [Back](/test-steps/browser/back)
* [Reload](/test-steps/browser/reload)
* [Browser](/test-steps/browser)

**Tags:** `action`, `goTo`, `forward`, `refresh`, `browser`, `open`, `navigate`, `website`


# Open File

Open a downloaded or generated file in the browser.

Open file loads a file into the browser tab. Use it after a download or [Generate file](/test-steps/runner/generate-file) when the journey needs to view or assert on the file itself.

![Open file Test Step](https://app.does.qa/screenshots/node/browser_open_file.png)

## When to use it

* Open the last download after a save or export on the page.
* Open a file created with [Generate file](/test-steps/runner/generate-file).
* Prefer [File](/test-steps/action/file) when the app expects an upload into a file input instead.

## Example Flow

Generate the file, then open it in the browser.

![Generate file then Open file](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-15c43a83cfca5f584ea254c46ea91c3c7e6b6aa6%2Fgenerate-file-open-miniflow-approx.png?alt=media)

## Configure

### Basics

| Field              | What to set                                     |
| ------------------ | ----------------------------------------------- |
| **File**           | `Last Downloaded` (default) or `Generated File` |
| **Generated File** | The generated file when File is Generated File  |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

{% hint style="info" %}
**Pro tip:** Place Open file after the download or generate step in the same Test Case so Last Downloaded or Generated File points at the right content.
{% endhint %}

## Related

* [Generate file](/test-steps/runner/generate-file)
* [File](/test-steps/action/file)
* [Test file uploads and downloads](/guides/test-file-uploads-and-downloads)
* [Browser](/test-steps/browser)

**Tags:** `browser`, `open`, `file`


# Run Browser Script

Run JavaScript in the browser during a Test Case.

Run browser script executes custom JavaScript in the page. Use it when you need logic the built-in steps do not cover, such as a calculation, a DOM read, or a small helper.

Read Values with `VALUES.yourKey` inside the script. The `$` picker works in other Test Step fields. The script field is JavaScript, so use the `VALUES` object instead.

![Run browser script Test Step](https://app.does.qa/screenshots/node/browser_script.png)

## When to use it

* **Store** mode saves the script return value under **Response Storage Name** for later steps.
* **Check** mode asserts the script result as part of the step outcome.
* Prefer built-in Action and Check steps when they already cover the job.

## Configure

### Basics

| Field                     | What to set                                                        |
| ------------------------- | ------------------------------------------------------------------ |
| **Label**                 | Optional label shown in results                                    |
| **JavaScript**            | The script to run. Use `VALUES.key` for stored Values              |
| **Mode**                  | `Store` (default) or `Check`                                       |
| **Response Storage Name** | Where to save the return value in Store mode (`output` by default) |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |

{% hint style="info" %}
**Pro tip:** If a Value looks empty in the script, confirm an earlier step wrote that storage name and that you used `VALUES.yourKey`, not `$yourKey`.
{% endhint %}

## Related

* [Value Store](/values/value-store)
* [Share data with Values](/better-coverage/share-data-with-values)
* [Browser](/test-steps/browser)

**Tags:** `browser`, `script`, `javascript`, `VALUES`


# Next Tab

Switch to the next browser tab.

Next Tab activates the tab to the right of the current one in the browser. Use it when a link or action opened a new tab and the Flow should continue there.

![Next tab Test Step](https://app.does.qa/screenshots/node/browser_tab_next.png)

## When to use it

* Follow a link that opens in a new tab, then switch to that tab for later steps.
* Move through several open tabs in order during a checkout or admin workflow.
* Pair with [Previous Tab](/test-steps/browser/previous-tab) to move between tabs without closing them.

## Configure

### Basics

This step has no required fields. It switches to the next tab in the tab strip.

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Previous Tab](/test-steps/browser/previous-tab)
* [Close Current Tab](/test-steps/browser/close-current-tab)
* [Browser](/test-steps/browser)

**Tags:** `browser`, `tab`, `next`


# Previous Tab

Switch to the previous browser tab.

Previous Tab activates the tab to the left of the current one in the browser. Use it to return to an earlier tab after working in a newly opened tab.

![Previous tab Test Step](https://app.does.qa/screenshots/node/browser_tab_previous.png)

## When to use it

* Return to the original tab after verifying content in a new tab.
* Step back through open tabs during a multi-window workflow.
* Pair with [Next Tab](/test-steps/browser/next-tab) to move between tabs without closing them.

## Configure

### Basics

This step has no required fields. It switches to the previous tab in the tab strip.

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Next Tab](/test-steps/browser/next-tab)
* [Close Current Tab](/test-steps/browser/close-current-tab)
* [Browser](/test-steps/browser)

**Tags:** `browser`, `tab`, `previous`


# Close Current Tab

Close the current browser tab.

Close Current Tab closes the active browser tab. Use it after verifying a popup or secondary tab when the Flow should continue on a tab that remains open.

![Close current tab Test Step](https://app.does.qa/screenshots/node/browser_tab_close.png)

## When to use it

* Dismiss a confirmation or receipt tab opened during checkout.
* Clean up extra tabs before the runner moves to the next Test Case.
* Switch to another tab with [Next Tab](/test-steps/browser/next-tab) or [Previous Tab](/test-steps/browser/previous-tab) first if the Flow should continue elsewhere.

## Configure

### Basics

This step has no required fields. It closes the tab that is currently active.

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Next Tab](/test-steps/browser/next-tab)
* [Previous Tab](/test-steps/browser/previous-tab)
* [Browser](/test-steps/browser)

**Tags:** `browser`, `tab`, `close`


# Action

Click, type, upload, scroll, and interact with Elements on the page.

Action Test Steps do what a user does on the page. They click, type, clear fields, upload files, hover, scroll, and handle MFA inputs.

Most Actions use an [Element](/elements/creating-elements) to find the control on the page.

## Click and pointer

| Test Step                                           | Use it to                           |
| --------------------------------------------------- | ----------------------------------- |
| [Touch](/test-steps/action/touch)                   | Click or tap an Element or position |
| [Double Tap](/test-steps/action/double-tap)         | Double-click an Element or position |
| [Touch and Hold](/test-steps/action/touch-and-hold) | Press and hold                      |
| [Touch Release](/test-steps/action/touch-release)   | Release after a hold                |
| [Hover](/test-steps/action/hover)                   | Move the pointer over an Element    |
| [Drag and Drop](/test-steps/action/drag-and-drop)   | Drag one Element onto another       |

## Type and fill

| Test Step                                         | Use it to                            |
| ------------------------------------------------- | ------------------------------------ |
| [Send Keys](/test-steps/action/send-keys)         | Type text or keyboard shortcuts      |
| [Set Value](/test-steps/action/set-value)         | Set an input value directly          |
| [Clear](/test-steps/action/clear)                 | Clear an input                       |
| [Select Option](/test-steps/action/select-option) | Choose an option in a dropdown       |
| [Set MFA](/test-steps/action/set-mfa)             | Fill an MFA field with a valid token |

## Files, scroll, and extras

| Test Step                                               | Use it to                                  |
| ------------------------------------------------------- | ------------------------------------------ |
| [File](/test-steps/action/file)                         | Upload a file                              |
| [Scroll Into View](/test-steps/action/scroll-into-view) | Bring an Element into view                 |
| [Scroll To Edge](/test-steps/action/scroll-to-edge)     | Scroll a page or Element to an edge        |
| [Scan](/test-steps/action/scan)                         | Read a QR code from an Element             |
| [Open Plugin](/test-steps/action/open-plugin)           | Install and open a Chrome Web Store plugin |


# Touch

Click or tap an Element or screen position.

Touch clicks or taps a control. Use it for buttons, links, checkboxes, and other interactive [Elements](/elements/creating-elements). Touch waits for the Element to be ready, scrolls it into view, then clicks.

Prefer Element mode for durable Flows. Use position mode only when the target has no stable Element yet.

![Touch Test Step](https://app.does.qa/screenshots/node/action_touch_single.png)

## When to use it

* Click a button, link, or other control after you have defined an Element.
* Open a mobile menu before a later step when the control is hidden on a small viewport.
* Use **Mode Event** when an overlay sits over the Element.

For hover menus, use [Hover](/test-steps/action/hover) first. For holding a press, use [Touch and Hold](/test-steps/action/touch-and-hold).

## Configure

### Basics

| Field             | What to set                                       |
| ----------------- | ------------------------------------------------- |
| **Type**          | `Element` (default) or `position`                 |
| **Element**       | The Element to click (Element type)               |
| **Position Type** | `Percentage` (default) or `Pixel` (position type) |
| **X** / **Y**     | Where to click when Type is position              |

### Advanced

| Field                                 | What to set                                                                                                                          |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Modifiers**                         | Optional `Shift`, `Ctrl`, `Windows`, or `Alt` held during the click                                                                  |
| **Mode**                              | `Area` (default) clicks the visible target area. `Event` sends the click to the Element directly, which helps with stubborn overlays |
| **X Offset** / **Y Offset**           | Fine-tune the click point on the Element (`Center` by default)                                                                       |
| **How fast is this typically?**       | [Timeout Override](/test-step-options/timeout-override) (`Fast`, `Slow`, `Very Slow`)                                                |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                                                                                    |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`                                                                                                  |

{% hint style="info" %}
**Pro tip:** You usually do not need a Wait or Scroll before Touch. Touch already waits for the Element and scrolls it to the centre before clicking.
{% endhint %}

## Related

* [Double Tap](/test-steps/action/double-tap)
* [Hover](/test-steps/action/hover)
* [Touch and Hold](/test-steps/action/touch-and-hold)
* [Element states](/test-step-options/element-states)
* [Action](/test-steps/action)

**Tags:** `action`, `touch`, `click`, `tap`, `mouse`


# Double Tap

Double Tap (double click) and element or position.

Double Tap sends two quick clicks or taps to an [Element](/elements/creating-elements) or screen position. Use it for controls that respond to a double click, such as opening a file or zooming a map tile.

![Double Tap Test Step](https://app.does.qa/screenshots/node/action_touch_double.png)

## When to use it

* Open an item that requires a double click in the desktop browser.
* Trigger a mobile gesture mapped to a double tap on a control.
* Prefer [Touch](/test-steps/action/touch) for a single click. Use **Mode Event** when an overlay blocks Area mode.

## Configure

### Basics

| Field                             | What to set                                                             |
| --------------------------------- | ----------------------------------------------------------------------- |
| **Type** *(conditional)*          | `Element` (default) or `position`                                       |
| **Element**                       | The [Element](/elements/creating-elements) to double tap (Element type) |
| **Position Type** *(conditional)* | `Percentage` (default) or `Pixel` (position type)                       |
| **X** *(conditional)*             | `Left Edge` or horizontal position when Type is position                |
| **Y** *(conditional)*             | `Top Edge` or vertical position when Type is position                   |
| **Mode**                          | `Area` (default) or `Event`                                             |

### Advanced

| Field                        | What to set                                            |
| ---------------------------- | ------------------------------------------------------ |
| **Modifiers**                | Optional `Shift`, `Ctrl`, `Windows`, or `Alt`          |
| **X Offset** *(conditional)* | Fine-tune horizontal click point (`Center` by default) |
| **Y Offset** *(conditional)* | Fine-tune vertical click point (`Center` by default)   |
| **Status on fail**           | [Failed Status](/test-step-options/failed-status)      |

## Related

* [Touch](/test-steps/action/touch)
* [Hover](/test-steps/action/hover)
* [Touch and Hold](/test-steps/action/touch-and-hold)
* [Touch Release](/test-steps/action/touch-release)
* [Action](/test-steps/action)

**Tags:** `action`, `touch`, `double`, `click`, `mouse`, `tap`


# Drag and Drop

Drag an Element and drop it onto another Element.

Drag and drop moves one Element onto another. Use it for kanban cards, sortable lists, upload dropzones, and other drag targets.

![Drag and drop Test Step](https://app.does.qa/screenshots/node/action_dragDrop.png)

## When to use it

* Drag a card or row onto a dropzone Element.
* Reorder items when the app supports HTML5-style drag and drop.

## Configure

### Basics

| Field        | What to set              |
| ------------ | ------------------------ |
| **Element**  | The Element to drag      |
| **Dropzone** | The Element to drop onto |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

## Related

* [Touch](/test-steps/action/touch)
* [Action](/test-steps/action)

**Tags:** `action`, `dragDrop`, `drag`, `drop`


# Clear

Clear the text in an input Element.

Clear removes the current value from an input. Use it before [Set value](/test-steps/action/set-value) when the field may already contain text, or when you need an empty field for the next assertion.

![Clear Test Step](https://app.does.qa/screenshots/node/action_input_clearValue.png)

## When to use it

* Empty a search box or form field before typing a new value.
* Prefer the **Clear Value** option on Set value when you clear and type in one step.

## Configure

### Basics

| Field       | What to set                                               |
| ----------- | --------------------------------------------------------- |
| **Element** | The input [Element](/elements/creating-elements) to clear |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

## Related

* [Set value](/test-steps/action/set-value)
* [Send keys](/test-steps/action/send-keys)
* [Action](/test-steps/action)

**Tags:** `action`, `input`, `clear`, `clearValue`


# File

Upload a file into a file input Element.

File chooses a file and uploads it through a file input on the page. Use it after you have downloaded or generated the file you need in an earlier step.

![File Test Step](https://app.does.qa/screenshots/node/action_input_file.png)

## When to use it

* Upload a file the Flow just downloaded.
* Upload a file created with [Generate file](/test-steps/runner/generate-file).
* Pair with [Open file](/test-steps/browser/open-file) when you need to open a downloaded file in the browser instead of uploading it.

## Example Flow

Generate a file, then upload it with File.

![Generate file then File upload](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-3368a183a473b28f3db0fa174f46b355c4b55d39%2Fgenerate-file-upload-miniflow-approx.png?alt=media)

## Configure

### Basics

| Field              | What to set                                              |
| ------------------ | -------------------------------------------------------- |
| **Element**        | The file input [Element](/elements/creating-elements)    |
| **File**           | `Last Downloaded` (default) or `Generated File`          |
| **Generated File** | The generated file to upload when File is Generated File |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

{% hint style="info" %}
**Pro tip:** Download or generate the file in an earlier step in the same Test Case so Last Downloaded or Generated File points at the right content.
{% endhint %}

## Related

* [Generate file](/test-steps/runner/generate-file)
* [Open file](/test-steps/browser/open-file)
* [Test file uploads and downloads](/guides/test-file-uploads-and-downloads)
* [Action](/test-steps/action)

**Tags:** `action`, `input`, `file`, `upload`


# Select Option

Choose an option in a select Element by value, text, or index.

Select option chooses an item in a native `<select>` control. Use it when the field is a real select element. For custom dropdowns built from buttons and lists, use [Touch](/test-steps/action/touch) on the trigger and the option instead.

![Select option Test Step](https://app.does.qa/screenshots/node/action_input_selectOption.png)

## When to use it

* Set a country, status, or other native select field.
* Prefer selecting by **Value** or **Visible Text** over Index when the option text is stable.

## Configure

### Basics

| Field               | What to set                                              |
| ------------------- | -------------------------------------------------------- |
| **Element**         | The select [Element](/elements/creating-elements)        |
| **Selection Mode**  | `Auto` (default), `Value`, `Text`, `Element`, or `Index` |
| **Value**           | Option value when Selection Mode is Value or Auto        |
| **Visible Text**    | Option label when Selection Mode is Text                 |
| **Element**         | Option Element when Selection Mode is Element            |
| **Index (0-based)** | Option index when Selection Mode is Index                |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

{% hint style="info" %}
**Pro tip:** If Touch on a custom dropdown is unreliable, check whether the control is a native select first. Select option is simpler when it is.
{% endhint %}

## Related

* [Touch](/test-steps/action/touch)
* [Set value](/test-steps/action/set-value)
* [Action](/test-steps/action)

**Tags:** `action`, `input`, `selectOption`, `select`, `dropdown`


# Send Keys

Send keyboard keys, including special keys such as Enter and Tab.

Send keys presses keyboard keys in the browser. Use it for shortcuts and special keys such as Enter, Tab, or Escape. Prefer [Set value](/test-steps/action/set-value) when you only need to fill an input with text.

![Send keys Test Step](https://app.does.qa/screenshots/node/action_input_sendKeys.png)

## When to use it

* Submit a form with Enter after Set value.
* Move focus with Tab, or dismiss a dialog with Escape.
* Hold modifiers such as Ctrl or Shift for shortcuts.

## Configure

### Basics

| Field       | What to set                                                                                    |
| ----------- | ---------------------------------------------------------------------------------------------- |
| **Focus**   | `Element focus` (default) focuses the Element first. `Retain current` leaves focus where it is |
| **Element** | Required when Focus is Element focus                                                           |
| **Keys**    | Keys to send (supports special key tokens in the field)                                        |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Modifiers**                         | Optional `Shift`, `Ctrl`, `Windows`, or `Alt`     |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

{% hint style="info" %}
**Pro tip:** Use Set value for the text, then Send keys with Enter when the app submits on keyboard rather than a button click.
{% endhint %}

## Related

* [Set value](/test-steps/action/set-value)
* [Clear](/test-steps/action/clear)
* [Touch](/test-steps/action/touch)
* [Action](/test-steps/action)

**Tags:** `action`, `input`, `sendKeys`, `keyboard`, `keys`


# Set MFA

Type a time-based MFA code into an Element.

Set MFA generates a one-time code and types it into an input. Use it for login and challenge screens that ask for an authenticator code.

Prefer **Saved** mode with an MFA entry from **Settings → MFA**. Use **New** only when the secret belongs to this step alone.

![Set MFA Test Step](https://app.does.qa/screenshots/node/action_input_setMFA.png)

## When to use it

* Complete MFA after username and password on a login Flow.
* Reuse a saved MFA key across Flows so secrets stay in one place.

For a full walkthrough, see [Test MFA login](/guides/test-mfa-login).

## Example Flow

Open the login page, enter credentials, type the MFA code, then continue.

![Open, Set value, Set MFA, and Touch](https://2973996442-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FH10EEO19EDpBHNPowThh%2Fuploads%2Fgit-blob-512f2770558e4391e106e75e4a242d8d73d243d3%2Fmfa-miniflow-approx.png?alt=media)

## Configure

### Basics

| Field       | What to set                                                                       |
| ----------- | --------------------------------------------------------------------------------- |
| **Mode**    | `Saved` (default) uses an MFA key from Settings. `New` uses a Secret on this step |
| **MFA Key** | The saved MFA entry (Saved mode)                                                  |
| **Secret**  | The MFA secret string (New mode)                                                  |
| **Element** | The code input [Element](/elements/creating-elements)                             |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

{% hint style="info" %}
**Pro tip:** After MFA login works, save the steps as a [Step Group](/better-coverage/reuse-steps-with-step-groups) so other Flows reuse the same path.
{% endhint %}

## Related

* [MFA](/configuration/mfa)
* [Test MFA login](/guides/test-mfa-login)
* [Set value](/test-steps/action/set-value)
* [Action](/test-steps/action)

**Tags:** `action`, `input`, `mfa`, `totp`, `otp`


# Open Plugin

Install and open plugins from the Chrome Plugin Web Store.

Open Plugin installs a Chrome extension from the Chrome Web Store URL and opens it in the runner browser. Use it when the Flow depends on a browser plugin that is not pre-installed on the runner.

![Open plugin Test Step](https://app.does.qa/screenshots/node/action_open_plugin.png)

{% hint style="warning" %}
This Test Step runs on Chrome runners.
{% endhint %}

## When to use it

* Load a password manager, accessibility, or testing extension before the main Flow steps.
* Verify behaviour that only appears when a specific Chrome plugin is active.
* Place this step early in the Flow so later steps can rely on the plugin being available.

## Configure

### Basics

| Field                           | What to set                                     |
| ------------------------------- | ----------------------------------------------- |
| **Chrome Plugin Web Store URL** | Full Web Store URL for the extension to install |

### Advanced

| Field              | What to set                                       |
| ------------------ | ------------------------------------------------- |
| **Status on fail** | [Failed Status](/test-step-options/failed-status) |

## Related

* [Touch](/test-steps/action/touch)
* [Action](/test-steps/action)

**Tags:** `action`, `open`, `plugin`, `click`, `mouse`, `tap`


# Scroll Into View

Scroll into view

Scroll Into View brings an [Element](/elements/creating-elements) into the visible viewport. Use it when a control sits below the fold or inside a scrollable panel and later steps need it on screen.

![Scroll into view Test Step](https://app.does.qa/screenshots/node/action_scroll_intoView.png)

## When to use it

* Reveal a footer link or long-form field before a [Touch](/test-steps/action/touch) step.
* Scroll a row into view inside a nested table or modal panel.
* Set **Parent Element** when the target lives inside a scrollable container rather than the main page.

## Configure

### Basics

| Field                              | What to set                                                                           |
| ---------------------------------- | ------------------------------------------------------------------------------------- |
| **Element**                        | The [Element](/elements/creating-elements) to scroll into view                        |
| **Target**                         | `Nearest Point` (default), `Top Left`, `Center`, or `Bottom Right`                    |
| **Parent Element** *(conditional)* | Scrollable container [Element](/elements/creating-elements) when the target is nested |

### Advanced

| Field              | What to set                                       |
| ------------------ | ------------------------------------------------- |
| **Status on fail** | [Failed Status](/test-step-options/failed-status) |

## Related

* [Scroll To Edge](/test-steps/action/scroll-to-edge)
* [Touch](/test-steps/action/touch)
* [Action](/test-steps/action)

**Tags:** `action`, `scroll`, `intoView`, `view`, `target`, `focus`, `move`, `viewport`


# Scroll To Edge

Scroll the page or element to a specific edge.

Scroll To Edge scrolls the page or a container [Element](/elements/creating-elements) to its top, bottom, left, or right edge. Use it when the Flow must reach content pinned to an edge of a long page or panel.

![Scroll to edge Test Step](https://app.does.qa/screenshots/node/action_scroll_page.png)

## When to use it

* Reach a sticky footer or infinite-list sentinel at the bottom of the page.
* Scroll a horizontal carousel container to its far edge before selecting an item.
* Prefer [Scroll Into View](/test-steps/action/scroll-into-view) when one specific control should land in the viewport.

## Configure

### Basics

| Field                              | What to set                                                                         |
| ---------------------------------- | ----------------------------------------------------------------------------------- |
| **Destination**                    | `Top` (default), `Bottom`, `Left`, or `Right`                                       |
| **Parent Element** *(conditional)* | Container [Element](/elements/creating-elements) to scroll instead of the main page |

### Advanced

| Field              | What to set                                       |
| ------------------ | ------------------------------------------------- |
| **Status on fail** | [Failed Status](/test-step-options/failed-status) |

## Related

* [Scroll Into View](/test-steps/action/scroll-into-view)
* [Touch](/test-steps/action/touch)
* [Action](/test-steps/action)

**Tags:** `action`, `scroll`, `page`, `view`, `target`, `focus`, `move`, `viewport`


# Hover

Move the pointer over an Element or screen position.

Hover moves the pointer over a control without clicking. Use it to open hover menus, reveal tooltips, or show controls that only appear on mouseover before a later [Touch](/test-steps/action/touch).

![Hover Test Step](https://app.does.qa/screenshots/node/action_touch_hover.png)

## When to use it

* Reveal a menu that only appears on hover, then Touch an item inside it.
* Show tooltip or preview UI before a Check step.

## Configure

### Basics

| Field             | What to set                                       |
| ----------------- | ------------------------------------------------- |
| **Type**          | `Element` (default) or `position`                 |
| **Element**       | The Element to hover (Element type)               |
| **Position Type** | `Percentage` (default) or `Pixel` (position type) |
| **X** / **Y**     | Where to hover when Type is position              |

### Advanced

| Field              | What to set                                       |
| ------------------ | ------------------------------------------------- |
| **Status on fail** | [Failed Status](/test-step-options/failed-status) |

## Related

* [Touch](/test-steps/action/touch)
* [Double Tap](/test-steps/action/double-tap)
* [Action](/test-steps/action)

**Tags:** `action`, `hover`, `mouse`, `moveto`


# Touch and Hold

Touch and hold an element or position.

Touch and Hold presses and holds on an [Element](/elements/creating-elements) or screen position. Use it to open context menus, drag handles, or mobile long-press actions.

![Touch and Hold Test Step](https://app.does.qa/screenshots/node/action_touch_down.png)

## When to use it

* Open a context menu that appears only after a long press.
* Start a drag gesture that begins with a held touch on a handle or list item.
* Pair with [Touch Release](/test-steps/action/touch-release) when the Flow must lift the press on a specific target.

## Configure

### Basics

| Field                             | What to set                                                        |
| --------------------------------- | ------------------------------------------------------------------ |
| **Type**                          | `Element` (default) or `position`                                  |
| **Element** *(conditional)*       | The [Element](/elements/creating-elements) to press (Element type) |
| **Position Type** *(conditional)* | `Percentage` (default) or `Pixel` (position type)                  |
| **X** *(conditional)*             | `Left Edge` or horizontal position when Type is position           |
| **Y** *(conditional)*             | `Top Edge` or vertical position when Type is position              |

### Advanced

| Field                        | What to set                                            |
| ---------------------------- | ------------------------------------------------------ |
| **Modifiers**                | Optional `Shift`, `Ctrl`, `Windows`, or `Alt`          |
| **Mode** *(conditional)*     | `Area` (default) or `Event`                            |
| **X Offset** *(conditional)* | Fine-tune horizontal press point (`Center` by default) |
| **Y Offset** *(conditional)* | Fine-tune vertical press point (`Center` by default)   |
| **Status on fail**           | [Failed Status](/test-step-options/failed-status)      |

## Related

* [Touch Release](/test-steps/action/touch-release)
* [Touch](/test-steps/action/touch)
* [Double Tap](/test-steps/action/double-tap)
* [Hover](/test-steps/action/hover)
* [Action](/test-steps/action)

**Tags:** `action`, `touch`, `down`, `click`, `mouse`, `hold`


# Touch Release

Touch Release an element or position.

Touch Release lifts a press on an [Element](/elements/creating-elements) or screen position. Use it after [Touch and Hold](/test-steps/action/touch-and-hold) to complete drag-and-drop or long-press gestures.

![Touch Release Test Step](https://app.does.qa/screenshots/node/action_touch_up.png)

## When to use it

* Drop an item after dragging it from a held touch on another control.
* End a long-press sequence on a different Element than where the hold started.
* Pair with [Touch and Hold](/test-steps/action/touch-and-hold) for gestures that span more than one step.

## Configure

### Basics

| Field                             | What to set                                                             |
| --------------------------------- | ----------------------------------------------------------------------- |
| **Type**                          | `Element` (default) or `position`                                       |
| **Element** *(conditional)*       | The [Element](/elements/creating-elements) to release on (Element type) |
| **Position Type** *(conditional)* | `Percentage` (default) or `Pixel` (position type)                       |
| **X** *(conditional)*             | `Left Edge` or horizontal position when Type is position                |
| **Y** *(conditional)*             | `Top Edge` or vertical position when Type is position                   |

### Advanced

| Field                        | What to set                                              |
| ---------------------------- | -------------------------------------------------------- |
| **Modifiers**                | Optional `Shift`, `Ctrl`, `Windows`, or `Alt`            |
| **Mode** *(conditional)*     | `Area` (default) or `Event`                              |
| **X Offset** *(conditional)* | Fine-tune horizontal release point (`Center` by default) |
| **Y Offset** *(conditional)* | Fine-tune vertical release point (`Center` by default)   |
| **Status on fail**           | [Failed Status](/test-step-options/failed-status)        |

## Related

* [Touch and Hold](/test-steps/action/touch-and-hold)
* [Touch](/test-steps/action/touch)
* [Drag and Drop](/test-steps/action/drag-and-drop)
* [Action](/test-steps/action)

**Tags:** `action`, `touch`, `down`, `click`, `mouse`, `hold`


# Set Value

Fill an input Element with text or a Value.

Set value types into an input, textarea, or similar control. Use it when you need to enter a username, password, search term, or any other field value.

This is the **Action** Set value step. The [Data Set value](/test-steps/data/set-value) step writes to storage instead of filling a form field. They share a label and do different jobs.

![Set value Test Step](https://app.does.qa/screenshots/node/action_input_setValue.png)

## When to use it

* Enter text into a form field from plain text or a [Value](/values/value-store).
* Prefer Set value over [Send keys](/test-steps/action/send-keys) for ordinary typing. Use Send keys for special keys such as Enter or Tab.
* Turn on **Clear Value** when the field may already contain text you need to replace.

## Configure

### Basics

| Field           | What to set                                              |
| --------------- | -------------------------------------------------------- |
| **Element**     | The input [Element](/elements/creating-elements) to fill |
| **Value**       | Text and/or Values to type                               |
| **Clear Value** | Clear the field before typing (`false` by default)       |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` (default) or `On Failures`               |

{% hint style="info" %}
**Pro tip:** Type `$` in Value to insert Assets Values or built-ins such as `$testEmail`.
{% endhint %}

## Related

* [Send keys](/test-steps/action/send-keys)
* [Clear](/test-steps/action/clear)
* [Select option](/test-steps/action/select-option)
* [File](/test-steps/action/file)
* [Action](/test-steps/action)

**Tags:** `action`, `input`, `setValue`, `fill`, `type`, `value`


# Scan

Scan an element for QR codes.

Scan reads a QR or barcode from an [Element](/elements/creating-elements) on the page and stores the result in the [Value Store](/values/value-store). Use it when the Flow must capture a code shown in the UI for a later step or check.

![Scan Test Step](https://app.does.qa/screenshots/node/action_scan.png)

## When to use it

* Capture a QR code displayed for mobile login or two-factor setup.
* Read a barcode rendered in the application and assert or reuse the decoded text.
* Choose **Response** in Advanced when the Flow needs parsed fields instead of raw text.

## Configure

### Basics

| Field                     | What to set                                                    |
| ------------------------- | -------------------------------------------------------------- |
| **Element**               | The [Element](/elements/creating-elements) that shows the code |
| **Response Storage Name** | Name for the scan result in the Value Store                    |

### Advanced

| Field              | What to set                                       |
| ------------------ | ------------------------------------------------- |
| **Response**       | `Text` (default), `Parsed Data`, or `Complete`    |
| **Status on fail** | [Failed Status](/test-step-options/failed-status) |

## Related

* [Store element text](/test-steps/data/store-element-text)
* [Check value](/test-steps/check/check-value)
* [Action](/test-steps/action)

**Tags:** `action`, `scan`, `qr`, `code`, `barcode`


# Check

Assert what the page, Element, browser, or stored data should look like.

Check Test Steps verify the result of the journey so far. Use them to confirm an Element state, text, URL, title, cookie, storage value, or other expected outcome.

If the check does not match, the Test Case fails according to the step's [Failed Status](/test-step-options/failed-status).

## Element state

For Exists, Displayed, Visible, and the related interaction states, see [Element states](/test-step-options/element-states).

| Test Step                                                                                                           | Use it to                                            |
| ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| [Check Exists](/test-steps/check/check-exists) / [Check Does Not Exist](/test-steps/check/check-does-not-exist)     | Confirm the Element is in the DOM                    |
| [Check Displayed](/test-steps/check/check-displayed) / [Check Not Displayed](/test-steps/check/check-not-displayed) | Confirm the Element is shown on the page             |
| [Check Visible](/test-steps/check/check-visible) / [Check Not Visible](/test-steps/check/check-not-visible)         | Confirm the Element is shown in the current viewport |
| [Check Enabled](/test-steps/check/check-enabled) / [Check Disabled](/test-steps/check/check-disabled)               | Confirm enabled state                                |
| [Check Clickable](/test-steps/check/check-clickable) / [Check Not Clickable](/test-steps/check/check-not-clickable) | Confirm the Element can be clicked                   |
| [Check Focused](/test-steps/check/check-focused) / [Check Not Focused](/test-steps/check/check-not-focused)         | Confirm focus                                        |
| [Check Selected](/test-steps/check/check-selected) / [Check Not Selected](/test-steps/check/check-not-selected)     | Confirm selection                                    |

## Content and attributes

| Test Step                                                      | Use it to                    |
| -------------------------------------------------------------- | ---------------------------- |
| [Check Text](/test-steps/check/check-text)                     | Compare Element text         |
| [Check Value](/test-steps/check/check-value)                   | Compare an input value       |
| [Check Attribute](/test-steps/check/check-attribute)           | Compare an attribute         |
| [Check Count](/test-steps/check/check-count)                   | Count matching Elements      |
| [Check Computed Label](/test-steps/check/check-computed-label) | Compare the accessible label |
| [Check Computed Role](/test-steps/check/check-computed-role)   | Compare the accessible role  |
| [Check Computed Style](/test-steps/check/check-computed-style) | Compare a computed style     |

## Browser, storage, and data

| Test Step                                                                                                         | Use it to                  |
| ----------------------------------------------------------------------------------------------------------------- | -------------------------- |
| [Check Address](/test-steps/check/check-address)                                                                  | Compare the browser URL    |
| [Check Title](/test-steps/check/check-title)                                                                      | Compare the page title     |
| [Check Cookie](/test-steps/check/check-cookie)                                                                    | Compare a cookie           |
| [Check LocalStorage](/test-steps/check/check-localstorage)                                                        | Compare local storage      |
| [Check SessionStorage](/test-steps/check/check-sessionstorage)                                                    | Compare session storage    |
| [Check Value Store](/test-steps/check/check-value-store)                                                          | Compare a Value Store item |
| [Check JSON Value](/test-steps/check/check-json-value) / [Check JSON Schema](/test-steps/check/check-json-schema) | Compare JSON data          |

## Links, timing, analytics, and SFTP

| Test Step                                                                                                                                               | Use it to                                |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| [Check Links](/test-steps/check/check-links)                                                                                                            | Check links on the page or in an Element |
| [Check Load Time](/test-steps/check/check-load-time)                                                                                                    | Compare page load time                   |
| [Check API Response Time](/test-steps/check/check-api-response-time)                                                                                    | Compare an API response time             |
| [Check GTM Event](/test-steps/check/check-gtm-event)                                                                                                    | Confirm a Google Tag Manager event       |
| [Check SFTP File Exists](/test-steps/check/check-sftp-file-exists) / [Check SFTP File Does Not Exist](/test-steps/check/check-sftp-file-does-not-exist) | Confirm an SFTP file                     |
| [Check SFTP File Count](/test-steps/check/check-sftp-file-count)                                                                                        | Count files in an SFTP directory         |


# Check Displayed

Confirm an Element is shown on the page.

Check Displayed confirms the [Element](/elements/creating-elements) is shown on the page. Use it to prove UI content appeared after an action, or that a section is visible to the user.

See [Element states](/test-step-options/element-states) for how Displayed differs from Exists and Visible.

![Check displayed Test Step](https://app.does.qa/screenshots/node/check_is_displayed.png)

## When to use it

* Confirm a message, panel, or control appeared after a login or form submit.
* Verify a modal or banner is shown before the next interaction step.
* Prefer [Check Visible](/test-steps/check/check-visible) when the Element must be on screen in the current view.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Not Displayed](/test-steps/check/check-not-displayed)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `displayed`, `test`, `expect`, `assert`, `element`, `state`


# Check Not Displayed

Confirm an Element is not shown on the page.

Check Not Displayed confirms the [Element](/elements/creating-elements) is not shown on the page. Use it after an action that should hide content, or to prove a block stays hidden.

See [Element states](/test-step-options/element-states) for how Displayed differs from Exists and Visible.

![Check not displayed Test Step](https://app.does.qa/screenshots/node/check_is_notDisplayed.png)

## When to use it

* Confirm an error banner or modal closed after dismissal.
* Verify a loading spinner or overlay is gone before the next step.
* Pair with [Check Displayed](/test-steps/check/check-displayed) on different branches of the same Flow.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Displayed](/test-steps/check/check-displayed)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `notDisplayed`, `test`, `expect`, `assert`, `element`, `not`, `displayed`, `hidden`, `state`


# Check Visible

Check a specific element is currently visible.

Check Visible confirms the [Element](/elements/creating-elements) is shown within the current viewport. Use it to prove a control or message is on screen before the next interaction.

See [Element states](/test-step-options/element-states) for how Visible differs from Displayed and Exists.

![Check visible Test Step](https://app.does.qa/screenshots/node/check_is_visible.png)

## When to use it

* Confirm a sticky header or banner is on screen after scroll.
* Verify a field scrolled into view before [Touch](/test-steps/action/touch).
* Prefer [Check Displayed](/test-steps/check/check-displayed) when presence on the page is enough.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Not Visible](/test-steps/check/check-not-visible)
* [Check Displayed](/test-steps/check/check-displayed)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `visible`, `test`, `expect`, `assert`, `element`, `state`


# Check Not Visible

Check a specific element is not currently visible.

Check Not Visible confirms the [Element](/elements/creating-elements) is not shown within the current viewport. Use it when UI should leave the visible area but may still exist on the page.

See [Element states](/test-step-options/element-states) for how Visible differs from Displayed and Exists.

![Check not visible Test Step](https://app.does.qa/screenshots/node/check_is_notVisible.png)

## When to use it

* Confirm a dropdown or tooltip left the viewport after selection.
* Verify a sticky banner scrolled away before checking content below it.
* Prefer [Check Not Displayed](/test-steps/check/check-not-displayed) when the Element should leave the page entirely.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Visible](/test-steps/check/check-visible)
* [Check Not Displayed](/test-steps/check/check-not-displayed)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `notVisible`, `test`, `expect`, `assert`, `element`, `not`, `visible`, `hidden`, `state`


# Check Exists

Confirm an Element is in the DOM.

Check Exists confirms the [Element](/elements/creating-elements) is in the DOM. The Element may still be hidden. Use it when presence in the page structure is enough.

See [Element states](/test-step-options/element-states) for how Exists differs from Displayed and Visible.

![Check exists Test Step](https://app.does.qa/screenshots/node/check_is_exist.png)

## When to use it

* Confirm a row or list item was added to the page after a create action.
* Verify markup is present before a later step reads from it.
* Prefer [Check Displayed](/test-steps/check/check-displayed) when the Element must be shown to the user.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Does Not Exist](/test-steps/check/check-does-not-exist)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `exist`, `test`, `expect`, `assert`, `element`, `state`


# Check Does Not Exist

Confirm an Element is not in the DOM.

Check Does Not Exist confirms the [Element](/elements/creating-elements) is not in the DOM. Use it after a delete or filter action that should remove markup entirely.

See [Element states](/test-step-options/element-states) for how Exists differs from Displayed and Visible.

![Check does not exist Test Step](https://app.does.qa/screenshots/node/check_is_notExist.png)

## When to use it

* Confirm a list item or row was removed after a delete action.
* Verify optional content is absent on a page variant.
* Prefer [Check Not Displayed](/test-steps/check/check-not-displayed) when the Element may stay in the DOM but should be hidden.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Exists](/test-steps/check/check-exists)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `notExist`, `test`, `expect`, `assert`, `element`, `state`


# Check Enabled

Check a specific element is currently enabled.

Check Enabled confirms the [Element](/elements/creating-elements) is active and accepts input. Use it when a control should unlock after validation or loading finishes.

See [Element states](/test-step-options/element-states) for how Enabled relates to Disabled and Clickable.

![Check enabled Test Step](https://app.does.qa/screenshots/node/check_is_enabled.png)

## When to use it

* Confirm a submit button unlocked after required fields are filled.
* Verify a field is editable before [Set value](/test-steps/action/set-value).
* Pair with [Check Disabled](/test-steps/check/check-disabled) on the branch where the control should stay locked.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Disabled](/test-steps/check/check-disabled)
* [Check Clickable](/test-steps/check/check-clickable)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `enabled`, `test`, `expect`, `assert`, `element`, `disabled`, `state`


# Check Disabled

Confirm an Element is disabled.

Check Disabled confirms the [Element](/elements/creating-elements) is disabled. Use it when a control should stay inactive until the user completes a prerequisite step.

See [Element states](/test-step-options/element-states) for how Disabled relates to Enabled and Clickable.

![Check disabled Test Step](https://app.does.qa/screenshots/node/check_is_disabled.png)

## When to use it

* Confirm a submit button stays disabled until the form is valid.
* Verify a destructive action stays locked until confirmation is complete.
* Pair with [Check Enabled](/test-steps/check/check-enabled) after the user satisfies the prerequisite.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Enabled](/test-steps/check/check-enabled)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `disabled`, `test`, `expect`, `assert`, `element`, `enabled`, `state`


# Check Clickable

Confirm an Element is ready to click.

Check Clickable confirms the [Element](/elements/creating-elements) is shown, enabled, and ready to click. Use it before a [Touch](/test-steps/action/touch) step when the Flow must prove the control is interactive first.

See [Element states](/test-step-options/element-states) for how Clickable relates to Displayed and Enabled.

![Check clickable Test Step](https://app.does.qa/screenshots/node/check_is_clickable.png)

## When to use it

* Confirm a submit button is ready after a form becomes valid.
* Verify a menu item or link can be clicked before the next action step.
* Prefer [Touch](/test-steps/action/touch) alone when you only need to click and do not need an explicit assertion.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

{% hint style="info" %}
**Pro tip:** [Touch](/test-steps/action/touch) already waits for the Element to become clickable and scrolls it into view. Add Check Clickable only when the Flow needs a clear pass or fail on that state before other work.
{% endhint %}

## Related

* [Check Not Clickable](/test-steps/check/check-not-clickable)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `clickable`, `test`, `expect`, `assert`, `element`, `state`


# Check Not Clickable

Confirm an Element is not ready to click.

Check Not Clickable confirms the [Element](/elements/creating-elements) is not ready to click. Use it when a control should stay disabled, hidden, or blocked by an overlay.

See [Element states](/test-step-options/element-states) for how Clickable relates to Displayed and Enabled.

![Check not clickable Test Step](https://app.does.qa/screenshots/node/check_is_notClickable.png)

## When to use it

* Confirm a submit button stays inactive until required fields are filled.
* Verify a link or button is blocked while a loading state is shown.
* Pair with [Check Clickable](/test-steps/check/check-clickable) on different branches of the same Flow.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Clickable](/test-steps/check/check-clickable)
* [Check Disabled](/test-steps/check/check-disabled)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `notClickable`, `test`, `expect`, `assert`, `element`, `state`


# Check Focused

Check a specific element is currently focused.

Check Focused confirms keyboard focus is on the [Element](/elements/creating-elements). Use it to prove tab order, autofocus, or post-click focus landed on the right control.

See [Element states](/test-step-options/element-states) for how focus fits with the other Element state checks.

![Check focused Test Step](https://app.does.qa/screenshots/node/check_is_focused.png)

## When to use it

* Confirm the first field is focused when a form opens.
* Verify focus moved to an error field after failed validation.
* Pair with [Check Not Focused](/test-steps/check/check-not-focused) when focus should leave a control.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Not Focused](/test-steps/check/check-not-focused)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `focused`, `test`, `expect`, `assert`, `element`, `state`


# Check Not Focused

Check a specific element is not currently focused.

Check Not Focused confirms keyboard focus is not on the [Element](/elements/creating-elements). Use it when focus should move away after submit, dismiss, or tab navigation.

See [Element states](/test-step-options/element-states) for how focus fits with the other Element state checks.

![Check not focused Test Step](https://app.does.qa/screenshots/node/check_is_notFocused.png)

## When to use it

* Confirm focus left an input after the form submitted.
* Verify a modal field lost focus when the dialog closed.
* Pair with [Check Focused](/test-steps/check/check-focused) on the control that should receive focus next.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Focused](/test-steps/check/check-focused)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `notFocused`, `test`, `expect`, `assert`, `element`, `state`


# Check Selected

Confirm an Element is selected or checked.

Check Selected confirms the [Element](/elements/creating-elements) is selected or checked. Use it for checkboxes, radio buttons, and other controls with a selected state.

See [Element states](/test-step-options/element-states) for how Selected fits with the other Element state checks.

![Check selected Test Step](https://app.does.qa/screenshots/node/check_is_selected.png)

## When to use it

* Confirm a checkbox stayed checked after save or reload.
* Verify the correct radio option is selected in a group.
* Pair with [Check Not Selected](/test-steps/check/check-not-selected) when toggling selection off.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Not Selected](/test-steps/check/check-not-selected)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `selected`, `test`, `expect`, `assert`, `element`, `state`, `checked`


# Check Not Selected

Check a specific element is not currently selected.

Check Not Selected confirms the [Element](/elements/creating-elements) is not selected or checked. Use it for checkboxes, radio buttons, and other controls with a selected state.

See [Element states](/test-step-options/element-states) for how Selected fits with the other Element state checks.

![Check not selected Test Step](https://app.does.qa/screenshots/node/check_is_notSelected.png)

## When to use it

* Confirm a checkbox cleared after toggling off.
* Verify the correct radio option is unselected in a group.
* Pair with [Check Selected](/test-steps/check/check-selected) on the branch where selection should be on.

## Configure

### Basics

| Field       | What to set                                         |
| ----------- | --------------------------------------------------- |
| **Element** | The [Element](/elements/creating-elements) to check |

### Advanced

| Field                                 | What to set                                       |
| ------------------------------------- | ------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status) |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)               |

## Related

* [Check Selected](/test-steps/check/check-selected)
* [Element states](/test-step-options/element-states)
* [Check](/test-steps/check)

**Tags:** `check`, `is`, `notSelected`, `test`, `expect`, `assert`, `element`, `state`, `checked`


# Check Text

Assert the visible text of an Element.

Check text compares an Element’s text with the value you expect. Use it to prove a heading, label, button label, or message is correct after an action.

![Check text Test Step](https://app.does.qa/screenshots/node/check_text.png)

## When to use it

* Confirm success copy after submit, save, or login.
* Assert a label or heading after navigation.
* Prefer [Check value](/test-steps/check/check-value) when you need the value attribute of an input rather than visible text.

## Configure

### Basics

| Field               | What to set                                           |
| ------------------- | ----------------------------------------------------- |
| **Element**         | The [Element](/elements/creating-elements) to read    |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type) |
| **Value**           | Expected text and/or [Values](/values/value-store)    |

### Advanced

| Field                                        | What to set                                                                                                                         |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| **Should the check be performed instantly?** | `Strict` (default) fails quickly when text does not match. `Tolerant` keeps checking within the step timeout while the text settles |
| **Status on fail**                           | [Failed Status](/test-step-options/failed-status)                                                                                   |
| **When should screenshots be taken?**        | `Always` or `On Failures` (default)                                                                                                 |
| **Value Standardization**                    | [Value Standardization](/test-step-options/value-standardization)                                                                   |

{% hint style="info" %}
**Pro tip:** Use Tolerant when the UI updates text a moment after the click. Use Strict when a mismatch should fail immediately.
{% endhint %}

## Related

* [Check value](/test-steps/check/check-value)
* [Check displayed](/test-steps/check/check-displayed)
* [Element states](/test-step-options/element-states)
* [Comparison Type](/test-step-options/comparison-type)
* [Check](/test-steps/check)

**Tags:** `check`, `text`, `assert`, `element`


# Check Value

Compare an input or field value on an Element.

Check Value compares the current value on an [Element](/elements/creating-elements) against what you expect. Use it for inputs, selects, and other controls that expose a value property.

![Check value Test Step](https://app.does.qa/screenshots/node/check_value.png)

## When to use it

* Confirm a form field kept the typed or selected value after save.
* Verify a default or prefilled value before the user edits it.
* Store the value first with [Store element value](/test-steps/data/store-element-value) when a later step needs the same data.

## Configure

### Basics

| Field               | What to set                                                                 |
| ------------------- | --------------------------------------------------------------------------- |
| **Element**         | The [Element](/elements/creating-elements) to check                         |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type) (`equals` by default) |
| **Value**           | Expected text and/or a [Value](/values/value-store)                         |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

## Related

* [Check Text](/test-steps/check/check-text)
* [Store element value](/test-steps/data/store-element-value)
* [Check](/test-steps/check)

**Tags:** `check`, `value`, `test`, `expect`, `assert`, `element`


# Check Value Store

Check a specific item in the value store.

Check Value Store compares a stored [Value](/values/value-store) with what you expect. Use it to assert data captured earlier in the Flow without reading the page again.

![Check Value Store Test Step](https://app.does.qa/screenshots/node/check_valueStore.png)

## When to use it

* Confirm an API response stored in the Value Store matches an expected ID or status.
* Reuse captured text from an earlier Store step in a later assertion.
* Pair with [Stop When Value](/test-steps/runner/stop-when-value) when the same comparison should end the Test Case early.

## Configure

### Basics

| Field                | What to set                                                                      |
| -------------------- | -------------------------------------------------------------------------------- |
| **Value Store Item** | The stored [Value](/values/value-store) to read                                  |
| **Comparison Type**  | [Comparison Type](/test-step-options/comparison-type)                            |
| **Value**            | Expected text and/or [Values](/values/value-store) when the comparison needs one |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

## Related

* [Value Store](/values/value-store)
* [Stop When Value](/test-steps/runner/stop-when-value)
* [Check](/test-steps/check)

**Tags:** `check`, `valueStore`, `test`, `expect`, `assert`


# Check Attribute

Compare an HTML attribute on an Element.

Check Attribute compares an HTML attribute on an [Element](/elements/creating-elements) against what you expect. Use it for `href`, `src`, `data-*`, and other attributes.

![Check attribute Test Step](https://app.does.qa/screenshots/node/check_attribute.png)

## When to use it

* Confirm a link points at the expected URL or path.
* Verify an image `src` or a `data-testid` after dynamic content loads.
* Store the attribute first with [Store element attribute](/test-steps/data/store-element-attribute) when a later step needs the same value.

## Configure

### Basics

| Field               | What to set                                                                 |
| ------------------- | --------------------------------------------------------------------------- |
| **Element**         | The [Element](/elements/creating-elements) to check                         |
| **Attribute**       | Attribute name (for example `href` or `data-status`)                        |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type) (`equals` by default) |
| **Value**           | Expected attribute value as text and/or a [Value](/values/value-store)      |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

## Related

* [Store element attribute](/test-steps/data/store-element-attribute)
* [Check Value](/test-steps/check/check-value)
* [Check](/test-steps/check)

**Tags:** `check`, `attribute`, `test`, `expect`, `assert`, `element`


# Check Computed Label

Check the computed label on a specific element.

Check Computed Label compares the accessible name on an [Element](/elements/creating-elements) with what you expect. Use it to prove assistive tools will read the right label for a control.

![Check computed label Test Step](https://app.does.qa/screenshots/node/check_computed_label.png)

## When to use it

* Confirm an icon button exposes a spoken label.
* Verify a form field's computed label matches visible copy.
* Pair with [Check Computed Role](/test-steps/check/check-computed-role) when both name and role matter.

## Configure

### Basics

| Field               | What to set                                                 |
| ------------------- | ----------------------------------------------------------- |
| **Element**         | The [Element](/elements/creating-elements) to read          |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type)       |
| **Value**           | Expected label as text and/or [Values](/values/value-store) |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

## Related

* [Check Computed Role](/test-steps/check/check-computed-role)
* [Check Text](/test-steps/check/check-text)
* [Check](/test-steps/check)

**Tags:** `check`, `computed`, `label`, `test`, `expect`, `assert`, `element`, `computed`, `accessibility`


# Check Computed Role

Check the computed role on a specific element.

Check Computed Role compares the accessibility role on an [Element](/elements/creating-elements) with what you expect. Use it to catch markup changes that affect screen readers and assistive tools.

![Check computed role Test Step](https://app.does.qa/screenshots/node/check_computed_role.png)

## When to use it

* Confirm a custom control exposes the correct role after a refactor.
* Verify a dialog or menu reports `dialog` or `menu` semantics.
* Pair with [Check Computed Label](/test-steps/check/check-computed-label) when both role and label matter.

## Configure

### Basics

| Field               | What to set                                                |
| ------------------- | ---------------------------------------------------------- |
| **Element**         | The [Element](/elements/creating-elements) to read         |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type)      |
| **Value**           | Expected role as text and/or [Values](/values/value-store) |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

## Related

* [Check Computed Label](/test-steps/check/check-computed-label)
* [Check Computed Style](/test-steps/check/check-computed-style)
* [Check](/test-steps/check)

**Tags:** `check`, `computed`, `role`, `test`, `expect`, `assert`, `element`, `computed`, `accessibility`


# Check Computed Style

Check the computed style on a specific element.

Check Computed Style compares a CSS property on an [Element](/elements/creating-elements) with what you expect. Use it when visual state is driven by styles rather than text or attributes alone.

![Check computed style Test Step](https://app.does.qa/screenshots/node/check_computed_style.png)

## When to use it

* Confirm an error field shows a red border after validation fails.
* Verify a hidden panel uses `display: none` or another expected property.
* Pair with [Check Attribute](/test-steps/check/check-attribute) when the source is an HTML attribute instead.

## Configure

### Basics

| Field               | What to set                                                                        |
| ------------------- | ---------------------------------------------------------------------------------- |
| **Element**         | The [Element](/elements/creating-elements) to read                                 |
| **Property**        | CSS property from the step dropdown (for example `Color`, `Display`, `Visibility`) |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type)                              |
| **Value**           | Expected value as text and/or [Values](/values/value-store)                        |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

## Related

* [Check Computed Label](/test-steps/check/check-computed-label)
* [Check Attribute](/test-steps/check/check-attribute)
* [Check](/test-steps/check)

**Tags:** `check`, `computed`, `style`, `test`, `expect`, `assert`, `element`, `computed`, `css`


# Check Count

Compare how many Elements match a selector.

Check Count compares how many [Elements](/elements/creating-elements) match the selector against what you expect. Use it for lists, tables, and repeating UI blocks.

![Check count Test Step](https://app.does.qa/screenshots/node/check_count.png)

## When to use it

* Confirm a search returned the expected number of results.
* Verify a cart or list grew or shrank after an add or remove action.
* Use `greaterThanOrEqual` when you only need to prove at least one match exists.

## Configure

### Basics

| Field               | What to set                                                                             |
| ------------------- | --------------------------------------------------------------------------------------- |
| **Element**         | The [Element](/elements/creating-elements) whose matches to count                       |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type) (`greaterThanOrEqual` by default) |
| **Value**           | Expected count as text and/or a [Value](/values/value-store)                            |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

{% hint style="info" %}
**Pro tip:** The default comparison is `greaterThanOrEqual`, which suits "at least one result" checks. Switch to `equals` when the exact count matters.
{% endhint %}

## Related

* [Store element count](/test-steps/data/store-element-count)
* [Check Text](/test-steps/check/check-text)
* [Check](/test-steps/check)

**Tags:** `check`, `count`, `test`, `expect`, `assert`, `element`, `total`


# Check Title

Compare the current browser tab title.

Check Title compares the current browser tab title against what you expect. Use it after navigation or when the title should change to reflect the page.

![Check title Test Step](https://app.does.qa/screenshots/node/check_browserTitle.png)

## When to use it

* Confirm the user landed on the correct page after login or checkout.
* Verify SEO or marketing titles on key landing pages.
* Pair with [Check Address](/test-steps/check/check-address) when both the URL and title should match.

## Configure

### Basics

| Field               | What to set                                                                 |
| ------------------- | --------------------------------------------------------------------------- |
| **Comparison Type** | [Comparison Type](/test-step-options/comparison-type) (`equals` by default) |
| **Value**           | Expected title text and/or a [Value](/values/value-store)                   |

### Advanced

| Field                                 | What to set                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| **Status on fail**                    | [Failed Status](/test-step-options/failed-status)                 |
| **When should screenshots be taken?** | `Always` or `On Failures` (default)                               |
| **Value Standardization**             | [Value Standardization](/test-step-options/value-standardization) |

## Related

* [Check Address](/test-steps/check/check-address)
* [Go to absolute URL](/test-steps/browser/go-to-absolute-url)
* [Check](/test-steps/check)

**Tags:** `check`, `browserTitle`, `test`, `expect`, `assert`, `browser`, `window`, `tab`, `title`




---

[Next Page](/llms-full.txt/1)

