playwright-cucumber-ts-steps 0.1.7 → 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 (96) hide show
  1. package/README.md +21 -11
  2. package/package.json +9 -2
  3. package/src/actions/clickSteps.ts +364 -142
  4. package/src/actions/cookieSteps.ts +66 -0
  5. package/src/actions/debugSteps.ts +17 -3
  6. package/src/actions/elementFindSteps.ts +822 -117
  7. package/src/actions/fillFormSteps.ts +234 -177
  8. package/src/actions/index.ts +12 -0
  9. package/src/actions/inputSteps.ts +318 -82
  10. package/src/actions/interceptionSteps.ts +295 -57
  11. package/src/actions/miscSteps.ts +984 -254
  12. package/src/actions/mouseSteps.ts +212 -55
  13. package/src/actions/scrollSteps.ts +114 -16
  14. package/src/actions/storageSteps.ts +267 -42
  15. package/src/assertions/buttonAndTextVisibilitySteps.ts +353 -95
  16. package/src/assertions/cookieSteps.ts +115 -36
  17. package/src/assertions/elementSteps.ts +414 -85
  18. package/src/assertions/formInputSteps.ts +375 -108
  19. package/src/assertions/index.ts +11 -0
  20. package/src/assertions/interceptionRequestsSteps.ts +619 -195
  21. package/src/assertions/locationSteps.ts +280 -64
  22. package/src/assertions/roleTestIdSteps.ts +244 -26
  23. package/src/assertions/semanticSteps.ts +257 -69
  24. package/src/assertions/storageSteps.ts +234 -73
  25. package/src/assertions/visualSteps.ts +245 -68
  26. package/src/custom_setups/loginHooks.ts +21 -2
  27. package/src/helpers/world.ts +30 -4
  28. package/src/index.ts +4 -25
  29. package/lib/actions/clickSteps.d.ts +0 -1
  30. package/lib/actions/clickSteps.js +0 -165
  31. package/lib/actions/cookieSteps.d.ts +0 -1
  32. package/lib/actions/cookieSteps.js +0 -28
  33. package/lib/actions/debugSteps.d.ts +0 -1
  34. package/lib/actions/debugSteps.js +0 -8
  35. package/lib/actions/elementFindSteps.d.ts +0 -1
  36. package/lib/actions/elementFindSteps.js +0 -217
  37. package/lib/actions/fillFormSteps.d.ts +0 -1
  38. package/lib/actions/fillFormSteps.js +0 -130
  39. package/lib/actions/inputSteps.d.ts +0 -1
  40. package/lib/actions/inputSteps.js +0 -97
  41. package/lib/actions/interceptionSteps.d.ts +0 -1
  42. package/lib/actions/interceptionSteps.js +0 -71
  43. package/lib/actions/miscSteps.d.ts +0 -1
  44. package/lib/actions/miscSteps.js +0 -320
  45. package/lib/actions/mouseSteps.d.ts +0 -1
  46. package/lib/actions/mouseSteps.js +0 -66
  47. package/lib/actions/scrollSteps.d.ts +0 -1
  48. package/lib/actions/scrollSteps.js +0 -23
  49. package/lib/actions/storageSteps.d.ts +0 -1
  50. package/lib/actions/storageSteps.js +0 -72
  51. package/lib/assertions/buttonAndTextVisibilitySteps.d.ts +0 -1
  52. package/lib/assertions/buttonAndTextVisibilitySteps.js +0 -150
  53. package/lib/assertions/cookieSteps.d.ts +0 -1
  54. package/lib/assertions/cookieSteps.js +0 -45
  55. package/lib/assertions/elementSteps.d.ts +0 -1
  56. package/lib/assertions/elementSteps.js +0 -90
  57. package/lib/assertions/formInputSteps.d.ts +0 -1
  58. package/lib/assertions/formInputSteps.js +0 -87
  59. package/lib/assertions/interceptionRequestsSteps.d.ts +0 -1
  60. package/lib/assertions/interceptionRequestsSteps.js +0 -201
  61. package/lib/assertions/locationSteps.d.ts +0 -1
  62. package/lib/assertions/locationSteps.js +0 -87
  63. package/lib/assertions/roleTestIdSteps.d.ts +0 -1
  64. package/lib/assertions/roleTestIdSteps.js +0 -26
  65. package/lib/assertions/semanticSteps.d.ts +0 -1
  66. package/lib/assertions/semanticSteps.js +0 -67
  67. package/lib/assertions/storageSteps.d.ts +0 -1
  68. package/lib/assertions/storageSteps.js +0 -74
  69. package/lib/assertions/visualSteps.d.ts +0 -1
  70. package/lib/assertions/visualSteps.js +0 -76
  71. package/lib/custom_setups/loginHooks.d.ts +0 -1
  72. package/lib/custom_setups/loginHooks.js +0 -113
  73. package/lib/helpers/checkPeerDeps.d.ts +0 -1
  74. package/lib/helpers/checkPeerDeps.js +0 -19
  75. package/lib/helpers/compareSnapshots.d.ts +0 -6
  76. package/lib/helpers/compareSnapshots.js +0 -20
  77. package/lib/helpers/hooks.d.ts +0 -1
  78. package/lib/helpers/hooks.js +0 -210
  79. package/lib/helpers/utils/fakerUtils.d.ts +0 -1
  80. package/lib/helpers/utils/fakerUtils.js +0 -60
  81. package/lib/helpers/utils/index.d.ts +0 -4
  82. package/lib/helpers/utils/index.js +0 -20
  83. package/lib/helpers/utils/optionsUtils.d.ts +0 -24
  84. package/lib/helpers/utils/optionsUtils.js +0 -88
  85. package/lib/helpers/utils/resolveUtils.d.ts +0 -6
  86. package/lib/helpers/utils/resolveUtils.js +0 -72
  87. package/lib/helpers/utils/sessionUtils.d.ts +0 -3
  88. package/lib/helpers/utils/sessionUtils.js +0 -40
  89. package/lib/helpers/world.d.ts +0 -31
  90. package/lib/helpers/world.js +0 -104
  91. package/lib/iframes/frames.d.ts +0 -1
  92. package/lib/iframes/frames.js +0 -11
  93. package/lib/index.d.ts +0 -28
  94. package/lib/index.js +0 -48
  95. package/lib/register.d.ts +0 -1
  96. package/lib/register.js +0 -6
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.7",
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
  }
