assuremind 1.2.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -1
- package/dist/cli/index.js +1212 -18497
- package/dist/index.d.mts +65 -1
- package/dist/index.d.ts +65 -1
- package/dist/index.js +56 -1912
- package/dist/index.mjs +56 -1807
- package/docs/STUDIO.md +96 -1
- package/docs/WRITING-STEPS.md +171 -0
- package/package.json +8 -6
- package/templates/docs/WRITING-STEPS.md +171 -0
- package/ui/dist/assets/index-DqkGvedS.js +1024 -0
- package/ui/dist/assets/index-Dry-Q0Et.css +1 -0
- package/ui/dist/favicon.svg +7 -7
- package/ui/dist/index.html +15 -15
- package/dist/cli/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/ui/dist/assets/index-B2cmnLeA.js +0 -942
- package/ui/dist/assets/index-Bz5b82ao.css +0 -1
package/docs/STUDIO.md
CHANGED
|
@@ -48,7 +48,7 @@ The sidebar on the left has these pages:
|
|
|
48
48
|
| 📋 | Reports | Browse historical run results |
|
|
49
49
|
| 🔧 | Variables | Manage test variables and secrets |
|
|
50
50
|
| 🩺 | Self-Healing | Review and apply AI-generated selector fixes |
|
|
51
|
-
| ⚙️ | Settings | Environment, browsers, healing, capture settings, MCP integration |
|
|
51
|
+
| ⚙️ | Settings | Environment, browsers, healing, capture settings, MCP integration, CI/CD integration |
|
|
52
52
|
| 🌿 | Git Control Center | Branch management, AI commits, push/pull, conflict resolution |
|
|
53
53
|
|
|
54
54
|
---
|
|
@@ -74,6 +74,8 @@ While data is loading, animated skeleton cards are shown so the layout never jum
|
|
|
74
74
|
|
|
75
75
|
## Test Editor
|
|
76
76
|
|
|
77
|
+
> **Writing steps:** for a full catalog of plain-English step phrasings (UI **and** API) with examples, see [WRITING-STEPS.md](WRITING-STEPS.md).
|
|
78
|
+
|
|
77
79
|
### Suite Types
|
|
78
80
|
|
|
79
81
|
Assuremind supports three suite types:
|
|
@@ -466,6 +468,19 @@ The **Device Emulation** card appears below the Browsers card. It lets you emula
|
|
|
466
468
|
|
|
467
469
|
**Equivalent CLI flag:** `--device "iPhone 15 Pro"`
|
|
468
470
|
|
|
471
|
+
### CI Config Generator
|
|
472
|
+
|
|
473
|
+
Click **Generate CI Config** to produce a pipeline file from your current run settings (browsers, parallel workers, device). Pick a platform tab — **GitHub Actions**, **GitLab CI**, or **Jenkins**.
|
|
474
|
+
|
|
475
|
+
- The YAML opens in a **preview** (read-only). Click **✎ Edit** to customise it — change branches, Node version, add steps, env vars, etc. Your edits apply to **Copy**, **Download**, and **Write to repo**. **↺ Reset** discards edits and regenerates from the run config.
|
|
476
|
+
- **Copy** and **Download** are always available.
|
|
477
|
+
- **Write to repo** writes the file into your project at its standard path:
|
|
478
|
+
- GitHub Actions → `.github/workflows/assuremind.yml`
|
|
479
|
+
- GitLab CI → `.gitlab-ci.yml`
|
|
480
|
+
- Jenkins → `Jenkinsfile`
|
|
481
|
+
|
|
482
|
+
This button only appears when **Settings → CI/CD Integration → "Write CI files to repo"** is enabled (off by default). It **only writes the file** — it does **not** commit or push. Review the change and commit it from the **Git Control Center** when you're ready.
|
|
483
|
+
|
|
469
484
|
---
|
|
470
485
|
|
|
471
486
|
## Reports
|
|
@@ -476,6 +491,7 @@ Browse all historical run results:
|
|
|
476
491
|
- Click a run to see the **full result tree**: Suite → Case → Step
|
|
477
492
|
- Each step shows: status, duration, generated code, and screenshot (on failure)
|
|
478
493
|
- Failed steps show the error message and a screenshot thumbnail
|
|
494
|
+
- A **Downloads** panel appears for runs that captured files (see [File Upload & Download](#file-upload--download)) — click a file to save it locally
|
|
479
495
|
|
|
480
496
|
### Lighthouse Results (Audit Suites)
|
|
481
497
|
|
|
@@ -700,6 +716,85 @@ The Faker Data modal (accessible from the Test Editor) lets you browse 100+ dyna
|
|
|
700
716
|
|
|
701
717
|
---
|
|
702
718
|
|
|
719
|
+
## File Upload & Download
|
|
720
|
+
|
|
721
|
+
### Uploading files (for upload steps)
|
|
722
|
+
|
|
723
|
+
In the **Test Editor**, click the **Files** button (next to *Fake Data*) to open the file picker:
|
|
724
|
+
|
|
725
|
+
1. Click **Choose a file to upload** and pick a file from your machine.
|
|
726
|
+
2. It's saved into your project at **`fixtures/uploads/`** (committed with the repo, so it works in CI) and appears in the list.
|
|
727
|
+
3. Click the file to insert a **`{{FILE:name}}`** token into your step. Delete files with the trash icon.
|
|
728
|
+
|
|
729
|
+
The token resolves to the file's relative path at runtime, so it works with `setInputFiles`:
|
|
730
|
+
|
|
731
|
+
| Step (plain English) | Generated code |
|
|
732
|
+
|----------------------|----------------|
|
|
733
|
+
| `Upload {{FILE:resume.pdf}} to the Resume field` | `await page.getByLabel('Resume').setInputFiles('{{FILE:resume.pdf}}');` |
|
|
734
|
+
| `Upload {{FILE:resume.pdf}}` | `await page.locator('input[type="file"]').setInputFiles('{{FILE:resume.pdf}}');` |
|
|
735
|
+
|
|
736
|
+
For a button that opens a native file chooser, keep the listener and the click in **one step**:
|
|
737
|
+
|
|
738
|
+
```js
|
|
739
|
+
const fileChooserPromise = page.waitForEvent('filechooser');
|
|
740
|
+
await page.getByRole('button', { name: 'Choose File' }).click();
|
|
741
|
+
(await fileChooserPromise).setFiles('{{FILE:resume.pdf}}');
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
Files inside an iframe still need `frameLocator(...)`, e.g.
|
|
745
|
+
`await page.frameLocator('#frame').locator('input[type="file"]').setInputFiles('{{FILE:doc.pdf}}');`
|
|
746
|
+
|
|
747
|
+
**Waiting for the upload to complete** — `setInputFiles` only attaches the file; there is no universal "upload done" event. The step waits for a completion signal:
|
|
748
|
+
|
|
749
|
+
| Step (plain English) | Wait behavior |
|
|
750
|
+
|----------------------|---------------|
|
|
751
|
+
| `Upload {{FILE:resume.pdf}} to the Resume field` | waits for the network to settle (`waitForLoadState('networkidle')`) |
|
|
752
|
+
| `Upload {{FILE:resume.pdf}} to the Resume field and wait for 'Upload complete'` | waits for the success text — **most reliable** |
|
|
753
|
+
| `Upload {{FILE:photo.png}}` | uploads to the page's file input, then waits for network |
|
|
754
|
+
|
|
755
|
+
**Example upload steps:**
|
|
756
|
+
|
|
757
|
+
```text
|
|
758
|
+
Upload {{FILE:resume.pdf}} to the Resume field
|
|
759
|
+
Upload {{FILE:resume.pdf}} to the Resume field and wait for 'Upload complete'
|
|
760
|
+
Upload {{FILE:photo.png}}
|
|
761
|
+
Upload {{FILE:invoice.pdf}} into the Attachment input
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Downloads (auto-captured)
|
|
765
|
+
|
|
766
|
+
You do **not** need any special code to handle downloads — just trigger them with a click. The step
|
|
767
|
+
**waits until the file finishes downloading** (`waitForEvent('download')` → `await download.path()`),
|
|
768
|
+
and the runner **automatically saves every download** to `results/downloads/<runId>/`. Avoid
|
|
769
|
+
`download.saveAs()` / `fs` in steps — the sandbox blocks them and it isn't needed.
|
|
770
|
+
|
|
771
|
+
**Example download steps:**
|
|
772
|
+
|
|
773
|
+
```text
|
|
774
|
+
Download the "Export CSV" link
|
|
775
|
+
Click the "Export" button to download
|
|
776
|
+
Download the file by clicking "Report PDF"
|
|
777
|
+
Click "Download invoice" and wait for download
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
Each generates:
|
|
781
|
+
```js
|
|
782
|
+
const downloadPromise = page.waitForEvent('download');
|
|
783
|
+
await page.getByRole('link', { name: 'Export CSV' }).click();
|
|
784
|
+
const download = await downloadPromise;
|
|
785
|
+
await download.path(); // resolves once the download is complete
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
To view and retrieve captured files:
|
|
789
|
+
|
|
790
|
+
1. Go to **Reports → Run Reports** and click the run to expand it.
|
|
791
|
+
2. A **Downloads** panel at the top lists every file captured during that run (name + size).
|
|
792
|
+
3. Click any file to download it to your local machine.
|
|
793
|
+
|
|
794
|
+
The panel only appears when the run produced downloads.
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
703
798
|
## Visual Regression
|
|
704
799
|
|
|
705
800
|
Visual regression is configured in **Settings** → Visual Regression and reviewed in **Reports** → Visual Diffs / Baselines tabs.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Writing Test Steps
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
Two engines handle generation:
|
|
6
|
+
- **⚡ Template engine** — deterministic, zero AI cost. Handles the common phrasings below (marked ⚡).
|
|
7
|
+
- **AI engine** — handles anything else, and (with **MCP** on) sees the real page to pick accurate locators.
|
|
8
|
+
|
|
9
|
+
Tips that apply everywhere:
|
|
10
|
+
- Put the **target name in quotes** for reliability: `Click the "Sign in" button`.
|
|
11
|
+
- Insert dynamic data with the **Fake Data** picker (`{{FAKE_*}}`) and uploaded files with the **Files** picker (`{{FILE:name}}`).
|
|
12
|
+
- Reference saved values with `{{VAR_NAME}}`; `{{BASE_URL}}` is your configured base URL.
|
|
13
|
+
- Prefix any assertion with **"Soft"** to keep running on failure (`Soft verify …`).
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## UI steps
|
|
18
|
+
|
|
19
|
+
### Navigation ⚡
|
|
20
|
+
```text
|
|
21
|
+
Go to https://example.com
|
|
22
|
+
Navigate to /dashboard
|
|
23
|
+
Open https://demoqa.com/upload-download
|
|
24
|
+
Go back
|
|
25
|
+
Refresh the page
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Click — buttons, links, tabs ⚡
|
|
29
|
+
Name the role so the right locator is used (`getByRole`):
|
|
30
|
+
```text
|
|
31
|
+
Click the "Login" button
|
|
32
|
+
Click on "Submit"
|
|
33
|
+
Click the "Dashboard" link
|
|
34
|
+
Click the "Settings" tab
|
|
35
|
+
Double click the "Row 1" element
|
|
36
|
+
Right click the "File" element
|
|
37
|
+
```
|
|
38
|
+
> 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.
|
|
39
|
+
|
|
40
|
+
### Text input ⚡
|
|
41
|
+
```text
|
|
42
|
+
Enter "deepak" in the Username field
|
|
43
|
+
Type {{FAKE_INTERNET_EMAIL}} in the Email field
|
|
44
|
+
Fill "secret123" in the Password field # password → getByLabel automatically
|
|
45
|
+
Enter {{FAKE_NUMBER_INT}} in the Quantity field # number → spinbutton role
|
|
46
|
+
Clear the Search field
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Dropdowns, checkboxes, radios ⚡
|
|
50
|
+
```text
|
|
51
|
+
Select "India" from the Country dropdown
|
|
52
|
+
Check the "Remember me" checkbox
|
|
53
|
+
Uncheck the "Subscribe" checkbox
|
|
54
|
+
Select the "Male" radio button
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Keyboard ⚡
|
|
58
|
+
```text
|
|
59
|
+
Press Enter
|
|
60
|
+
Press Escape
|
|
61
|
+
Press Tab
|
|
62
|
+
Press "Control+A"
|
|
63
|
+
Type "hello" and press Enter
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Waits, scroll, hover, screenshot ⚡
|
|
67
|
+
```text
|
|
68
|
+
Wait for 2 seconds
|
|
69
|
+
Wait for the page to load
|
|
70
|
+
Scroll down
|
|
71
|
+
Scroll to bottom
|
|
72
|
+
Hover over the "Profile" menu
|
|
73
|
+
Take a screenshot
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### File upload ⚡
|
|
77
|
+
Upload a file with the **Files** picker, then reference its `{{FILE:name}}` token:
|
|
78
|
+
```text
|
|
79
|
+
Upload {{FILE:resume.pdf}} to the Resume field
|
|
80
|
+
Upload {{FILE:resume.pdf}} to the Resume field and wait for 'Upload complete' # most reliable
|
|
81
|
+
Upload {{FILE:photo.png}} # page's file input
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### File download ⚡
|
|
85
|
+
Downloads are auto-captured (Reports → Downloads, and attached to Allure). The step waits until the file finishes:
|
|
86
|
+
```text
|
|
87
|
+
Download the "Export CSV" link
|
|
88
|
+
Click the "Download" button to download
|
|
89
|
+
Download the file by clicking "Report PDF"
|
|
90
|
+
Click "Download invoice" and wait for download
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Assertions ⚡
|
|
94
|
+
```text
|
|
95
|
+
Verify "Welcome back" is visible
|
|
96
|
+
Verify "Error" is not visible
|
|
97
|
+
Verify the page title is "Dashboard"
|
|
98
|
+
Verify the URL contains "/dashboard"
|
|
99
|
+
Verify the "Email" field has value "user@test.com"
|
|
100
|
+
Soft verify "Saved successfully" is visible # continues on failure
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Scenarios the AI handles (MCP recommended)
|
|
104
|
+
```text
|
|
105
|
+
Login as admin using {{ADMIN_EMAIL}} and {{DEFAULT_PASSWORD}}
|
|
106
|
+
Click the "Submit" button inside the payment iframe
|
|
107
|
+
Fill the card number "4111111111111111" in the Stripe iframe
|
|
108
|
+
Accept the confirmation dialog after clicking "Delete"
|
|
109
|
+
Verify the table has 5 rows
|
|
110
|
+
Click the element inside the shadow DOM component
|
|
111
|
+
```
|
|
112
|
+
- **iframes** → wrapped in `page.frameLocator(...)` automatically.
|
|
113
|
+
- **shadow DOM** → locator chaining (`page.locator('host').locator('inner')`).
|
|
114
|
+
- **dialogs** → a `page.once('dialog', …)` handler is added before the trigger.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## API steps
|
|
119
|
+
|
|
120
|
+
Mark a suite/case as **API** type. Steps use Playwright's `page.request` API. Use `{{BASE_URL}}` and saved variables.
|
|
121
|
+
|
|
122
|
+
### Basic requests
|
|
123
|
+
```text
|
|
124
|
+
Send a GET request to {{BASE_URL}}/api/users and verify status is 200
|
|
125
|
+
Send a POST request to {{BASE_URL}}/api/users with body { "name": "John", "email": "john@test.com" } and verify status 201
|
|
126
|
+
Send a PUT request to {{BASE_URL}}/api/users/1 with body { "name": "Jane" }
|
|
127
|
+
Send a DELETE request to {{BASE_URL}}/api/users/1 and verify status 204
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Auth — extract and reuse a token
|
|
131
|
+
```text
|
|
132
|
+
POST to {{BASE_URL}}/api/login with { "email": "{{ADMIN_EMAIL}}", "password": "{{DEFAULT_PASSWORD}}" }, save token as AUTH_TOKEN
|
|
133
|
+
GET {{BASE_URL}}/api/profile with Authorization Bearer {{AUTH_TOKEN}} and verify status 200
|
|
134
|
+
```
|
|
135
|
+
- "save / store / extract … as NAME" → `context.setVariable('NAME', …)`.
|
|
136
|
+
- `{{AUTH_TOKEN}}` (or `context.getVariable`) reuses it in later steps/cases.
|
|
137
|
+
|
|
138
|
+
### Assertions on the response
|
|
139
|
+
```text
|
|
140
|
+
Verify the response status is 200
|
|
141
|
+
Verify the response body has property "id"
|
|
142
|
+
Verify the response field "name" equals "Admin"
|
|
143
|
+
Verify the response has 5 users
|
|
144
|
+
Verify the content-type header contains "application/json"
|
|
145
|
+
Verify the response time is under 500 ms
|
|
146
|
+
Soft verify the response status is 200
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Headers, query params, form bodies
|
|
150
|
+
```text
|
|
151
|
+
Send a GET request to {{BASE_URL}}/api/search with query { "q": "phone", "page": "1" }
|
|
152
|
+
Send a POST to {{BASE_URL}}/api/upload with form { "name": "doc", "type": "pdf" }
|
|
153
|
+
Send a GET to {{BASE_URL}}/api/data with header "X-Api-Key" "{{API_KEY}}"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Soft vs hard assertions
|
|
159
|
+
- **Hard** (default): the test stops at the first failure.
|
|
160
|
+
- **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.
|
|
161
|
+
|
|
162
|
+
## Variables & dynamic data
|
|
163
|
+
| Token | Resolves to |
|
|
164
|
+
|-------|-------------|
|
|
165
|
+
| `{{BASE_URL}}` | Configured base URL for the active environment |
|
|
166
|
+
| `{{FAKE_PERSON_FULLNAME}}`, `{{FAKE_INTERNET_EMAIL}}`, … | Fresh random data each run (Fake Data picker) |
|
|
167
|
+
| `{{FILE:resume.pdf}}` | `fixtures/uploads/resume.pdf` (Files picker) |
|
|
168
|
+
| `{{MY_VAR}}` | A value from Variables or saved earlier with `context.setVariable` |
|
|
169
|
+
|
|
170
|
+
## Editing generated code
|
|
171
|
+
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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assuremind",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "AI-powered codeless UI & API automation framework",
|
|
5
5
|
"author": "Deepak Hiremath",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,12 +41,14 @@
|
|
|
41
41
|
"ai",
|
|
42
42
|
"codeless",
|
|
43
43
|
"no-code",
|
|
44
|
+
"zero-code",
|
|
44
45
|
"test-automation",
|
|
45
46
|
"qa",
|
|
46
47
|
"self-healing",
|
|
47
48
|
"claude",
|
|
48
49
|
"openai",
|
|
49
50
|
"gemini",
|
|
51
|
+
"ollama",
|
|
50
52
|
"ui-testing"
|
|
51
53
|
],
|
|
52
54
|
"scripts": {
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
"@google/generative-ai": "^0.21.0",
|
|
75
77
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
76
78
|
"@playwright/mcp": "^0.0.70",
|
|
77
|
-
"@playwright/test": "^1.
|
|
79
|
+
"@playwright/test": "^1.60.0",
|
|
78
80
|
"allure-commandline": "^2.38.1",
|
|
79
81
|
"allure-js-commons": "^3.0.0",
|
|
80
82
|
"allure-playwright": "^3.0.0",
|
|
@@ -97,10 +99,10 @@
|
|
|
97
99
|
"pino": "^9.4.0",
|
|
98
100
|
"pino-pretty": "^11.2.0",
|
|
99
101
|
"pixelmatch": "^7.1.0",
|
|
100
|
-
"playwright": "^1.
|
|
102
|
+
"playwright": "^1.60.0",
|
|
101
103
|
"pngjs": "^7.0.0",
|
|
102
104
|
"simple-git": "^3.33.0",
|
|
103
|
-
"uuid": "
|
|
105
|
+
"uuid": "11.1.1",
|
|
104
106
|
"zod": "^3.23.0"
|
|
105
107
|
},
|
|
106
108
|
"devDependencies": {
|
|
@@ -113,12 +115,12 @@
|
|
|
113
115
|
"@types/ws": "^8.5.0",
|
|
114
116
|
"@typescript-eslint/eslint-plugin": "^8.8.0",
|
|
115
117
|
"@typescript-eslint/parser": "^8.8.0",
|
|
116
|
-
"@vitest/coverage-v8": "
|
|
118
|
+
"@vitest/coverage-v8": "3.2.6",
|
|
117
119
|
"docx": "^9.6.1",
|
|
118
120
|
"eslint": "^9.12.0",
|
|
119
121
|
"prettier": "^3.3.0",
|
|
120
122
|
"tsup": "^8.3.0",
|
|
121
123
|
"typescript": "^5.6.0",
|
|
122
|
-
"vitest": "
|
|
124
|
+
"vitest": "3.2.6"
|
|
123
125
|
}
|
|
124
126
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Writing Test Steps
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
Two engines handle generation:
|
|
6
|
+
- **⚡ Template engine** — deterministic, zero AI cost. Handles the common phrasings below (marked ⚡).
|
|
7
|
+
- **AI engine** — handles anything else, and (with **MCP** on) sees the real page to pick accurate locators.
|
|
8
|
+
|
|
9
|
+
Tips that apply everywhere:
|
|
10
|
+
- Put the **target name in quotes** for reliability: `Click the "Sign in" button`.
|
|
11
|
+
- Insert dynamic data with the **Fake Data** picker (`{{FAKE_*}}`) and uploaded files with the **Files** picker (`{{FILE:name}}`).
|
|
12
|
+
- Reference saved values with `{{VAR_NAME}}`; `{{BASE_URL}}` is your configured base URL.
|
|
13
|
+
- Prefix any assertion with **"Soft"** to keep running on failure (`Soft verify …`).
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## UI steps
|
|
18
|
+
|
|
19
|
+
### Navigation ⚡
|
|
20
|
+
```text
|
|
21
|
+
Go to https://example.com
|
|
22
|
+
Navigate to /dashboard
|
|
23
|
+
Open https://demoqa.com/upload-download
|
|
24
|
+
Go back
|
|
25
|
+
Refresh the page
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Click — buttons, links, tabs ⚡
|
|
29
|
+
Name the role so the right locator is used (`getByRole`):
|
|
30
|
+
```text
|
|
31
|
+
Click the "Login" button
|
|
32
|
+
Click on "Submit"
|
|
33
|
+
Click the "Dashboard" link
|
|
34
|
+
Click the "Settings" tab
|
|
35
|
+
Double click the "Row 1" element
|
|
36
|
+
Right click the "File" element
|
|
37
|
+
```
|
|
38
|
+
> 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.
|
|
39
|
+
|
|
40
|
+
### Text input ⚡
|
|
41
|
+
```text
|
|
42
|
+
Enter "deepak" in the Username field
|
|
43
|
+
Type {{FAKE_INTERNET_EMAIL}} in the Email field
|
|
44
|
+
Fill "secret123" in the Password field # password → getByLabel automatically
|
|
45
|
+
Enter {{FAKE_NUMBER_INT}} in the Quantity field # number → spinbutton role
|
|
46
|
+
Clear the Search field
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Dropdowns, checkboxes, radios ⚡
|
|
50
|
+
```text
|
|
51
|
+
Select "India" from the Country dropdown
|
|
52
|
+
Check the "Remember me" checkbox
|
|
53
|
+
Uncheck the "Subscribe" checkbox
|
|
54
|
+
Select the "Male" radio button
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Keyboard ⚡
|
|
58
|
+
```text
|
|
59
|
+
Press Enter
|
|
60
|
+
Press Escape
|
|
61
|
+
Press Tab
|
|
62
|
+
Press "Control+A"
|
|
63
|
+
Type "hello" and press Enter
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Waits, scroll, hover, screenshot ⚡
|
|
67
|
+
```text
|
|
68
|
+
Wait for 2 seconds
|
|
69
|
+
Wait for the page to load
|
|
70
|
+
Scroll down
|
|
71
|
+
Scroll to bottom
|
|
72
|
+
Hover over the "Profile" menu
|
|
73
|
+
Take a screenshot
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### File upload ⚡
|
|
77
|
+
Upload a file with the **Files** picker, then reference its `{{FILE:name}}` token:
|
|
78
|
+
```text
|
|
79
|
+
Upload {{FILE:resume.pdf}} to the Resume field
|
|
80
|
+
Upload {{FILE:resume.pdf}} to the Resume field and wait for 'Upload complete' # most reliable
|
|
81
|
+
Upload {{FILE:photo.png}} # page's file input
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### File download ⚡
|
|
85
|
+
Downloads are auto-captured (Reports → Downloads, and attached to Allure). The step waits until the file finishes:
|
|
86
|
+
```text
|
|
87
|
+
Download the "Export CSV" link
|
|
88
|
+
Click the "Download" button to download
|
|
89
|
+
Download the file by clicking "Report PDF"
|
|
90
|
+
Click "Download invoice" and wait for download
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Assertions ⚡
|
|
94
|
+
```text
|
|
95
|
+
Verify "Welcome back" is visible
|
|
96
|
+
Verify "Error" is not visible
|
|
97
|
+
Verify the page title is "Dashboard"
|
|
98
|
+
Verify the URL contains "/dashboard"
|
|
99
|
+
Verify the "Email" field has value "user@test.com"
|
|
100
|
+
Soft verify "Saved successfully" is visible # continues on failure
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Scenarios the AI handles (MCP recommended)
|
|
104
|
+
```text
|
|
105
|
+
Login as admin using {{ADMIN_EMAIL}} and {{DEFAULT_PASSWORD}}
|
|
106
|
+
Click the "Submit" button inside the payment iframe
|
|
107
|
+
Fill the card number "4111111111111111" in the Stripe iframe
|
|
108
|
+
Accept the confirmation dialog after clicking "Delete"
|
|
109
|
+
Verify the table has 5 rows
|
|
110
|
+
Click the element inside the shadow DOM component
|
|
111
|
+
```
|
|
112
|
+
- **iframes** → wrapped in `page.frameLocator(...)` automatically.
|
|
113
|
+
- **shadow DOM** → locator chaining (`page.locator('host').locator('inner')`).
|
|
114
|
+
- **dialogs** → a `page.once('dialog', …)` handler is added before the trigger.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## API steps
|
|
119
|
+
|
|
120
|
+
Mark a suite/case as **API** type. Steps use Playwright's `page.request` API. Use `{{BASE_URL}}` and saved variables.
|
|
121
|
+
|
|
122
|
+
### Basic requests
|
|
123
|
+
```text
|
|
124
|
+
Send a GET request to {{BASE_URL}}/api/users and verify status is 200
|
|
125
|
+
Send a POST request to {{BASE_URL}}/api/users with body { "name": "John", "email": "john@test.com" } and verify status 201
|
|
126
|
+
Send a PUT request to {{BASE_URL}}/api/users/1 with body { "name": "Jane" }
|
|
127
|
+
Send a DELETE request to {{BASE_URL}}/api/users/1 and verify status 204
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Auth — extract and reuse a token
|
|
131
|
+
```text
|
|
132
|
+
POST to {{BASE_URL}}/api/login with { "email": "{{ADMIN_EMAIL}}", "password": "{{DEFAULT_PASSWORD}}" }, save token as AUTH_TOKEN
|
|
133
|
+
GET {{BASE_URL}}/api/profile with Authorization Bearer {{AUTH_TOKEN}} and verify status 200
|
|
134
|
+
```
|
|
135
|
+
- "save / store / extract … as NAME" → `context.setVariable('NAME', …)`.
|
|
136
|
+
- `{{AUTH_TOKEN}}` (or `context.getVariable`) reuses it in later steps/cases.
|
|
137
|
+
|
|
138
|
+
### Assertions on the response
|
|
139
|
+
```text
|
|
140
|
+
Verify the response status is 200
|
|
141
|
+
Verify the response body has property "id"
|
|
142
|
+
Verify the response field "name" equals "Admin"
|
|
143
|
+
Verify the response has 5 users
|
|
144
|
+
Verify the content-type header contains "application/json"
|
|
145
|
+
Verify the response time is under 500 ms
|
|
146
|
+
Soft verify the response status is 200
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Headers, query params, form bodies
|
|
150
|
+
```text
|
|
151
|
+
Send a GET request to {{BASE_URL}}/api/search with query { "q": "phone", "page": "1" }
|
|
152
|
+
Send a POST to {{BASE_URL}}/api/upload with form { "name": "doc", "type": "pdf" }
|
|
153
|
+
Send a GET to {{BASE_URL}}/api/data with header "X-Api-Key" "{{API_KEY}}"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Soft vs hard assertions
|
|
159
|
+
- **Hard** (default): the test stops at the first failure.
|
|
160
|
+
- **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.
|
|
161
|
+
|
|
162
|
+
## Variables & dynamic data
|
|
163
|
+
| Token | Resolves to |
|
|
164
|
+
|-------|-------------|
|
|
165
|
+
| `{{BASE_URL}}` | Configured base URL for the active environment |
|
|
166
|
+
| `{{FAKE_PERSON_FULLNAME}}`, `{{FAKE_INTERNET_EMAIL}}`, … | Fresh random data each run (Fake Data picker) |
|
|
167
|
+
| `{{FILE:resume.pdf}}` | `fixtures/uploads/resume.pdf` (Files picker) |
|
|
168
|
+
| `{{MY_VAR}}` | A value from Variables or saved earlier with `context.setVariable` |
|
|
169
|
+
|
|
170
|
+
## Editing generated code
|
|
171
|
+
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.
|