> For the complete documentation index, see [llms.txt](https://docs.drizz.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.drizz.dev/writing-tests/recipes.md).

# Recipes

Six complete tests against ShopEase, the demo app used throughout these docs. Each runs as written.

|                  |                                                                       |
| ---------------- | --------------------------------------------------------------------- |
| **Platforms**    | Android · iOS— except where a recipe says otherwise                   |
| **Demo app**     | ShopEase — `com.shopease.android` / `com.shopease.ios`                |
| **Test user**    | `qa@example.com` · phone `9000000000` · OTP `123456`                  |
| **Every recipe** | Ends in `CLEAR_APP` so the next test starts clean                     |
| **Watch out**    | `CLEAR_APP` is effectively a no-op on iOS. Log out explicitly instead |

## Prerequisites

* Drizz desktop app installed and signed in
* ShopEase registered as an app, with a device or emulator connected
* A dataset supplying `app_package`, `phone` and `otp`, bound to the plan

## 1 · Login with OTP

The setup module every other recipe calls, driven by dataset variables.

```
# BEGIN shopease_login
OPEN_APP {{app_package}}
Wait Until 5 Seconds

IF Validate that the location permission prompt is visible
{
    Tap on While using the app
    Wait Until 1 Seconds
}

Type {{phone}} in the mobile number field
Tap on Get OTP
Wait Until 3 Seconds

Type {{otp}} in the OTP field
Tap on Continue
Wait Until 5 Seconds

Validate that the home screen is visible
# END shopease_login
```

The test that proves it works:

```
# T01 — ShopEase: login with OTP

CALL shopease_login

Validate 1. Search 2. Cart 3. Account is visible

CLEAR_APP com.shopease.android
```

An app that returns the OTP on screen rather than by SMS supports capturing it instead of hardcoding it:

```
Store the OTP as otp_initial
Type {{otp_initial}} in the OTP field
```

## 2 · Search, add to cart, check out

The five-beat test — setup, navigate, act, validate, clean up — with a before/after numeric comparison.

```
# T02 — ShopEase: search, add to cart and place an order

CALL shopease_login

Tap on the search icon
Wait Until 2 Seconds

Type running shoes in the search field
Tap on the first search result
Wait Until 3 Seconds

Validate that the product detail page is visible
Store the price as listed_price

Tap on Add to Cart
Wait Until 2 Seconds
Validate that Item added to cart is visible

Tap on Cart
Wait Until 2 Seconds

Validate that {{listed_price}} is visible beside the item
Store the Order Total as total_before

# the checkout button sits below the fold on smaller screens;
# a scroll that isn't needed costs almost nothing
Scroll down until "Proceed to Checkout" is visible
Tap on Proceed to Checkout
Wait Until 3 Seconds

Validate that the delivery address is visible
Tap on Place Order
Wait Until 5 Seconds

Validate 1. Order placed 2. Order ID 3. Estimated delivery is visible
Store the Order ID as order_id

CLEAR_APP com.shopease.android
```

## 3 · Multi-app: place an order, accept it in the partner app

Switching between two apps in one test with `OPEN_APP`, carrying a value across the switch.

```
# T03 — ShopEase: an order placed in the customer app appears in the partner app

CALL shopease_login

Tap on the search icon
Type running shoes in the search field
Tap on the first search result
Wait Until 3 Seconds

Tap on Add to Cart
Wait Until 2 Seconds

Tap on Cart
Scroll down until "Proceed to Checkout" is visible
Tap on Proceed to Checkout
Wait Until 3 Seconds

Tap on Place Order
Wait Until 5 Seconds

Validate that Order placed is visible
Store the Order ID as order_id

# switch to the delivery partner app
OPEN_APP com.shopease.partner
Wait Until 5 Seconds

Tap on Available Orders
Wait Until 3 Seconds

Scroll down until "{{order_id}}" is visible
Validate that {{order_id}} is visible in the available orders list

Tap on Accept beside {{order_id}}
Wait Until 3 Seconds

Validate that Order accepted is visible

KILL_APP com.shopease.partner
CLEAR_APP com.shopease.android
```

`OPEN_APP` switches apps directly. `MINIMISE_APP` followed by a tap on the app from the home screen is the slower alternative, closer to what a person does. Variables survive the switch — `{{order_id}}` captured in ShopEase is still set in the partner app.

## 4 · Mobile web: check the order on the website

Validating the same data in an app and in a browser, in one test.

```
# T04 — ShopEase: the order in the app matches the order on the website

CALL shopease_login

Tap on Account
Wait Until 2 Seconds

Tap on My Orders
Wait Until 3 Seconds

Tap on the first order
Wait Until 2 Seconds

Validate that the order detail page is visible
Store the Order ID as order_id
Store the Order Total as order_total

# switch to the browser
OPEN_APP com.android.chrome
Wait Until 5 Seconds

Tap on the address bar
Type shopease.example.com/orders in the address bar
Wait Until 5 Seconds

Type {{order_id}} in the order search field
Tap on Search
Wait Until 5 Seconds

Validate that {{order_id}} is visible on the page
Validate that {{order_total}} is visible on the page

KILL_APP com.android.chrome
CLEAR_APP com.shopease.android
```

The browser is another app. `Tap`, `Type` and `Validate` work the same on a web page.

## 5 · Location: offers change with the city

Mocking GPS, and the kill-and-relaunch that makes the app pick it up. Android only — `SET_GPS` mocks the device location, and the app has to be restarted to read it.

```
# T05 — ShopEase: the offers screen follows the mocked location

# Bangalore
SET_GPS(latitude=12.9716, longitude=77.5946)

CALL shopease_login

Tap on Offers
Wait Until 3 Seconds

Validate that Bangalore is visible on the offers screen
Store the first offer title as bangalore_offer

# move to Delhi — the order KILL_APP, SET_GPS, OPEN_APP is required
KILL_APP com.shopease.android
SET_GPS(latitude=28.7041, longitude=77.1025)

OPEN_APP com.shopease.android
Wait Until 5 Seconds

Tap on Offers
Wait Until 3 Seconds

Validate that Delhi is visible on the offers screen
Store the first offer title as delhi_offer

Validate that delhi_offer is not equal to bangalore_offer

CLEAR_APP com.shopease.android
```

An app already running keeps the location it started with. `SET_GPS` without a restart changes nothing and the test passes for the wrong reason. A test that needs one location throughout sets it before `OPEN_APP` and skips the restart.

## 6 · Data-driven: one test, every environment and account

A single script driven entirely by a dataset, so it runs against staging, production, or ten different users without editing.

The dataset, `shopease_staging`:

```yaml
app_package: com.shopease.android
phone: "9000000000"
otp: "123456"
search_term: running shoes
expected_city: Bangalore
```

The test:

```
# T06 — ShopEase: search and add to cart, fully data-driven

CALL shopease_login

Validate that {{expected_city}} is visible on the address bar

Tap on the search icon
Wait Until 2 Seconds

Type {{search_term}} in the search field
Wait Until 3 Seconds

Validate that {{search_term}} is visible in the search field
Tap on the first search result
Wait Until 3 Seconds

Validate that the product detail page is visible
Tap on Add to Cart
Wait Until 2 Seconds

Tap on Cart
Wait Until 2 Seconds
Validate that the cart has 1 item

CLEAR_APP {{app_package}}
```

Nothing in the script names an environment. A second dataset, `shopease_production`, with the production package and a production account, bound to a second plan, covers production from the same file.

Accounts that can't be shared between parallel runs go in a [lockable pool](/writing-tests/which-variable/lockable-pools.md), so each run leases its own row.

## Common mistakes

<table data-search="false"><thead><tr><th>What you write</th><th>What happens</th></tr></thead><tbody><tr><td><code>SET_GPS</code> without killing and relaunching the app</td><td>The app keeps the location it started with. The test passes for the wrong reason</td></tr><tr><td><code>OPEN_APP</code> with no package argument</td><td>Fails by design. The package is required</td></tr><tr><td>Browser steps with app-length waits</td><td>The page hasn't loaded and the validation fails</td></tr><tr><td>A hardcoded package in a data-driven test</td><td>The one line you have to edit per environment, which someone will forget</td></tr><tr><td>Chaining all six recipes into one test</td><td>When it fails you don't know which feature broke</td></tr><tr><td><code>CLEAR_APP</code> as teardown on iOS</td><td>Does effectively nothing. Log out explicitly instead</td></tr><tr><td>Reusing one variable name across an app switch</td><td>The second capture overwrites the first, and the comparison is meaningless</td></tr></tbody></table>

## Next

* [Authoring rules](/writing-tests/authoring-rules.md)
* [Datasets & test data](/writing-tests/which-variable/datasets.md)
* [Test plans](/running-tests/test-plans.md)

***

*Last updated: 6 August 2026*