@@ -3,94 +3,212 @@ import { When, DataTable } from "@cucumber/cucumber";
3
3
  import { parseClickOptions } from "../helpers/utils/optionsUtils";
4
4
  import { CustomWorld } from "../helpers/world";
5
5
 
6
- When("I click", async function (this: CustomWorld, ...rest: any[]) {
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[]) {
7
22
  const maybeTable = rest[0];
8
23
  const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
9
24
  if (!this.element) throw new Error("❌ No stored element to click.");
10
25
  await this.element.click(options);
11
26
  this.log?.("🖱️ Clicked on stored element");
12
- });
13
-
14
- When(
15
- "I click on element {string}",
16
- async function (this: CustomWorld, selector: string, ...rest: any[]) {
17
- const maybeTable = rest[0];
18
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
19
- const element = this.getLocator(selector);
20
- await element.click(options);
21
- this.element = element;
22
- this.log?.(`🖱️ Clicked on element "${selector}"`);
23
- }
24
- );
25
- When(
26
- "I click on button {string}",
27
- async function (this: CustomWorld, label: string, ...rest: any[]) {
28
- const maybeTable = rest[0];
29
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
30
- const button = await this.page.getByRole("button", { name: label });
31
- await button.click(options);
32
- this.element = button;
33
- this.log?.(`🖱️ Clicked on button "${label}"`);
34
- }
35
- );
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);
36
54
 
37
- When("I click on link {string}", async function (this: CustomWorld, text: string, ...rest: any[]) {
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[]) {
38
96
  const maybeTable = rest[0];
39
97
  const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
40
98
  const link = await this.page.getByRole("link", { name: text });
41
99
  await link.click(options);
42
100
  this.element = link;
43
101
  this.log?.(`✅ Clicked on link "${text}"`);
44
- });
45
-
46
- When(
47
- "I click on label {string}",
48
- async function (this: CustomWorld, labelText: string, ...rest: any[]) {
49
- const maybeTable = rest[0];
50
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
51
- const label = await this.page.getByLabel(labelText);
52
- await label.click(options);
53
- this.element = label;
54
- this.log?.(`🏷️ Clicked on label "${labelText}"`);
55
- }
56
- );
57
-
58
- When(
59
- "I click on text {string}",
60
- async function (this: CustomWorld, rawText: string, ...rest: any[]) {
61
- const maybeTable = rest[0];
62
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
63
-
64
- let text = rawText;
65
- if (rawText.startsWith("@")) {
66
- const alias = rawText.slice(1);
67
- text = this.data[alias];
68
- if (!text) throw new Error(`❌ No value found for alias "@${alias}"`);
69
- }
70
-
71
- const locator = this.page.getByText(text, { exact: false });
72
- await locator.first().waitFor({ state: "visible", timeout: 5000 });
73
- await locator.first().click(options);
74
-
75
- this.element = locator.first();
76
- this.log?.(`🖱️ Clicked on text "${text}"`);
77
- }
78
- );
79
-
80
- When(
81
- "I click on exact text {string}",
82
- async function (this: CustomWorld, exactText: string, ...rest: any[]) {
83
- const maybeTable = rest[0];
84
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
85
- const locator = this.page.getByText(exactText, { exact: true });
86
- await locator.waitFor({ state: "visible", timeout: 5000 });
87
- await locator.click(options);
88
- this.element = locator;
89
- this.log?.(`🖱️ Clicked on exact text "${exactText}"`);
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}"`);
90
155
  }
