playwright-cucumber-ts-steps 0.1.6 → 1.0.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.
Files changed (105) hide show
  1. package/README.md +21 -11
  2. package/package.json +9 -2
  3. package/src/actions/clickSteps.ts +429 -0
  4. package/src/actions/cookieSteps.ts +95 -0
  5. package/src/actions/debugSteps.ts +21 -0
  6. package/src/actions/elementFindSteps.ts +961 -0
  7. package/src/actions/fillFormSteps.ts +270 -0
  8. package/src/actions/index.ts +12 -0
  9. package/src/actions/inputSteps.ts +354 -0
  10. package/src/actions/interceptionSteps.ts +325 -0
  11. package/src/actions/miscSteps.ts +1144 -0
  12. package/src/actions/mouseSteps.ts +256 -0
  13. package/src/actions/scrollSteps.ts +122 -0
  14. package/src/actions/storageSteps.ts +308 -0
  15. package/src/assertions/buttonAndTextVisibilitySteps.ts +436 -0
  16. package/src/assertions/cookieSteps.ts +131 -0
  17. package/src/assertions/elementSteps.ts +432 -0
  18. package/src/assertions/formInputSteps.ts +377 -0
  19. package/src/assertions/index.ts +11 -0
  20. package/src/assertions/interceptionRequestsSteps.ts +640 -0
  21. package/src/assertions/locationSteps.ts +315 -0
  22. package/src/assertions/roleTestIdSteps.ts +254 -0
  23. package/src/assertions/semanticSteps.ts +267 -0
  24. package/src/assertions/storageSteps.ts +250 -0
  25. package/src/assertions/visualSteps.ts +275 -0
  26. package/src/custom_setups/loginHooks.ts +154 -0
  27. package/src/helpers/checkPeerDeps.ts +19 -0
  28. package/src/helpers/compareSnapshots.ts +35 -0
  29. package/src/helpers/hooks.ts +212 -0
  30. package/src/helpers/utils/fakerUtils.ts +64 -0
  31. package/src/helpers/utils/optionsUtils.ts +104 -0
  32. package/src/helpers/utils/resolveUtils.ts +74 -0
  33. package/src/helpers/utils/sessionUtils.ts +36 -0
  34. package/src/helpers/world.ts +119 -0
  35. package/src/iframes/frames.ts +15 -0
  36. package/src/index.ts +18 -0
  37. package/src/register.ts +4 -0
  38. package/lib/actions/clickSteps.d.ts +0 -1
  39. package/lib/actions/clickSteps.js +0 -165
  40. package/lib/actions/cookieSteps.d.ts +0 -1
  41. package/lib/actions/cookieSteps.js +0 -28
  42. package/lib/actions/debugSteps.d.ts +0 -1
  43. package/lib/actions/debugSteps.js +0 -8
  44. package/lib/actions/elementFindSteps.d.ts +0 -1
  45. package/lib/actions/elementFindSteps.js +0 -217
  46. package/lib/actions/fillFormSteps.d.ts +0 -1
  47. package/lib/actions/fillFormSteps.js +0 -130
  48. package/lib/actions/inputSteps.d.ts +0 -1
  49. package/lib/actions/inputSteps.js +0 -97
  50. package/lib/actions/interceptionSteps.d.ts +0 -1
  51. package/lib/actions/interceptionSteps.js +0 -71
  52. package/lib/actions/miscSteps.d.ts +0 -1
  53. package/lib/actions/miscSteps.js +0 -320
  54. package/lib/actions/mouseSteps.d.ts +0 -1
  55. package/lib/actions/mouseSteps.js +0 -66
  56. package/lib/actions/scrollSteps.d.ts +0 -1
  57. package/lib/actions/scrollSteps.js +0 -23
  58. package/lib/actions/storageSteps.d.ts +0 -1
  59. package/lib/actions/storageSteps.js +0 -72
  60. package/lib/assertions/buttonAndTextVisibilitySteps.d.ts +0 -1
  61. package/lib/assertions/buttonAndTextVisibilitySteps.js +0 -150
  62. package/lib/assertions/cookieSteps.d.ts +0 -1
  63. package/lib/assertions/cookieSteps.js +0 -45
  64. package/lib/assertions/elementSteps.d.ts +0 -1
  65. package/lib/assertions/elementSteps.js +0 -90
  66. package/lib/assertions/formInputSteps.d.ts +0 -1
  67. package/lib/assertions/formInputSteps.js +0 -87
  68. package/lib/assertions/interceptionRequestsSteps.d.ts +0 -1
  69. package/lib/assertions/interceptionRequestsSteps.js +0 -201
  70. package/lib/assertions/locationSteps.d.ts +0 -1
  71. package/lib/assertions/locationSteps.js +0 -87
  72. package/lib/assertions/roleTestIdSteps.d.ts +0 -1
  73. package/lib/assertions/roleTestIdSteps.js +0 -26
  74. package/lib/assertions/semanticSteps.d.ts +0 -1
  75. package/lib/assertions/semanticSteps.js +0 -67
  76. package/lib/assertions/storageSteps.d.ts +0 -1
  77. package/lib/assertions/storageSteps.js +0 -74
  78. package/lib/assertions/visualSteps.d.ts +0 -1
  79. package/lib/assertions/visualSteps.js +0 -76
  80. package/lib/custom_setups/loginHooks.d.ts +0 -1
  81. package/lib/custom_setups/loginHooks.js +0 -113
  82. package/lib/helpers/checkPeerDeps.d.ts +0 -1
  83. package/lib/helpers/checkPeerDeps.js +0 -19
  84. package/lib/helpers/compareSnapshots.d.ts +0 -6
  85. package/lib/helpers/compareSnapshots.js +0 -20
  86. package/lib/helpers/hooks.d.ts +0 -1
  87. package/lib/helpers/hooks.js +0 -210
  88. package/lib/helpers/utils/fakerUtils.d.ts +0 -1
  89. package/lib/helpers/utils/fakerUtils.js +0 -60
  90. package/lib/helpers/utils/index.js +0 -20
  91. package/lib/helpers/utils/optionsUtils.d.ts +0 -24
  92. package/lib/helpers/utils/optionsUtils.js +0 -88
  93. package/lib/helpers/utils/resolveUtils.d.ts +0 -6
  94. package/lib/helpers/utils/resolveUtils.js +0 -72
  95. package/lib/helpers/utils/sessionUtils.d.ts +0 -3
  96. package/lib/helpers/utils/sessionUtils.js +0 -40
  97. package/lib/helpers/world.d.ts +0 -31
  98. package/lib/helpers/world.js +0 -104
  99. package/lib/iframes/frames.d.ts +0 -1
  100. package/lib/iframes/frames.js +0 -11
  101. package/lib/index.d.ts +0 -28
  102. package/lib/index.js +0 -48
  103. package/lib/register.d.ts +0 -1
  104. package/lib/register.js +0 -6
  105. /package/{lib/helpers/utils/index.d.ts → src/helpers/utils/index.ts} +0 -0
