# Writing Test Steps

A reference for describing test steps in plain English. Type a step in the **Test Editor** (or `assuremind generate`) and AssureMind turns it into Playwright code.

Two engines handle generation:
- **⚡ Template engine** — deterministic, zero AI cost. Handles the common phrasings below (marked ⚡).
- **AI engine** — handles anything else, and (with **MCP** on) sees the real page to pick accurate locators.

Tips that apply everywhere:
- Put the **target name in quotes** for reliability: `Click the "Sign in" button`.
- Insert dynamic data with the **Fake Data** picker (`{{FAKE_*}}`) and uploaded files with the **Files** picker (`{{FILE:name}}`).
- Reference saved values with `{{VAR_NAME}}`; `{{BASE_URL}}` is your configured base URL.
- Prefix any assertion with **"Soft"** to keep running on failure (`Soft verify …`).

---

## UI steps

### Navigation ⚡
```text
Go to https://example.com
Navigate to /dashboard
Open https://demoqa.com/upload-download
Go back
Refresh the page
```

### Click — buttons, links, tabs ⚡
Name the role so the right locator is used (`getByRole`):
```text
Click the "Login" button
Click on "Submit"
Click the "Dashboard" link
Click the "Settings" tab
Double click the "Row 1" element
Right click the "File" element
```
> The role word should match the element's **actual ARIA role**. A control that looks like a button but is `<a role="button">` is still a button; a plain `<a href>` is a link.

### Text input ⚡
```text
Enter "deepak" in the Username field
Type {{FAKE_INTERNET_EMAIL}} in the Email field
Fill "secret123" in the Password field          # password → getByLabel automatically
Enter {{FAKE_NUMBER_INT}} in the Quantity field # number → spinbutton role
Clear the Search field
```

### Dropdowns, checkboxes, radios ⚡
```text
Select "India" from the Country dropdown
Check the "Remember me" checkbox
Uncheck the "Subscribe" checkbox
Select the "Male" radio button
```

### Keyboard ⚡
```text
Press Enter
Press Escape
Press Tab
Press "Control+A"
Type "hello" and press Enter
```

### Waits, scroll, hover, screenshot ⚡
```text
Wait for 2 seconds
Wait for the page to load
Scroll down
Scroll to bottom
Hover over the "Profile" menu
Take a screenshot
```

### File upload ⚡
Upload a file with the **Files** picker, then reference its `{{FILE:name}}` token:
```text
Upload {{FILE:resume.pdf}} to the Resume field
Upload {{FILE:resume.pdf}} to the Resume field and wait for 'Upload complete'   # most reliable
Upload {{FILE:photo.png}}                                                       # page's file input
```

### File download ⚡
Downloads are auto-captured (Reports → Downloads, and attached to Allure). The step waits until the file finishes:
```text
Download the "Export CSV" link
Click the "Download" button to download
Download the file by clicking "Report PDF"
Click "Download invoice" and wait for download
```

### Assertions ⚡
```text
Verify "Welcome back" is visible
Verify "Error" is not visible
Verify the page title is "Dashboard"
Verify the URL contains "/dashboard"
Verify the "Email" field has value "user@test.com"
Soft verify "Saved successfully" is visible        # continues on failure
```

### Scenarios the AI handles (MCP recommended)
```text
Login as admin using {{ADMIN_EMAIL}} and {{DEFAULT_PASSWORD}}
Click the "Submit" button inside the payment iframe
Fill the card number "4111111111111111" in the Stripe iframe
Accept the confirmation dialog after clicking "Delete"
Verify the table has 5 rows
Click the element inside the shadow DOM component
```
- **iframes** → wrapped in `page.frameLocator(...)` automatically.
- **shadow DOM** → locator chaining (`page.locator('host').locator('inner')`).
- **dialogs** → a `page.once('dialog', …)` handler is added before the trigger.

---

## API steps

Mark a suite/case as **API** type. Steps use Playwright's `page.request` API. Use `{{BASE_URL}}` and saved variables.

### Basic requests
```text
Send a GET request to {{BASE_URL}}/api/users and verify status is 200
Send a POST request to {{BASE_URL}}/api/users with body { "name": "John", "email": "john@test.com" } and verify status 201
Send a PUT request to {{BASE_URL}}/api/users/1 with body { "name": "Jane" }
Send a DELETE request to {{BASE_URL}}/api/users/1 and verify status 204
```

### Auth — extract and reuse a token
```text
POST to {{BASE_URL}}/api/login with { "email": "{{ADMIN_EMAIL}}", "password": "{{DEFAULT_PASSWORD}}" }, save token as AUTH_TOKEN
GET {{BASE_URL}}/api/profile with Authorization Bearer {{AUTH_TOKEN}} and verify status 200
```
- "save / store / extract … as NAME" → `context.setVariable('NAME', …)`.
- `{{AUTH_TOKEN}}` (or `context.getVariable`) reuses it in later steps/cases.

### Assertions on the response
```text
Verify the response status is 200
Verify the response body has property "id"
Verify the response field "name" equals "Admin"
Verify the response has 5 users
Verify the content-type header contains "application/json"
Verify the response time is under 500 ms
Soft verify the response status is 200
```

### Headers, query params, form bodies
```text
Send a GET request to {{BASE_URL}}/api/search with query { "q": "phone", "page": "1" }
Send a POST to {{BASE_URL}}/api/upload with form { "name": "doc", "type": "pdf" }
Send a GET to {{BASE_URL}}/api/data with header "X-Api-Key" "{{API_KEY}}"
```

---

## Soft vs hard assertions
- **Hard** (default): the test stops at the first failure.
- **Soft**: prefix with **"Soft"** (`Soft verify …`) — failures are collected and the test keeps going. In the Recorder, use `Ctrl+Shift+Click` for a soft assertion.

## Variables & dynamic data
| Token | Resolves to |
|-------|-------------|
| `{{BASE_URL}}` | Configured base URL for the active environment |
| `{{FAKE_PERSON_FULLNAME}}`, `{{FAKE_INTERNET_EMAIL}}`, … | Fresh random data each run (Fake Data picker) |
| `{{FILE:resume.pdf}}` | `fixtures/uploads/resume.pdf` (Files picker) |
| `{{MY_VAR}}` | A value from Variables or saved earlier with `context.setVariable` |

## Editing generated code
Every step's code is editable — expand the step (chevron) and edit the code block directly, or click the **✎** to change the instruction and **regenerate** (wand). Use this for anything the engines don't phrase exactly the way your app needs.
