playwright-cucumber-ts-steps 1.0.1 โ 1.0.3
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 +270 -244
- package/dist/backend/actions/formTable.js +34 -0
- package/dist/backend/actions/index.js +5 -0
- package/dist/backend/actions/interactions.js +23 -0
- package/dist/backend/actions/navigation.js +19 -0
- package/dist/backend/api/assertions.js +26 -0
- package/dist/backend/api/index.js +5 -0
- package/dist/backend/api/mock.js +75 -0
- package/dist/backend/api/requests.js +86 -0
- package/dist/backend/api/state.js +15 -0
- package/dist/backend/assertions/expectVisible.js +8 -0
- package/dist/backend/assertions/index.js +5 -0
- package/dist/backend/assertions/pageState.js +25 -0
- package/dist/backend/assertions/text.js +20 -0
- package/dist/backend/assertions/visibility.js +20 -0
- package/dist/backend/auth/index.js +71 -0
- package/dist/backend/db/index.js +6 -0
- package/dist/backend/db/state.js +24 -0
- package/dist/backend/db/steps.js +43 -0
- package/dist/backend/elements/alerts.js +21 -0
- package/dist/backend/elements/forms.js +59 -0
- package/dist/backend/elements/frames.js +25 -0
- package/dist/backend/elements/index.js +5 -0
- package/dist/core/registry.js +20 -0
- package/dist/core/runner.js +151 -0
- package/dist/index.js +10 -0
- package/dist/reporting/index.js +43 -0
- package/package.json +19 -101
- package/LICENSE +0 -21
- package/lib/actions/clickSteps.d.ts +0 -251
- package/lib/actions/clickSteps.js +0 -415
- package/lib/actions/cookieSteps.d.ts +0 -18
- package/lib/actions/cookieSteps.js +0 -93
- package/lib/actions/debugSteps.d.ts +0 -14
- package/lib/actions/debugSteps.js +0 -23
- package/lib/actions/elementFindSteps.d.ts +0 -668
- package/lib/actions/elementFindSteps.js +0 -931
- package/lib/actions/fillFormSteps.d.ts +0 -69
- package/lib/actions/fillFormSteps.js +0 -237
- package/lib/actions/index.d.ts +0 -11
- package/lib/actions/index.js +0 -28
- package/lib/actions/inputSteps.d.ts +0 -218
- package/lib/actions/inputSteps.js +0 -343
- package/lib/actions/interceptionSteps.d.ts +0 -169
- package/lib/actions/interceptionSteps.js +0 -291
- package/lib/actions/miscSteps.d.ts +0 -645
- package/lib/actions/miscSteps.js +0 -1061
- package/lib/actions/mouseSteps.d.ts +0 -143
- package/lib/actions/mouseSteps.js +0 -234
- package/lib/actions/scrollSteps.d.ts +0 -82
- package/lib/actions/scrollSteps.js +0 -123
- package/lib/actions/storageSteps.d.ts +0 -174
- package/lib/actions/storageSteps.js +0 -292
- package/lib/assertions/buttonAndTextVisibilitySteps.d.ts +0 -245
- package/lib/assertions/buttonAndTextVisibilitySteps.js +0 -401
- package/lib/assertions/cookieSteps.d.ts +0 -75
- package/lib/assertions/cookieSteps.js +0 -113
- package/lib/assertions/elementSteps.d.ts +0 -264
- package/lib/assertions/elementSteps.js +0 -388
- package/lib/assertions/formInputSteps.d.ts +0 -248
- package/lib/assertions/formInputSteps.js +0 -350
- package/lib/assertions/index.d.ts +0 -10
- package/lib/assertions/index.js +0 -27
- package/lib/assertions/interceptionRequestsSteps.d.ts +0 -353
- package/lib/assertions/interceptionRequestsSteps.js +0 -593
- package/lib/assertions/locationSteps.d.ts +0 -217
- package/lib/assertions/locationSteps.js +0 -310
- package/lib/assertions/roleTestIdSteps.d.ts +0 -159
- package/lib/assertions/roleTestIdSteps.js +0 -221
- package/lib/assertions/semanticSteps.d.ts +0 -176
- package/lib/assertions/semanticSteps.js +0 -252
- package/lib/assertions/storageSteps.d.ts +0 -149
- package/lib/assertions/storageSteps.js +0 -210
- package/lib/assertions/visualSteps.d.ts +0 -74
- package/lib/assertions/visualSteps.js +0 -209
- package/lib/custom_setups/loginHooks.d.ts +0 -1
- package/lib/custom_setups/loginHooks.js +0 -130
- package/lib/helpers/checkPeerDeps.d.ts +0 -1
- package/lib/helpers/checkPeerDeps.js +0 -19
- package/lib/helpers/compareSnapshots.d.ts +0 -6
- package/lib/helpers/compareSnapshots.js +0 -20
- package/lib/helpers/hooks.d.ts +0 -1
- package/lib/helpers/hooks.js +0 -210
- package/lib/helpers/utils/fakerUtils.d.ts +0 -1
- package/lib/helpers/utils/fakerUtils.js +0 -60
- package/lib/helpers/utils/index.d.ts +0 -4
- package/lib/helpers/utils/index.js +0 -20
- package/lib/helpers/utils/optionsUtils.d.ts +0 -24
- package/lib/helpers/utils/optionsUtils.js +0 -88
- package/lib/helpers/utils/resolveUtils.d.ts +0 -6
- package/lib/helpers/utils/resolveUtils.js +0 -72
- package/lib/helpers/utils/sessionUtils.d.ts +0 -3
- package/lib/helpers/utils/sessionUtils.js +0 -40
- package/lib/helpers/world.d.ts +0 -34
- package/lib/helpers/world.js +0 -110
- package/lib/iframes/frames.d.ts +0 -1
- package/lib/iframes/frames.js +0 -11
- package/lib/index.d.ts +0 -10
- package/lib/index.js +0 -28
- package/lib/register.d.ts +0 -1
- package/lib/register.js +0 -6
- package/src/actions/clickSteps.ts +0 -429
- package/src/actions/cookieSteps.ts +0 -95
- package/src/actions/debugSteps.ts +0 -21
- package/src/actions/elementFindSteps.ts +0 -961
- package/src/actions/fillFormSteps.ts +0 -270
- package/src/actions/index.ts +0 -12
- package/src/actions/inputSteps.ts +0 -354
- package/src/actions/interceptionSteps.ts +0 -325
- package/src/actions/miscSteps.ts +0 -1144
- package/src/actions/mouseSteps.ts +0 -256
- package/src/actions/scrollSteps.ts +0 -122
- package/src/actions/storageSteps.ts +0 -308
- package/src/assertions/buttonAndTextVisibilitySteps.ts +0 -436
- package/src/assertions/cookieSteps.ts +0 -131
- package/src/assertions/elementSteps.ts +0 -432
- package/src/assertions/formInputSteps.ts +0 -377
- package/src/assertions/index.ts +0 -11
- package/src/assertions/interceptionRequestsSteps.ts +0 -640
- package/src/assertions/locationSteps.ts +0 -315
- package/src/assertions/roleTestIdSteps.ts +0 -254
- package/src/assertions/semanticSteps.ts +0 -267
- package/src/assertions/storageSteps.ts +0 -250
- package/src/assertions/visualSteps.ts +0 -275
- package/src/custom_setups/loginHooks.ts +0 -154
- package/src/helpers/checkPeerDeps.ts +0 -19
- package/src/helpers/compareSnapshots.ts +0 -35
- package/src/helpers/hooks.ts +0 -212
- package/src/helpers/utils/fakerUtils.ts +0 -64
- package/src/helpers/utils/index.ts +0 -4
- package/src/helpers/utils/optionsUtils.ts +0 -104
- package/src/helpers/utils/resolveUtils.ts +0 -74
- package/src/helpers/utils/sessionUtils.ts +0 -36
- package/src/helpers/world.ts +0 -119
- package/src/iframes/frames.ts +0 -15
- package/src/index.ts +0 -18
- package/src/register.ts +0 -4
package/README.md
CHANGED
|
@@ -1,343 +1,369 @@
|
|
|
1
|
-
# ๐ญ
|
|
1
|
+
# ๐ญ Playwright Cucumber TS Steps
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/playwright-cucumber-ts-steps)
|
|
4
|
+
[](https://www.npmjs.com/package/playwright-cucumber-ts-steps)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://playwright.dev)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/stargazers)
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
<img src="https://github.com/qaPaschalE/k6-cucumber-steps/blob/main/assets/paschal%20logo%20(2).png?raw=true" alt="paschal Logo" style="margin-top:25px;" align="center"/>
|
|
7
|
-
</td></tr></table>
|
|
10
|
+
**The "Low-Code" BDD Framework for Playwright.**
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
[](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/blob/main/LICENSE)
|
|
11
|
-
[](https://nodejs.org/)
|
|
12
|
-
[](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/actions)
|
|
13
|
-
[](https://www.npmjs.com/package/playwright-cucumber-ts-steps)
|
|
14
|
-
[](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/issues)
|
|
15
|
-
[](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/stargazers)
|
|
12
|
+
Write powerful end-to-end tests in plain English using Gherkin syntax, without managing complex glue code. `playwright-cucumber-ts-steps` provides a pre-built library of robust steps for UI, API, and Authentication testing, running natively inside Playwright.
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
---
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
## ๐ Features
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
- **Zero Boilerplate:** Install and start writing `.feature` files immediately.
|
|
19
|
+
- **Hybrid Testing:** Mix **UI**, **API**, and **Database** steps in a single scenario.
|
|
20
|
+
- **Smart Auth:** Login once, save the session, and reuse it across thousands of tests.
|
|
21
|
+
- **Native Performance:** Runs purely on Playwright (no heavy Cucumber-JS wrapper), giving you Parallelism, Tracing, and Retries out of the box.
|
|
22
|
+
- **Tag Filtering:** Run specific tests like `@smoke` or `@regression` easily.
|
|
23
|
+
- **Auto-Reporting:** Built-in helper for HTML and Slack reports with **screenshots on failure**.
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
- ๐ฏ Support for **UI**, **API**, **mobile**, **iframe**, **hybrid login**, and **visual testing**
|
|
25
|
-
- ๐ง Smart **session management** via storageState, `localStorage`, `sessionStorage`, and alias reuse
|
|
26
|
-
- ๐๏ธ **Alias**, **Faker**, `.env`, and dynamic JSON fixture support
|
|
27
|
-
- ๐ธ **Screenshot** on failure, ๐ฅ **video recording**, and ๐ผ๏ธ **visual diff** with baseline comparison
|
|
28
|
-
- ๐ค Supports **file upload**, **drag-and-drop**, and **multi-user session flows**
|
|
29
|
-
- ๐ Fully supports **API requests with inline assertions**, payload from custom folders, and session injection
|
|
30
|
-
- โ
Compatible with both `Page` and `FrameLocator` contexts (iframe-aware)
|
|
25
|
+
---
|
|
31
26
|
|
|
32
27
|
## ๐ฆ Installation
|
|
33
28
|
|
|
34
29
|
```bash
|
|
35
|
-
npm install playwright-cucumber-ts-steps
|
|
30
|
+
npm install playwright-cucumber-ts-steps @playwright/test
|
|
36
31
|
```
|
|
37
32
|
|
|
38
|
-
or
|
|
39
|
-
|
|
40
33
|
```bash
|
|
41
|
-
|
|
34
|
+
npx playwright install
|
|
42
35
|
```
|
|
43
36
|
|
|
44
37
|
---
|
|
45
38
|
|
|
46
|
-
##
|
|
39
|
+
## โก Quick Start Guide
|
|
47
40
|
|
|
48
|
-
|
|
41
|
+
### 1. Configure Playwright
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
- [`@cucumber/cucumber`](https://github.com/cucumber/cucumber-js)
|
|
52
|
-
- TypeScript
|
|
53
|
-
- Cucumber IDE plugin (Optional), but Highly recommended
|
|
43
|
+
Update `playwright.config.ts` to use the built-in reporting helper.
|
|
54
44
|
|
|
55
|
-
|
|
45
|
+
```typescript
|
|
46
|
+
import { defineConfig } from "@playwright/test";
|
|
47
|
+
import { getReporters } from "playwright-cucumber-ts-steps";
|
|
56
48
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
export default defineConfig({
|
|
50
|
+
testDir: "./tests",
|
|
51
|
+
// Sets up HTML report + Console list automatically
|
|
52
|
+
reporter: getReporters({ on: ["html"] }),
|
|
53
|
+
use: {
|
|
54
|
+
// We handle screenshots manually in the runner,
|
|
55
|
+
// but this is good as a backup
|
|
56
|
+
screenshot: "only-on-failure",
|
|
57
|
+
},
|
|
58
|
+
});
|
|
60
59
|
```
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
### 2. Create the Runner
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
Create a file at `tests/bdd.spec.ts`. This is the entry point.
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
```typescript
|
|
66
|
+
import { runTests } from "playwright-cucumber-ts-steps";
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
// Runs all feature files in the 'features' folder
|
|
69
|
+
runTests("features/*.feature");
|
|
70
|
+
```
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
### 3. Write Your Feature
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
// e2e/steps/index.ts
|
|
74
|
-
import "playwright-cucumber-ts-steps/register";
|
|
75
|
-
```
|
|
74
|
+
Create `features/login.feature`:
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
```gherkin
|
|
77
|
+
Feature: User Authentication
|
|
78
|
+
|
|
79
|
+
@smoke
|
|
80
|
+
Scenario: Successful Login
|
|
81
|
+
Given I visit "[https://the-internet.herokuapp.com/login](https://the-internet.herokuapp.com/login)"
|
|
82
|
+
When I fill "#username" with "tomsmith"
|
|
83
|
+
And I fill "#password" with "SuperSecretPassword!"
|
|
84
|
+
And I click "button[type='submit']"
|
|
85
|
+
Then I expect "#flash" to contain text "You logged into a secure area!"
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
Feature: Login
|
|
87
|
+
```
|
|
81
88
|
|
|
82
|
-
|
|
83
|
-
Given I visit "/login"
|
|
84
|
-
When I find input by name "Email"
|
|
85
|
-
And I type "user@example.com"
|
|
86
|
-
And I click button "Login"
|
|
87
|
-
Then I see visible text "Welcome"
|
|
88
|
-
Then I do not see URL contains "/login"
|
|
89
|
+
### 4. Run Tests
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
```bash
|
|
92
|
+
npx playwright test demo.spec.ts --headed
|
|
93
|
+
```
|
|
91
94
|
|
|
92
95
|
---
|
|
93
96
|
|
|
94
|
-
##
|
|
97
|
+
## ๐ท๏ธ Tags & Filtering
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
- ๐ฌ **Actions**: `I click`, `I type`, `I wait`, `I switch to iframe`, etc.
|
|
98
|
-
- ๐ **Forms**: `I fill the following`, aliasing, dynamic faker values
|
|
99
|
-
- ๐ **API**: Request mocking, assertions, response validation
|
|
100
|
-
- ๐ฑ **Mobile support**: Enable with `@mobile` tag (iPhone 13 emulation)
|
|
101
|
-
- ๐๏ธ **Visual testing**: Enable with `@visual` tag (pixelmatch diff)
|
|
99
|
+
You can use tags to organize your tests and run specific subsets (e.g., only Smoke tests).
|
|
102
100
|
|
|
103
|
-
|
|
101
|
+
**In your Feature file:**
|
|
104
102
|
|
|
105
|
-
|
|
103
|
+
```gherkin
|
|
104
|
+
Feature: Checkout
|
|
106
105
|
|
|
107
|
-
|
|
106
|
+
@smoke @critical
|
|
107
|
+
Scenario: Guest Checkout
|
|
108
|
+
...
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
@regression
|
|
111
|
+
Scenario: Registered User Checkout
|
|
112
|
+
...
|
|
112
113
|
|
|
113
|
-
export class CustomWorld extends BaseWorld {
|
|
114
|
-
// Add your custom context or helpers here
|
|
115
|
-
}
|
|
116
114
|
```
|
|
117
115
|
|
|
118
|
-
|
|
116
|
+
**In your Test Runner (`tests/bdd.spec.ts`):**
|
|
119
117
|
|
|
120
|
-
|
|
118
|
+
```typescript
|
|
119
|
+
import { runTests } from "playwright-cucumber-ts-steps";
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
// OPTION 1: Run Everything
|
|
122
|
+
// runTests('features/*.feature');
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
// OPTION 2: Run only Smoke tests
|
|
125
|
+
runTests("features/*.feature", { tags: "@smoke" });
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
## ๐ก Various Usage Examples
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
// Here below "Email" represents a faker variable "Email: () => faker.internet.email()", Continue button containing text with action click, best for Forms
|
|
132
|
+
### 1. API Testing (Backend Validation)
|
|
134
133
|
|
|
135
|
-
|
|
136
|
-
| Target | Value |
|
|
137
|
-
| [name='email'] | Email |
|
|
138
|
-
| Continue | Click |
|
|
139
|
-
```
|
|
134
|
+
You can validate your backend directly without opening a browser, or mix it with UI tests.
|
|
140
135
|
|
|
141
|
-
|
|
136
|
+
```gherkin
|
|
137
|
+
Feature: User API
|
|
142
138
|
|
|
143
|
-
|
|
139
|
+
@api
|
|
140
|
+
Scenario: Create and Verify User
|
|
141
|
+
When I make a POST request to "[https://reqres.in/api/users](https://reqres.in/api/users)" with body '{"name": "Morpheus", "job": "Leader"}'
|
|
142
|
+
Then I expect the response status to be 201
|
|
143
|
+
And I expect the response property "name" to be "Morpheus"
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
```
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
- ๐ฅ **Video recording per scenario**
|
|
149
|
-
- ๐ **Session reuse** using `storageState`
|
|
147
|
+
### 2. Advanced Elements (Iframes & Uploads)
|
|
150
148
|
|
|
151
|
-
|
|
149
|
+
Handling complex HTML elements is built-in.
|
|
152
150
|
|
|
153
|
-
|
|
151
|
+
```gherkin
|
|
152
|
+
Feature: File Upload and Iframes
|
|
154
153
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
| | - `drag:<targetSelector>` for drag-and-drop |
|
|
162
|
-
| | - `assert:visible`, `assert:text:<value>` |
|
|
163
|
-
| | - `request:<METHOD>:<URL>:<payload>.json` |
|
|
164
|
-
| | - `set:localStorage:<key>`, `set:sessionStorage:<key>` |
|
|
165
|
-
| | - `wait:<ms>`, `reload`, and use alias `@aliasName` |
|
|
166
|
-
| Session Handling | Steps like `I login with a session data "admin.json"`, `I save session as "customer"` |
|
|
167
|
-
| Session Restore | `I restore session cookies "customer" [with reload] [using localStorage]` |
|
|
168
|
-
| API Assertions | Validate JSON response with `assert:json:key=expectedValue` |
|
|
154
|
+
Scenario: Upload Document inside Iframe
|
|
155
|
+
Given I visit "[https://example.com/upload](https://example.com/upload)"
|
|
156
|
+
# Switch context to the iframe
|
|
157
|
+
When I upload file "data/resume.pdf" to "#file-input" inside frame "#upload-iframe"
|
|
158
|
+
And I click "#submit-btn" inside frame "#upload-iframe"
|
|
159
|
+
Then I expect "div.success" inside frame "#upload-iframe" to be visible
|
|
169
160
|
|
|
170
|
-
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3. The "Login Once" Pattern (Authentication)
|
|
171
164
|
|
|
172
|
-
|
|
165
|
+
Speed up your suite by 10x. Login once, save the cookies, and reuse them.
|
|
166
|
+
|
|
167
|
+
**Step 1: Create a Setup Feature (`features/setup.feature`)**
|
|
173
168
|
|
|
174
169
|
```gherkin
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
When I visit "/dashboard"
|
|
188
|
-
Then I see text "Welcome back"
|
|
189
|
-
|
|
190
|
-
Scenario: API login + inject session
|
|
191
|
-
When I fill the following "Login" form data:
|
|
192
|
-
| request:POST:/api/login:adminPayload.json | saveAs:loginData |
|
|
193
|
-
| set:localStorage:token | @loginData.token |
|
|
194
|
-
| save session as | adminViaAPI |
|
|
170
|
+
Feature: Setup
|
|
171
|
+
|
|
172
|
+
@setup
|
|
173
|
+
Scenario: Admin Login
|
|
174
|
+
Given I visit "/login"
|
|
175
|
+
When I fill "#user" with "admin"
|
|
176
|
+
And I fill "#pass" with "1234"
|
|
177
|
+
And I click "#login-btn"
|
|
178
|
+
And I expect "#dashboard" to be visible
|
|
179
|
+
# Saves session to ./auth/admin.json
|
|
180
|
+
And I save the browser state to "admin.json"
|
|
181
|
+
|
|
195
182
|
```
|
|
196
183
|
|
|
197
|
-
|
|
184
|
+
**Step 2: Use in Daily Tests (`features/admin.feature`)**
|
|
185
|
+
|
|
186
|
+
```gherkin
|
|
187
|
+
Feature: Admin Panel
|
|
188
|
+
|
|
189
|
+
Scenario: Check Reports
|
|
190
|
+
# Loads cookies instantly - No login UI needed!
|
|
191
|
+
Given I load the browser state from "admin.json"
|
|
192
|
+
When I visit "/admin/reports"
|
|
193
|
+
Then I expect "h1" to have text "Weekly Reports"
|
|
198
194
|
|
|
199
|
-
### โ
Folder Structure Suggestion
|
|
200
|
-
|
|
201
|
-
```text
|
|
202
|
-
e2e/
|
|
203
|
-
โโโ features/ # .feature files
|
|
204
|
-
โโโ step_definitions/
|
|
205
|
-
โ โโโ index.ts # import from this package
|
|
206
|
-
โโโ support/
|
|
207
|
-
โ โโโ world.ts # CustomWorld extends with iframe support
|
|
208
|
-
โ โโโ hooks.ts # artifact & session manager
|
|
209
|
-
โ โโโ helpers/
|
|
210
|
-
โ โโโ resolveUtils.ts # alias/env/json resolver
|
|
211
|
-
โโโ test-data/ # JSON fixtures
|
|
212
|
-
โโโ payload/ # API request payloads
|
|
213
195
|
```
|
|
214
196
|
|
|
215
|
-
|
|
197
|
+
### 4. Data Tables (Forms)
|
|
216
198
|
|
|
217
|
-
|
|
199
|
+
Fill out entire forms in a single step using a Data Table. You can type, click, check, or assert visibility in one go.
|
|
218
200
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
-
|
|
223
|
-
-
|
|
224
|
-
|
|
201
|
+
```gherkin
|
|
202
|
+
Scenario: Registration
|
|
203
|
+
When I fill the following "Registration" form data:
|
|
204
|
+
| #first-name | John |
|
|
205
|
+
| #last-name | Doe |
|
|
206
|
+
| #email | john@test.com |
|
|
207
|
+
| #newsletter | check |
|
|
208
|
+
| #submit-btn | click |
|
|
209
|
+
| .success | assert:visible |
|
|
210
|
+
```
|
|
225
211
|
|
|
226
|
-
|
|
212
|
+
### 5. API Testing (Tables & Files)
|
|
227
213
|
|
|
228
|
-
|
|
214
|
+
Validate your backend directly. You can send payloads via Tables or JSON Files.
|
|
229
215
|
|
|
230
|
-
|
|
231
|
-
import path from "path";
|
|
232
|
-
import dotenv from "dotenv";
|
|
216
|
+
#### Option A: Data Table Payload
|
|
233
217
|
|
|
234
|
-
|
|
218
|
+
```gherkin
|
|
219
|
+
Scenario: Create User (Table)
|
|
220
|
+
When I make a POST request to "[https://reqres.in/api/users](https://reqres.in/api/users)" with data:
|
|
221
|
+
| name | Neo |
|
|
222
|
+
| job | The Chosen |
|
|
223
|
+
Then I expect the response status to be 201
|
|
224
|
+
And I expect the response property "name" to be "Neo"
|
|
225
|
+
```
|
|
235
226
|
|
|
236
|
-
|
|
227
|
+
#### Option B: File Payload
|
|
237
228
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
enableVisualTest: process.env.ENABLE_VISUAL_TEST === "true",
|
|
245
|
-
device: process.env.MOBILE_DEVICE || undefined, // e.g., "Pixel 5"
|
|
246
|
-
};
|
|
229
|
+
```gherkin
|
|
230
|
+
Scenario: Create User (File)
|
|
231
|
+
# Reads from 'data/user.json' in your project root
|
|
232
|
+
When I make a POST request to "/api/users" with payload from "data/user.json"
|
|
233
|
+
Then I expect the response status to be 201
|
|
234
|
+
```
|
|
247
235
|
|
|
248
|
-
|
|
249
|
-
default: {
|
|
250
|
-
require: ["ts-node/register", "src/test/steps/**/*.ts", "src/test/support/**/*.ts"],
|
|
251
|
-
format: ["progress", `html:${path.join(ARTIFACT_DIR, "report.html")}`],
|
|
252
|
-
publishQuiet: true,
|
|
253
|
-
paths: ["src/test/features/**/*.feature"],
|
|
254
|
-
parallel: 2,
|
|
255
|
-
worldParameters: defaultWorldParams,
|
|
256
|
-
},
|
|
236
|
+
### 6. Network Mocking
|
|
257
237
|
|
|
258
|
-
|
|
259
|
-
require: ["ts-node/register", "src/test/steps/**/*.ts", "src/test/support/**/*.ts"],
|
|
260
|
-
format: ["progress"],
|
|
261
|
-
publishQuiet: true,
|
|
262
|
-
paths: ["src/test/features/**/*.feature"],
|
|
263
|
-
parallel: 1,
|
|
264
|
-
tags: "@mobile",
|
|
265
|
-
worldParameters: {
|
|
266
|
-
...defaultWorldParams,
|
|
267
|
-
device: process.env.MOBILE_DEVICE || "iPhone 13 Pro",
|
|
268
|
-
},
|
|
269
|
-
},
|
|
238
|
+
Simulate backend responses to test UI behavior without relying on real APIs.
|
|
270
239
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
enableVisualTest: true,
|
|
280
|
-
},
|
|
281
|
-
},
|
|
240
|
+
```gherkin
|
|
241
|
+
Scenario: Mocking User Profile
|
|
242
|
+
# Intercept calls to /api/user/1 and return fake data
|
|
243
|
+
Given I mock the API endpoint "*/**/api/user/1" with body '{"name": "Mocked User"}'
|
|
244
|
+
|
|
245
|
+
# When the UI calls the API, it gets our fake data
|
|
246
|
+
When I visit "/profile"
|
|
247
|
+
Then I expect "#username-display" to have text "Mocked User"
|
|
282
248
|
|
|
283
|
-
ci: {
|
|
284
|
-
require: ["ts-node/register", "src/test/steps/**/*.ts", "src/test/support/**/*.ts"],
|
|
285
|
-
format: ["progress", `json:${path.join(ARTIFACT_DIR, "report.json")}`],
|
|
286
|
-
publishQuiet: true,
|
|
287
|
-
paths: ["src/test/features/**/*.feature"],
|
|
288
|
-
parallel: 4,
|
|
289
|
-
worldParameters: {
|
|
290
|
-
...defaultWorldParams,
|
|
291
|
-
enableScreenshots: true,
|
|
292
|
-
enableVideos: true,
|
|
293
|
-
enableVisualTest: false,
|
|
294
|
-
},
|
|
295
|
-
},
|
|
296
|
-
};
|
|
297
249
|
```
|
|
298
250
|
|
|
299
|
-
|
|
251
|
+
### 7. Database Testing (Adapter Pattern)
|
|
300
252
|
|
|
301
|
-
|
|
253
|
+
You can validate database states by injecting your own DB driver into the runner.
|
|
302
254
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
255
|
+
**1. In your `bdd.spec.ts`:**
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { runTests } from "playwright-cucumber-ts-steps";
|
|
259
|
+
import pg from "pg"; // Your driver (pg, mysql, mongo, etc)
|
|
306
260
|
|
|
307
|
-
|
|
308
|
-
|
|
261
|
+
// wrapper function
|
|
262
|
+
const queryDb = async (query: string) => {
|
|
263
|
+
const client = new pg.Client(process.env.DB_URL);
|
|
264
|
+
await client.connect();
|
|
265
|
+
const res = await client.query(query);
|
|
266
|
+
await client.end();
|
|
267
|
+
return res.rows; // Must return an array of objects
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
runTests("features/*.feature", { dbQuery: queryDb });
|
|
271
|
+
```
|
|
309
272
|
|
|
310
|
-
|
|
311
|
-
ENABLE_VISUAL_TEST=true npx cucumber-js --config cucumber.js --profile visual
|
|
273
|
+
**2. In your `Feature file`:**
|
|
312
274
|
|
|
313
|
-
|
|
314
|
-
|
|
275
|
+
```gherkin
|
|
276
|
+
Scenario: Create User
|
|
277
|
+
When I run the database query "INSERT INTO users (name) VALUES ('Bob')"
|
|
278
|
+
Then I expect the database to return 1 record
|
|
279
|
+
And I expect the first database record to contain:
|
|
280
|
+
| name | Bob |
|
|
315
281
|
```
|
|
316
282
|
|
|
317
283
|
---
|
|
318
284
|
|
|
319
|
-
|
|
285
|
+
## ๐ Step Glossary (Cheat Sheet)
|
|
286
|
+
|
|
287
|
+
### ๐ฑ๏ธ Actions
|
|
288
|
+
|
|
289
|
+
| Step | Usage Example |
|
|
290
|
+
| ---------------- | -------------------------------------- |
|
|
291
|
+
| **Visit** | `I visit "https://google.com"` |
|
|
292
|
+
| **Click** | `I click "#submit-btn"` |
|
|
293
|
+
| **Force Click** | `I force click "#hidden-btn"` |
|
|
294
|
+
| **Double Click** | `I double click ".icon"` |
|
|
295
|
+
| **Fill Input** | `I fill "#email" with "user@test.com"` |
|
|
296
|
+
| **Press Key** | `I press "Enter"` (or "Tab", "Escape") |
|
|
297
|
+
| **Wait** | `I wait for 2000 milliseconds` |
|
|
298
|
+
| **Reload** | `I reload the page` |
|
|
299
|
+
| **Go Back** | `I go back` |
|
|
300
|
+
|
|
301
|
+
### โ
Assertions
|
|
302
|
+
|
|
303
|
+
| Step | Usage Example |
|
|
304
|
+
| ---------------- | -------------------------------------------------------------- |
|
|
305
|
+
| **Visibility** | `I expect "#modal" to be visible` |
|
|
306
|
+
| **Hidden** | `I expect "#loader" to be hidden` |
|
|
307
|
+
| **Exact Text** | `I expect "#header" to have text "Welcome"` |
|
|
308
|
+
| **Partial Text** | `I expect ".error" to contain text "Failed"` |
|
|
309
|
+
| **Input Value** | `I expect "#username" to have value "admin"` |
|
|
310
|
+
| **Exact URL** | `I expect the url to be "https://site.com/home"` |
|
|
311
|
+
| **Partial URL** | `I expect the url to contain "/dashboard"` |
|
|
312
|
+
| **Title** | `I expect the title to contain "Home Page"` |
|
|
313
|
+
| **Attribute** | `I expect "img" to have attribute "src" with value "logo.png"` |
|
|
314
|
+
| **Screenshot** | `I expect the page screenshot to match "home.png"` |
|
|
315
|
+
|
|
316
|
+
### ๐งฉ Forms & Elements
|
|
317
|
+
|
|
318
|
+
| Step | Usage Example |
|
|
319
|
+
| --------------------- | ---------------------------------------------- |
|
|
320
|
+
| **Select (Dropdown)** | `I select option "Canada" from "#country"` |
|
|
321
|
+
| **Check Box** | `I check "#terms-checkbox"` |
|
|
322
|
+
| **Uncheck** | `I uncheck "#newsletter"` |
|
|
323
|
+
| **Upload File** | `I upload file "data.csv" to "#upload"` |
|
|
324
|
+
| **Handle Alert** | `I accept the next dialog` |
|
|
325
|
+
| **Frame Click** | `I click "#btn" inside frame "#payment-frame"` |
|
|
326
|
+
|
|
327
|
+
### ๐ API
|
|
328
|
+
|
|
329
|
+
| Step | Usage Example |
|
|
330
|
+
| ---------------- | ------------------------------------------------------------- |
|
|
331
|
+
| **GET** | `I make a GET request to "/api/users"` |
|
|
332
|
+
| **DELETE** | `I make a DELETE request to "/api/users/1"` |
|
|
333
|
+
| **POST** | `I make a POST request to "/api/login" with body '{"u":"1"}'` |
|
|
334
|
+
| **Status Check** | `I expect the response status to be 200` |
|
|
335
|
+
| **JSON Check** | `I expect the response property "data.id" to be "99"` |
|
|
320
336
|
|
|
321
|
-
|
|
322
|
-
| ------------------ | -------------------- | --------------------- | ------------------------------------------- |
|
|
323
|
-
| Screenshot toggle | `ENABLE_SCREENSHOTS` | `enableScreenshots` | Capture screenshots on failure |
|
|
324
|
-
| Video toggle | `ENABLE_VIDEOS` | `enableVideos` | Enable/disable video recording |
|
|
325
|
-
| Visual testing | `ENABLE_VISUAL_TEST` | `enableVisualTest` | Capture and compare visual snapshots |
|
|
326
|
-
| Artifact directory | `TEST_ARTIFACT_DIR` | `artifactDir` | Where to save screenshots, videos, etc. |
|
|
327
|
-
| Mobile device emu | `MOBILE_DEVICE` | `device` | Device name for Playwright mobile emulation |
|
|
337
|
+
---
|
|
328
338
|
|
|
329
|
-
##
|
|
339
|
+
## ๐ ๏ธ Extending (Custom Steps)
|
|
330
340
|
|
|
331
|
-
|
|
341
|
+
Need a step that isn't included? You can easily register your own in your spec file.
|
|
332
342
|
|
|
333
|
-
|
|
343
|
+
```typescript
|
|
344
|
+
// tests/bdd.spec.ts
|
|
345
|
+
import { runTests, Step } from "playwright-cucumber-ts-steps";
|
|
346
|
+
|
|
347
|
+
// 1. Define custom step
|
|
348
|
+
Step("I scroll to the bottom of the page", async (page) => {
|
|
349
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// 2. Run tests
|
|
353
|
+
runTests("features/*.feature");
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Then use it in your feature:
|
|
334
357
|
|
|
335
|
-
|
|
358
|
+
```gherkin
|
|
359
|
+
Scenario: Scroll Test
|
|
360
|
+
Given I visit "[https://infinite-scroll.com](https://infinite-scroll.com)"
|
|
361
|
+
When I scroll to the bottom of the page
|
|
336
362
|
|
|
337
|
-
|
|
363
|
+
```
|
|
338
364
|
|
|
339
365
|
---
|
|
340
366
|
|
|
341
|
-
##
|
|
367
|
+
## ๐ License
|
|
342
368
|
|
|
343
|
-
|
|
369
|
+
MIT ยฉ 2024
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const registry_1 = require("../../core/registry");
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
// CHANGE: Removed the ':' at the end of the string below
|
|
6
|
+
(0, registry_1.Step)("I fill the following {string} form data", async (page, formName, tableData) => {
|
|
7
|
+
console.log(`๐ Processing Form: ${formName}`);
|
|
8
|
+
// The runner passes the table data as the last argument
|
|
9
|
+
// tableData = [ ['#username', 'tomsmith'], ['#password', '...'] ]
|
|
10
|
+
// Guard clause: Ensure tableData exists to prevent crashes if user forgets the table
|
|
11
|
+
if (!tableData || !Array.isArray(tableData)) {
|
|
12
|
+
throw new Error(`โ The step "I fill the following '${formName}' form data" requires a Data Table below it.`);
|
|
13
|
+
}
|
|
14
|
+
for (const row of tableData) {
|
|
15
|
+
const selector = row[0];
|
|
16
|
+
const value = row[1];
|
|
17
|
+
if (value === "click") {
|
|
18
|
+
await page.click(selector);
|
|
19
|
+
}
|
|
20
|
+
else if (value === "check") {
|
|
21
|
+
await page.check(selector);
|
|
22
|
+
}
|
|
23
|
+
else if (value === "assert:visible") {
|
|
24
|
+
await (0, test_1.expect)(page.locator(selector)).toBeVisible();
|
|
25
|
+
}
|
|
26
|
+
else if (value.startsWith("assert:text:")) {
|
|
27
|
+
const text = value.replace("assert:text:", "");
|
|
28
|
+
await (0, test_1.expect)(page.locator(selector)).toHaveText(text);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
await page.fill(selector, value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|