package/README.md CHANGED
@@ -1,17 +1,22 @@
1
1
  # 🎭 playwright-cucumber-ts-steps
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/playwright-cucumber-ts-steps.svg)](https://www.npmjs.com/package/playwright-cucumber-ts-steps)
4
- [![license](https://img.shields.io/npm/l/playwright-cucumber-ts-steps.svg)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/blob/main/LICENSE)
5
- [![build](https://img.shields.io/github/actions/workflow/status/qaPaschalE/playwright-cucumber-ts-steps/ci.yml?branch=main)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/actions)
6
- [![types](https://img.shields.io/npm/types/playwright-cucumber-ts-steps.svg)](https://www.npmjs.com/package/playwright-cucumber-ts-steps)
7
- [![GitHub issues](https://img.shields.io/github/issues/qaPaschalE/playwright-cucumber-ts-steps)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/issues)
8
- [![GitHub stars](https://img.shields.io/github/stars/qaPaschalE/playwright-cucumber-ts-steps)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/stargazers)
3
+ [![NPM](https://nodei.co/npm/playwright-cucumber-ts-steps.png?downloads=true&downloadRank=true&stars=true&height=3)](https://nodei.co/npm/playwright-cucumber-ts-steps/)
9
4
 
10
- > A collection of reusable Playwright step definitions for Cucumber in TypeScript, designed to streamline end-to-end testing across web, API, and mobile applications.
5
+ <table align="center" style="margin-bottom:30px;"><tr><td align="center" width="9999" heigth="9999" >
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>
11
8
 
12
- Here's the updated **README** with all the latest features and corrections integrated into your `playwright-cucumber-ts-steps` package:
9
+ [![npm](https://img.shields.io/npm/v/playwright-cucumber-ts-steps?logo=npm)](https://www.npmjs.com/package/playwright-cucumber-ts-steps)
10
+ [![License](https://img.shields.io/github/license/qaPaschalE/playwright-cucumber-ts-steps?logo=github)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/blob/main/LICENSE)
11
+ [![Node.js](https://img.shields.io/badge/node-%3E=18-green?logo=node.js)](https://nodejs.org/)
12
+ [![Build Status](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/actions)
13
+ [![TypeScript](https://img.shields.io/badge/types-TypeScript-blue?logo=typescript)](https://www.npmjs.com/package/playwright-cucumber-ts-steps)
14
+ [![Issues](https://img.shields.io/github/issues/qaPaschalE/playwright-cucumber-ts-steps?logo=github)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/issues)
15
+ [![Stars](https://img.shields.io/github/stars/qaPaschalE/playwright-cucumber-ts-steps?logo=github)](https://github.com/qaPaschalE/playwright-cucumber-ts-steps/stargazers)
13
16
 
14
- ---
17
+ > A collection of reusable Playwright step definitions for Cucumber in TypeScript, designed to streamline end-to-end testing across web, API, and mobile applications.
18
+
19
+ > **Note:** This package is designed for advanced Cucumber+Playwright+TypeScript setups. For basic Playwright usage, see the [official Playwright docs](https://playwright.dev/).
15
20
 
16
21
  ## ✨ Features
17
22
 
@@ -54,6 +59,10 @@ npm install --save-dev @playwright/test @cucumber/cucumber typescript ts-node
54
59
  npx playwright install
55
60
  ```
56
61
 
62
+ ## 📘 Step Definition Documentation
63
+
64
+ 👉 [View Steps Documentation](https://qapaschale.github.io/playwright-cucumber-ts-steps/) and [examples](https://github.com/qaPaschale/playwright-cucumber-ts-steps/tree/master/playwright/e2e).
65
+
57
66
  ---
58
67
 
59
68
  ## 🛠️ Usage
@@ -229,8 +238,9 @@ const ARTIFACT_DIR = process.env.TEST_ARTIFACT_DIR || "test-artifacts";
229
238
  const defaultWorldParams = {
230
239
  artifactDir: ARTIFACT_DIR,
231
240
  payloadDir: "payloads",
232
- enableScreenshots: process.env.ENABLE_SCREENSHOTS !== "false",
233
- enableVideos: process.env.ENABLE_VIDEOS !== "false",
241
+ enableTrace: process.env.ENABLE_TRACE || "fail", // "false" | "fail" | "all"
242
+ enableScreenshots: process.env.ENABLE_SCREENSHOTS || "fail", // "false" | "fail" | "all"
243
+ enableVideos: process.env.ENABLE_VIDEOS || "all", // "false" | "fail" | "all"
234
244
  enableVisualTest: process.env.ENABLE_VISUAL_TEST === "true",
235
245
  device: process.env.MOBILE_DEVICE || undefined, // e.g., "Pixel 5"
236
246
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright-cucumber-ts-steps",
3
- "version": "0.1.6",
3
+ "version": "1.0.0",
4
4
  "description": "A collection of reusable Playwright step definitions for Cucumber in TypeScript, designed to streamline end-to-end testing across web, API, and mobile applications.",
5
5
  "type": "commonjs",
6
6
  "main": "lib/index.js",
@@ -26,7 +26,8 @@
26
26
  },
27
27
  "scripts": {
28
28
  "build": "tsc",
29
- "docs": "typedoc src",
29
+ "docs": "typedoc",
30
+ "docs:deploy": "gh-pages -d temp-docs",
30
31
  "prepare": "husky",
31
32
  "lint": "eslint . --ext .ts",
32
33
  "lint:fix": "eslint . --ext .ts --fix",
@@ -79,6 +80,10 @@
79
80
  "@cucumber/cucumber": "*",
80
81
  "@playwright/test": "*"
81
82
  },
83
+ "files": [
84
+ "lib/",
85
+ "src/"
86
+ ],
82
87
  "dependencies": {
83
88
  "@cucumber/tag-expressions": "^6.2.0",
84
89
  "@faker-js/faker": "^9.8.0",
@@ -96,10 +101,12 @@
96
101
  "eslint": "^9.29.0",
97
102
  "eslint-config-prettier": "^10.1.5",
98
103
  "eslint-plugin-import": "^2.32.0",
104
+ "gh-pages": "^6.3.0",
99
105
  "husky": "^9.1.7",
100
106
  "lint-staged": "^16.1.2",
101
107
  "prettier": "^3.5.3",
102
108
  "ts-node": "^10.9.2",
109
+ "typedoc": "^0.28.5",
103
110
  "typescript": "^5.8.3",
104
111
  "typescript-eslint": "^8.34.1"
105
112
  }
@@ -0,0 +1,429 @@
1
+ // e2e/step_definitions/common/actions/clickSteps.ts
2
+ import { When, DataTable } from "@cucumber/cucumber";
3
+ import { parseClickOptions } from "../helpers/utils/optionsUtils";
4
+ import { CustomWorld } from "../helpers/world";
5
+
6
+ /**
7
+ * Clicks on the previously stored element.
8
+ *
9
+ * ```gherkin
10
+ * When I click
11
+ * ```
12
+ *
13
+ * @example
14
+ * ```gherkin
15
+ * When I click
16
+ * ```
17
+ * @remarks
18
+ * Requires a previous step that stores an element.
19
+ * @category Click Steps
20
+ */
21
+ export async function When_I_click(this: CustomWorld, ...rest: any[]) {
22
+ const maybeTable = rest[0];
23
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
24
+ if (!this.element) throw new Error("❌ No stored element to click.");
25
+ await this.element.click(options);
26
+ this.log?.("🖱️ Clicked on stored element");
27
+ }
28
+ When("I click", When_I_click);
29
+
30
+ /**
31
+ * Clicks on an element matching the given selector.
32
+ *
33
+ * ```gherkin
34
+ * When I click on element {string}
35
+ * ```
36
+ *
37
+ * @example
38
+ * ```gherkin
39
+ * When I click on element ".my-class"
40
+ * ```
41
+ * @remarks
42
+ * Stores the clicked element for later use.
43
+ * @category Click Steps
44
+ */
45
+ export async function When_I_click_on_element(this: CustomWorld, selector: string, ...rest: any[]) {
46
+ const maybeTable = rest[0];
47
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
48
+ const element = this.getLocator(selector);
49
+ await element.click(options);
50
+ this.element = element;
51
+ this.log?.(`🖱️ Clicked on element "${selector}"`);
52
+ }
53
+ When("I click on element {string}", When_I_click_on_element);
54
+
55
+ /**
56
+ * Clicks on a button with the given label.
57
+ *
58
+ * ```gherkin
59
+ * When I click on button {string}
60
+ * ```
61
+ *
62
+ * @example
63
+ * ```gherkin
64
+ * When I click on button "Submit"
65
+ * ```
66
+ * @remarks
67
+ * Stores the clicked button for later use.
68
+ * @category Click Steps
69
+ */
70
+ export async function When_I_click_on_button(this: CustomWorld, label: string, ...rest: any[]) {
71
+ const maybeTable = rest[0];
72
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
73
+ const button = await this.page.getByRole("button", { name: label });
74
+ await button.click(options);
75
+ this.element = button;
76
+ this.log?.(`🖱️ Clicked on button "${label}"`);
77
+ }
78
+ When("I click on button {string}", When_I_click_on_button);
79
+
80
+ /**
81
+ * Clicks on a link with the given text.
82
+ *
83
+ * ```gherkin
84
+ * When I click on link {string}
85
+ * ```
86
+ *
87
+ * @example
88
+ * ```gherkin
89
+ * When I click on link "Home"
90
+ * ```
91
+ * @remarks
92
+ * Stores the clicked link for later use.
93
+ * @category Click Steps
94
+ */
95
+ export async function When_I_click_on_link(this: CustomWorld, text: string, ...rest: any[]) {
96
+ const maybeTable = rest[0];
97
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
98
+ const link = await this.page.getByRole("link", { name: text });
99
+ await link.click(options);
100
+ this.element = link;
101
+ this.log?.(`✅ Clicked on link "${text}"`);
102
+ }
103
+ When("I click on link {string}", When_I_click_on_link);
104
+
105
+ /**
106
+ * Clicks on a label with the given text.
107
+ *
108
+ * ```gherkin
109
+ * When I click on label {string}
110
+ * ```
111
+ *
112
+ * @example
113
+ * ```gherkin
114
+ * When I click on label "Username"
115
+ * ```
116
+ * @remarks
117
+ * Stores the clicked label for later use.
118
+ * @category Click Steps
119
+ */
120
+ export async function When_I_click_on_label(this: CustomWorld, labelText: string, ...rest: any[]) {
121
+ const maybeTable = rest[0];
122
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
123
+ const label = await this.page.getByLabel(labelText);
124
+ await label.click(options);
125
+ this.element = label;
126
+ this.log?.(`🏷️ Clicked on label "${labelText}"`);
127
+ }
128
+ When("I click on label {string}", When_I_click_on_label);
129
+
130
+ /**
131
+ * Clicks on an element containing the given text (not exact match). Supports aliasing with @alias.
132
+ *
133
+ * ```gherkin
134
+ * When I click on text {string}
135
+ * ```
136
+ *
137
+ * @example
138
+ * ```gherkin
139
+ * When I click on text "Welcome"
140
+ * When I click on text "@username"
141
+ * ```
142
+ * @remarks
143
+ * Stores the clicked element for later use.
144
+ * @category Click Steps
145
+ */
146
+ export async function When_I_click_on_text(this: CustomWorld, rawText: string, ...rest: any[]) {
147
+ const maybeTable = rest[0];
148
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
149
+
150
+ let text = rawText;
151
+ if (rawText.startsWith("@")) {
152
+ const alias = rawText.slice(1);
153
+ text = this.data[alias];
154
+ if (!text) throw new Error(`❌ No value found for alias "@${alias}"`);
155
+ }
156
+
157
+ const locator = this.page.getByText(text, { exact: false });
158
+ await locator.first().waitFor({ state: "visible", timeout: 5000 });
159
+ await locator.first().click(options);
160
+
161
+ this.element = locator.first();
162
+ this.log?.(`🖱️ Clicked on text "${text}"`);
163
+ }
164
+ When("I click on text {string}", When_I_click_on_text);
165
+
166
+ /**
167
+ * Clicks on an element containing the exact given text.
168
+ *
169
+ * ```gherkin
170
+ * When I click on exact text {string}
171
+ * ```
172
+ *
173
+ * @example
174
+ * ```gherkin
175
+ * When I click on exact text "Log out"
176
+ * ```
177
+ * @remarks
178
+ * Stores the clicked element for later use.
179
+ * @category Click Steps
180
+ */
181
+ export async function When_I_click_on_exact_text(
182
+ this: CustomWorld,
183
+ exactText: string,
184
+ ...rest: any[]
185
+ ) {
186
+ const maybeTable = rest[0];
187
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
188
+ const locator = this.page.getByText(exactText, { exact: true });
189
+ await locator.waitFor({ state: "visible", timeout: 5000 });
190
+ await locator.click(options);
191
+ this.element = locator;
192
+ this.log?.(`🖱️ Clicked on exact text "${exactText}"`);
193
+ }
194
+ When("I click on exact text {string}", When_I_click_on_exact_text);
195
+
196
+ /**
197
+ * Clicks all previously stored elements.
198
+ *
199
+ * ```gherkin
200
+ * When I click all
201
+ * ```
202
+ *
203
+ * @example
204
+ * ```gherkin
205
+ * When I click all
206
+ * ```
207
+ * @remarks
208
+ * Requires a previous step that stores elements.
209
+ * @category Click Steps
210
+ */
211
+ export async function When_I_click_all(this: CustomWorld, ...rest: any[]) {
212
+ const maybeTable = rest[0];
213
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
214
+ if (!this.elements) throw new Error("❌ No stored elements to click.");
215
+ const count = await this.elements.count();
216
+ if (count === 0) throw new Error("⚠️ No elements found to click.");
217
+ for (let i = 0; i < count; i++) {
218
+ const el = this.elements.nth(i);
219
+ await el.waitFor({ state: "visible", timeout: 5000 });
220
+ await el.click(options);
221
+ this.log?.(`🖱️ Clicked element #${i + 1}`);
222
+ }
223
+ this.log?.(`✅ Clicked all ${count} elements.`);
224
+ }
225
+ When("I click all", When_I_click_all);
226
+
227
+ /**
228
+ * Double-clicks on an element containing the given text.
229
+ *
230
+ * ```gherkin
231
+ * When I double click on text {string}
232
+ * ```
233
+ *
234
+ * @example
235
+ * ```gherkin
236
+ * When I double click on text "Edit"
237
+ * ```
238
+ * @remarks
239
+ * Uses the previously stored element if available.
240
+ * @category Click Steps
241
+ */
242
+ export async function When_I_double_click_on_text(this: CustomWorld, text: string, ...rest: any[]) {
243
+ const maybeTable = rest[0];
244
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
245
+ const element = this.element || this.page.getByText(text);
246
+ await element.dblclick(options);
247
+ this.log?.(`🖱️ Double-clicked on text "${text}"`);
248
+ }
249
+ When("I double click on text {string}", When_I_double_click_on_text);
250
+
251
+ /**
252
+ * Double-clicks at the given page coordinates.
253
+ *
254
+ * ```gherkin
255
+ * When I double click position {int} {int}
256
+ * ```
257
+ *
258
+ * @example
259
+ * ```gherkin
260
+ * When I double click position 100 200
261
+ * ```
262
+ * @category Click Steps
263
+ */
264
+ export async function When_I_double_click_position(
265
+ this: CustomWorld,
266
+ x: number,
267
+ y: number,
268
+ ...rest: any[]
269
+ ) {
270
+ const maybeTable = rest[0];
271
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
272
+ await this.page.mouse.dblclick(x, y, options);
273
+ this.log?.(`🖱️ Double-clicked at (${x}, ${y})`);
274
+ }
275
+ When("I double click position {int} {int}", When_I_double_click_position);
276
+
277
+ /**
278
+ * Double-clicks on the previously stored element.
279
+ *
280
+ * ```gherkin
281
+ * When I double click
282
+ * ```
283
+ *
284
+ * @example
285
+ * ```gherkin
286
+ * When I double click
287
+ * ```
288
+ * @remarks
289
+ * Requires a previous step that stores an element.
290
+ * @category Click Steps
291
+ */
292
+ export async function When_I_double_click(this: CustomWorld, ...rest: any[]) {
293
+ const maybeTable = rest[0];
294
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
295
+ if (!this.element) throw new Error("❌ No stored element to double-click.");
296
+ await this.element.dblclick(options);
297
+ this.log?.("🖱️ Double-clicked on stored element");
298
+ }
299
+ When("I double click", When_I_double_click);
300
+
301
+ /**
302
+ * Right-clicks on the previously stored element.
303
+ *
304
+ * ```gherkin
305
+ * When I right click
306
+ * ```
307
+ *
308
+ * @example
309
+ * ```gherkin
310
+ * When I right click
311
+ * ```
312
+ * @remarks
313
+ * Requires a previous step that stores an element.
314
+ * @category Click Steps
315
+ */
316
+ export async function When_I_right_click(this: CustomWorld, ...rest: any[]) {
317
+ const maybeTable = rest[0];
318
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
319
+ if (!this.element) throw new Error("❌ No stored element to right-click.");
320
+ await this.element.click({ button: "right", ...options });
321
+ this.log?.("🖱️ Right-clicked on stored element");
322
+ }
323
+ When("I right click", When_I_right_click);
324
+
325
+ /**
326
+ * Right-clicks on an element containing the given text.
327
+ *
328
+ * ```gherkin
329
+ * When I right click on text {string}
330
+ * ```
331
+ *
332
+ * @example
333
+ * ```gherkin
334
+ * When I right click on text "Options"
335
+ * ```
336
+ * @category Click Steps
337
+ */
338
+ export async function When_I_right_click_on_text(this: CustomWorld, text: string, ...rest: any[]) {
339
+ const maybeTable = rest[0];
340
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
341
+ const element = this.page.getByText(text);
342
+ await element.click({ button: "right", ...options });
343
+ this.log?.(`🖱️ Right-clicked on text "${text}"`);
344
+ }
345
+ When("I right click on text {string}", When_I_right_click_on_text);
346
+
347
+ /**
348
+ * Right-clicks at the given page coordinates.
349
+ *
350
+ * ```gherkin
351
+ * When I right click position {int} {int}
352
+ * ```
353
+ *
354
+ * @example
355
+ * ```gherkin
356
+ * When I right click position 50 50
357
+ * ```
358
+ * @category Click Steps
359
+ */
360
+ export async function When_I_right_click_position(
361
+ this: CustomWorld,
362
+ x: number,
363
+ y: number,
364
+ ...rest: any[]
365
+ ) {
366
+ const maybeTable = rest[0];
367
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
368
+ await this.page.mouse.click(x, y, { button: "right", ...options });
369
+ this.log?.(`🖱️ Right-clicked at (${x}, ${y})`);
370
+ }
371
+ When("I right click position {int} {int}", When_I_right_click_position);
372
+
373
+ /**
374
+ * Clicks all stored elements (alternative signature).
375
+ *
376
+ * ```gherkin
377
+ * When I click all
378
+ * ```
379
+ *
380
+ * @example
381
+ * ```gherkin
382
+ * When I click all
383
+ * ```
384
+ * @remarks
385
+ * Requires a previous step that stores elements.
386
+ * @category Click Steps
387
+ */
388
+ export async function When_I_click_all_alt(this: CustomWorld, dataTable?: DataTable) {
389
+ const options = parseClickOptions(dataTable);
390
+
391
+ if (!this.elements) {
392
+ throw new Error("❌ No elements stored. Use a 'find' step before 'I click all'.");
393
+ }
394
+
395
+ const count = await this.elements.count();
396
+ if (count === 0) {
397
+ throw new Error("⚠️ Stored elements are empty. Nothing to click.");
398
+ }
399
+
400
+ for (let i = 0; i < count; i++) {
401
+ const element = this.elements.nth(i);
402
+ await element.waitFor({ state: "visible", timeout: 5000 });
403
+ await element.click(options);
404
+ this.log?.(`🖱️ Clicked element #${i + 1}`);
405
+ }
406
+
407
+ this.log?.(`✅ Clicked all ${count} stored elements.`);
408
+ }
409
+ When("I click all", When_I_click_all_alt);
410
+
411
+ /**
412
+ * Clicks on an element matching the given selector (regex step).
413
+ *
414
+ * ```gherkin
415
+ * When I click on selector {string}
416
+ * ```
417
+ *
418
+ * @example
419
+ * ```gherkin
420
+ * When I click on selector ".my-selector"
421
+ * ```
422
+ * @category Click Steps
423
+ */
424
+ export async function When_I_click_on_selector(this: CustomWorld, selector: string) {
425
+ const locator = this.getLocator(selector);
426
+ await locator.click();
427
+ this.log?.(`🖱️ Clicked on selector: ${selector}`);
428
+ }
429
+ When(/^I click on selector "([^"]+)"$/, When_I_click_on_selector);
@@ -0,0 +1,95 @@
1
+ // e2e/step_definitions/common/actions/cookieSteps.ts
2
+ import { When } from "@cucumber/cucumber";
3
+
4
+ /**
5
+ * @step
6
+ * @description Clears all cookies in the current browser context.
7
+ * @example
8
+ * When I clear all cookies
9
+ */
10
+ When("I clear all cookies", async function () {
11
+ await this.page.context().clearCookies();
12
+ this.log("Cleared all cookies");
13
+ });
14
+
15
+ /**
16
+ * @step
17
+ * @description Clears all cookies in the current browser context (alias).
18
+ * @example
19
+ * When I clear cookies
20
+ */
21
+ When("I clear cookies", async function () {
22
+ await this.page.context().clearCookies();
23
+ this.log("Cleared cookies (alias)");
24
+ });
25
+
26
+ /**
27
+ * @step
28
+ * @description Clears a specific cookie by name.
29
+ * @example
30
+ * When I clear cookie "session_id"
31
+ */
32
+ When("I clear cookie {string}", async function (name: string) {
33
+ await this.page.context().addCookies([
34
+ {
35
+ name,
36
+ value: "",
37
+ domain: new URL(this.page.url()).hostname,
38
+ path: "/",
39
+ expires: 0,
40
+ },
41
+ ]);
42
+ this.log(`Cleared cookie: ${name}`);
43
+ });
44
+
45
+ /**
46
+ * @step
47
+ * @description Logs all cookies in the current browser context to the console.
48
+ * @example
49
+ * When I log all cookies
50
+ */
51
+ When("I log all cookies", async function () {
52
+ const cookies = await this.page.context().cookies();
53
+ console.log("Cookies:", cookies);
54
+ });
55
+
56
+ /**
57
+ * @step
58
+ * @description Sets a cookie with the given name and value for the current domain.
59
+ * @example
60
+ * When I set cookie "session_id" to "abc123"
61
+ * @remarks
62
+ * The cookie is set for the current page's domain and path "/".
63
+ * @category Cookie Steps
64
+ */
65
+ export async function When_I_set_cookie(this: any, name: string, value: string) {
66
+ const url = new URL(this.page.url());
67
+ await this.page.context().addCookies([
68
+ {
69
+ name,
70
+ value,
71
+ domain: url.hostname,
72
+ path: "/",
73
+ expires: Math.floor(Date.now() / 1000) + 3600, // 1 hour from now
74
+ httpOnly: false,
75
+ secure: false,
76
+ sameSite: "Lax",
77
+ },
78
+ ]);
79
+ this.log?.(`Set cookie: ${name}=${value}`);
80
+ }
81
+ When("I set cookie {string} to {string}", When_I_set_cookie);
82
+
83
+ /**
84
+ * @step
85
+ * @description Gets a cookie value by name and logs it.
86
+ * @example
87
+ * When I get cookie "session_id"
88
+ * @category Cookie Steps
89
+ */
90
+ export async function When_I_get_cookie(this: any, name: string) {
91
+ const cookies = await this.page.context().cookies();
92
+ const found = cookies.find((c: any) => c.name === name);
93
+ this.log?.(`Cookie "${name}": ${found ? found.value : "not found"}`);
94
+ }
95
+ When("I get cookie {string}", When_I_get_cookie);
@@ -0,0 +1,21 @@
1
+ // e2e/step_definitions/common/actions/debugSteps.ts
2
+ import { When } from "@cucumber/cucumber";
3
+
4
+ /**
5
+ * Pauses the test execution for debugging with a custom message.
6
+ *
7
+ * ```gherkin
8
+ * When I debug with message {string}
9
+ * ```
10
+ *
11
+ * @example
12
+ * ```gherkin
13
+ * When I debug with message "Check login form"
14
+ * ```
15
+ * @category Debug Steps
16
+ */
17
+ export async function When_I_debug_with_message(this: any, message: string) {
18
+ await this.page.pause();
19
+ this.log?.(`Paused test for debugging: ${message}`);
20
+ }
21
+ When("I debug with message {string}", When_I_debug_with_message);