91
- );
92
156
 
93
- When("I click all", async function (this: CustomWorld, ...rest: any[]) {
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[]) {
94
212
  const maybeTable = rest[0];
95
213
  const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
96
214
  if (!this.elements) throw new Error("❌ No stored elements to click.");
@@ -103,83 +221,171 @@ When("I click all", async function (this: CustomWorld, ...rest: any[]) {
103
221
  this.log?.(`🖱️ Clicked element #${i + 1}`);
104
222
  }
105
223
  this.log?.(`✅ Clicked all ${count} elements.`);
106
- });
107
-
108
- When(
109
- "I double click on text {string}",
110
- async function (this: CustomWorld, text: string, ...rest: any[]) {
111
- const maybeTable = rest[0];
112
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
113
- const element = this.element || this.page.getByText(text);
114
- await element.dblclick(options);
115
- this.log?.(`🖱️ Double-clicked on text "${text}"`);
116
- }
117
- );
118
-
119
- When(
120
- "I double click position {int} {int}",
121
- async function (this: CustomWorld, x: number, y: number, ...rest: any[]) {
122
- const maybeTable = rest[0];
123
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
124
- await this.page.mouse.dblclick(x, y, options);
125
- this.log?.(`🖱️ Double-clicked at (${x}, ${y})`);
126
- }
127
- );
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);
128
276
 
129
- When("I double click", async function (this: CustomWorld, ...rest: any[]) {
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[]) {
130
293
  const maybeTable = rest[0];
131
294
  const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
132
295
  if (!this.element) throw new Error("❌ No stored element to double-click.");
133
296
  await this.element.dblclick(options);
134
297
  this.log?.("🖱️ Double-clicked on stored element");
135
- });
298
+ }
299
+ When("I double click", When_I_double_click);
136
300
 
137
- When("I right click", async function (this: CustomWorld, ...rest: any[]) {
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[]) {
138
317
  const maybeTable = rest[0];
139
318
  const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
140
319
  if (!this.element) throw new Error("❌ No stored element to right-click.");
141
320
  await this.element.click({ button: "right", ...options });
142
321
  this.log?.("🖱️ Right-clicked on stored element");
143
- });
144
-
145
- When(
146
- "I right click on text {string}",
147
- async function (this: CustomWorld, text: string, ...rest: any[]) {
148
- const maybeTable = rest[0];
149
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
150
- const element = this.page.getByText(text);
151
- await element.click({ button: "right", ...options });
152
- this.log?.(`🖱️ Right-clicked on text "${text}"`);
153
- }
154
- );
155
-
156
- When(
157
- "I right click position {int} {int}",
158
- async function (this: CustomWorld, x: number, y: number, ...rest: any[]) {
159
- const maybeTable = rest[0];
160
- const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
161
- await this.page.mouse.click(x, y, { button: "right", ...options });
162
- this.log?.(`🖱️ Right-clicked at (${x}, ${y})`);
163
- }
164
- );
165
-
166
- When("I blur", async function (this: CustomWorld) {
167
- await this.page.evaluate(() => {
168
- const active = document.activeElement;
169
- if (active && typeof (active as HTMLElement).blur === "function") {
170
- (active as HTMLElement).blur();
171
- }
172
- });
173
- this.log?.("🌀 Blurred active element");
174
- });
175
-
176
- When("I focus", async function (this: CustomWorld) {
177
- if (!this.element) throw new Error("❌ No stored element to focus.");
178
- await this.element.focus();
179
- this.log?.("🎯 Focused stored element");
180
- });
181
-
182
- When("I click all", async function (this: CustomWorld, dataTable?: DataTable) {
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) {
183
389
  const options = parseClickOptions(dataTable);
184
390
 
185
391
  if (!this.elements) {
@@ -199,9 +405,25 @@ When("I click all", async function (this: CustomWorld, dataTable?: DataTable) {
199
405
  }
200
406
 
201
407
  this.log?.(`✅ Clicked all ${count} stored elements.`);
202
- });
203
- When(/^I click on selector "([^"]+)"$/, async function (this: CustomWorld, selector: string) {
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) {
204
425
  const locator = this.getLocator(selector);
205
426
  await locator.click();
206
427
  this.log?.(`🖱️ Clicked on selector: ${selector}`);
207
- });
428
+ }
429
+ When(/^I click on selector "([^"]+)"$/, When_I_click_on_selector);