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
@@ -0,0 +1,256 @@
1
+ // e2e/step_definitions/common/mouseSteps.ts
2
+ import { When } from "@cucumber/cucumber";
3
+ import { CustomWorld } from "../helpers/world"; // Assuming this path is correct
4
+
5
+ // ===================================================================================
6
+ // MOUSE ACTIONS: SCROLLING
7
+ // ===================================================================================
8
+
9
+ /**
10
+ * Scrolls the element matching the given selector into view.
11
+ * This is useful for making sure an element is visible before interacting with it.
12
+ *
13
+ * ```gherkin
14
+ * When I scroll {string} into view
15
+ * ```
16
+ *
17
+ * @param selector - The CSS selector of the element to scroll into view.
18
+ *
19
+ * @example
20
+ * When I scroll ".footer-section" into view
21
+ *
22
+ * @remarks
23
+ * This step uses Playwright's `locator.scrollIntoViewIfNeeded()`.
24
+ * It will scroll the page or scrollable container as little as possible to bring
25
+ * the element into the viewport.
26
+ * @category Scrolling Steps
27
+ */
28
+ export async function When_I_scroll_element_into_view(this: CustomWorld, selector: string) {
29
+ const locator = this.getScope().locator(selector);
30
+ await locator.scrollIntoViewIfNeeded();
31
+ this.log?.(`๐Ÿ–ฑ๏ธ Scrolled element "${selector}" into view.`);
32
+ }
33
+ When(/^I scroll "([^"]+)" into view$/, When_I_scroll_element_into_view);
34
+
35
+ /**
36
+ * Scrolls the element matching the given selector to a specific X and Y position.
37
+ * The scrolling is relative to the element's own scrollable area.
38
+ *
39
+ * ```gherkin
40
+ * When I scroll {string} to position x:{int} y:{int}
41
+ * ```
42
+ *
43
+ * @param selector - The CSS selector of the element to scroll.
44
+ * @param x - The X-coordinate (horizontal) to scroll to within the element.
45
+ * @param y - The Y-coordinate (vertical) to scroll to within the element.
46
+ *
47
+ * @example
48
+ * When I scroll ".my-scrollable-div" to position x:100 y:200
49
+ *
50
+ * @remarks
51
+ * This step uses `locator.evaluate()` to execute `element.scrollTo()` directly
52
+ * in the browser context. This is typically used for scrolling within a specific
53
+ * scrollable HTML element, not the main window.
54
+ * @category Scrolling Steps
55
+ */
56
+ export async function When_I_scroll_element_to_position(
57
+ this: CustomWorld,
58
+ selector: string,
59
+ x: number, // Changed to number as Cucumber's {int} already parses it
60
+ y: number // Changed to number
61
+ ) {
62
+ const locator = this.getScope().locator(selector);
63
+ await locator.evaluate(
64
+ (el: Element, coords: { x: number; y: number }) => {
65
+ el.scrollTo(coords.x, coords.y);
66
+ },
67
+ { x, y } // Pass coordinates as an object
68
+ );
69
+ this.log?.(`๐Ÿ–ฑ๏ธ Scrolled element "${selector}" to position x:${x} y:${y}.`);
70
+ }
71
+ When(/^I scroll "([^"]+)" to position x:(\d+) y:(\d+)$/, When_I_scroll_element_to_position);
72
+
73
+ /**
74
+ * Scrolls the entire window to specific X and Y coordinates.
75
+ * The coordinates are absolute positions on the page.
76
+ *
77
+ * ```gherkin
78
+ * When I scroll to coordinates x:{int} y:{int}
79
+ * ```
80
+ *
81
+ * @param x - The X-coordinate (horizontal) to scroll the window to.
82
+ * @param y - The Y-coordinate (vertical) to scroll the window to.
83
+ *
84
+ * @example
85
+ * When I scroll to coordinates x:0 y:500
86
+ *
87
+ * @remarks
88
+ * This step uses `page.evaluate()` to execute `window.scrollTo()` directly
89
+ * in the browser context. This controls the main browser window's scroll position.
90
+ * @category Scrolling Steps
91
+ */
92
+ export async function When_I_scroll_to_coordinates(
93
+ this: CustomWorld,
94
+ x: number, // Changed to number
95
+ y: number // Changed to number
96
+ ) {
97
+ await this.page.evaluate(
98
+ (coords: { x: number; y: number }) => {
99
+ window.scrollTo(coords.x, coords.y);
100
+ },
101
+ { x, y } // Pass coordinates as an object
102
+ );
103
+ this.log?.(`๐Ÿ–ฑ๏ธ Scrolled window to coordinates x:${x} y:${y}.`);
104
+ }
105
+ When(/^I scroll to coordinates x:(\d+) y:(\d+)$/, When_I_scroll_to_coordinates);
106
+
107
+ /**
108
+ * Scrolls the entire window to a specified top and left position with a smooth animation.
109
+ *
110
+ * ```gherkin
111
+ * When I scroll window to position top:{int} left:{int}
112
+ * ```
113
+ *
114
+ * @param top - The Y-coordinate (vertical) to scroll the window to.
115
+ * @param left - The X-coordinate (horizontal) to scroll the window to.
116
+ *
117
+ * @example
118
+ * When I scroll window to position top:0 left:100
119
+ *
120
+ * @remarks
121
+ * This step uses `page.evaluate()` to execute `window.scrollTo()` with a `behavior: "smooth"`
122
+ * option in the browser context, providing a native smooth scrolling experience.
123
+ * @category Scrolling Steps
124
+ */
125
+ export async function When_I_scroll_mouse_window_to_position(
126
+ this: CustomWorld,
127
+ top: number, // Changed to number
128
+ left: number // Changed to number
129
+ ) {
130
+ await this.page.evaluate(
131
+ (coords: { top: number; left: number }) => {
132
+ window.scrollTo({
133
+ top: coords.top,
134
+ left: coords.left,
135
+ behavior: "smooth",
136
+ });
137
+ },
138
+ { top, left } // Pass coordinates as an object
139
+ );
140
+ this.log?.(`๐Ÿ–ฑ๏ธ Scrolled window to position top:${top} left:${left} (smooth).`);
141
+ }
142
+ When(
143
+ /^I scroll mouse window to position top:(\d+) left:(\d+)$/,
144
+ When_I_scroll_mouse_window_to_position
145
+ );
146
+
147
+ /**
148
+ * Scrolls the window to a predefined direction (top, bottom, left, or right) with smooth behavior.
149
+ *
150
+ * ```gherkin
151
+ * When I scroll to "{word}"
152
+ * ```
153
+ *
154
+ * @param direction - The direction to scroll to: "top", "bottom", "left", or "right".
155
+ *
156
+ * @example
157
+ * When I scroll to "bottom"
158
+ * When I scroll to "top"
159
+ *
160
+ * @remarks
161
+ * This step evaluates `window.scrollTo()` in the browser context, setting the `top`
162
+ * or `left` property based on the `direction`. It includes a short `waitForTimeout`
163
+ * to allow the smooth scroll animation to complete.
164
+ * @category Scrolling Steps
165
+ */
166
+ export async function When_I_scroll_to_direction(this: CustomWorld, direction: string) {
167
+ const validDirections = ["top", "bottom", "left", "right"];
168
+ if (!validDirections.includes(direction)) {
169
+ throw new Error(
170
+ `Invalid scroll direction "${direction}". Must be one of: ${validDirections.join(", ")}.`
171
+ );
172
+ }
173
+
174
+ await this.page.evaluate((dir) => {
175
+ const scrollOptions: ScrollToOptions = {
176
+ behavior: "smooth",
177
+ };
178
+
179
+ switch (dir) {
180
+ case "top":
181
+ scrollOptions.top = 0;
182
+ break;
183
+ case "bottom":
184
+ // Scroll to the bottom of the body's scroll height
185
+ scrollOptions.top = document.body.scrollHeight;
186
+ break;
187
+ case "left":
188
+ scrollOptions.left = 0;
189
+ break;
190
+ case "right":
191
+ // Scroll to the rightmost edge of the body's scroll width
192
+ scrollOptions.left = document.body.scrollWidth;
193
+ break;
194
+ }
195
+ window.scrollTo(scrollOptions);
196
+ }, direction);
197
+
198
+ this.log?.(`๐Ÿ–ฑ๏ธ Scrolled to "${direction}".`);
199
+ // Allow a brief moment for the smooth scroll animation to complete
200
+ await this.page.waitForTimeout(500);
201
+ }
202
+ When('I scroll to "{word}"', When_I_scroll_to_direction);
203
+
204
+ // ===================================================================================
205
+ // MOUSE ACTIONS: HOVERING / MOVEMENT
206
+ // ===================================================================================
207
+
208
+ /**
209
+ * Hovers the mouse cursor over the element matching the given selector.
210
+ *
211
+ * ```gherkin
212
+ * When I hover over the element {string}
213
+ * ```
214
+ *
215
+ * @param selector - The CSS selector of the element to hover over.
216
+ *
217
+ * @example
218
+ * When I hover over the element ".dropdown-menu-trigger"
219
+ * Then I should see element ".dropdown-content"
220
+ *
221
+ * @remarks
222
+ * This step simulates a mouse hover event. It also stores the hovered element
223
+ * in {@link CustomWorld.element | this.element} for potential subsequent actions.
224
+ * @category Mouse Interaction Steps
225
+ */
226
+ export async function When_I_hover_over_the_element(this: CustomWorld, selector: string) {
227
+ const element = this.getScope().locator(selector);
228
+ await element.hover();
229
+ this.element = element; // Store the hovered element as the current element
230
+ this.log?.(`๐Ÿ–ฑ๏ธ Hovered over: "${selector}".`);
231
+ }
232
+ When("I hover over the element {string}", When_I_hover_over_the_element);
233
+
234
+ /**
235
+ * Moves the mouse cursor to the given absolute X and Y coordinates on the page.
236
+ *
237
+ * ```gherkin
238
+ * When I move mouse to coordinates {int}, {int}
239
+ * ```
240
+ *
241
+ * @param x - The X-coordinate in pixels.
242
+ * @param y - The Y-coordinate in pixels.
243
+ *
244
+ * @example
245
+ * When I move mouse to coordinates 100, 200
246
+ *
247
+ * @remarks
248
+ * This step directly controls the mouse cursor position using Playwright's
249
+ * `page.mouse.move()`. This is a low-level mouse action.
250
+ * @category Mouse Interaction Steps
251
+ */
252
+ export async function When_I_move_mouse_to_coordinates(this: CustomWorld, x: number, y: number) {
253
+ await this.page.mouse.move(x, y);
254
+ this.log?.(`๐Ÿงญ Mouse moved to (${x}, ${y}).`);
255
+ }
256
+ When("I move mouse to coordinates {int}, {int}", When_I_move_mouse_to_coordinates);
@@ -0,0 +1,122 @@
1
+ // e2e/step_definitions/common/scrollSteps.ts
2
+ import { When } from "@cucumber/cucumber";
3
+ import { CustomWorld } from "../helpers/world"; // Assuming this path is correct
4
+
5
+ // ===================================================================================
6
+ // SCROLLING ACTIONS
7
+ // ===================================================================================
8
+
9
+ /**
10
+ * Scrolls the previously selected element into the viewport if it's not already visible.
11
+ *
12
+ * ```gherkin
13
+ * When I scroll into view
14
+ * ```
15
+ *
16
+ * @example
17
+ * When I find element by selector ".my-long-content-element"
18
+ * And I scroll into view
19
+ *
20
+ * @remarks
21
+ * This step requires a preceding step that sets the {@link CustomWorld.element | current element}
22
+ * (e.g., "When I find element by selector"). It uses Playwright's `locator.scrollIntoViewIfNeeded()`,
23
+ * which scrolls the least amount necessary to make the element visible.
24
+ * @category Scrolling Steps
25
+ */
26
+ export async function When_I_scroll_into_view(this: CustomWorld) {
27
+ const element = this.element;
28
+ if (!element) throw new Error("No element selected. Use a 'find element' step before this.");
29
+ await element.scrollIntoViewIfNeeded();
30
+ this.log?.("Scrolled selected element into view."); // Using optional chaining for log
31
+ }
32
+ When("I scroll into view", When_I_scroll_into_view);
33
+
34
+ /**
35
+ * Scrolls the main browser window to the given X (horizontal) and Y (vertical) pixel coordinates.
36
+ *
37
+ * ```gherkin
38
+ * When I scroll to position {int} {int}
39
+ * ```
40
+ *
41
+ * @param x - The X-coordinate in pixels to scroll to.
42
+ * @param y - The Y-coordinate in pixels to scroll to.
43
+ *
44
+ * @example
45
+ * When I scroll to position 0 500
46
+ *
47
+ * @remarks
48
+ * This step directly executes `window.scrollTo(x, y)` in the browser's context.
49
+ * It sets the absolute scroll position of the main document.
50
+ * This is similar to `When I scroll window to position {int} {int}` and `When I scroll window to x {int} and y {int}`.
51
+ * Consider consolidating if their functionality is identical.
52
+ * @category Scrolling Steps
53
+ */
54
+ export async function When_I_scroll_to_position(this: CustomWorld, x: number, y: number) {
55
+ // FIX: Pass arguments as an object instead of an array
56
+ await this.page.evaluate(({ xCoord, yCoord }) => window.scrollTo(xCoord, yCoord), {
57
+ xCoord: x,
58
+ yCoord: y,
59
+ });
60
+ this.log?.(`Scrolled window to position: ${x}, ${y}.`);
61
+ }
62
+ When("I scroll to position {int} {int}", When_I_scroll_to_position);
63
+
64
+ /**
65
+ * Scrolls the main browser window to the given X (horizontal) and Y (vertical) pixel coordinates.
66
+ * This step is an alias for "When I scroll to position {int} {int}".
67
+ *
68
+ * ```gherkin
69
+ * When I scroll window to position {int} {int}
70
+ * ```
71
+ *
72
+ * @param x - The X-coordinate in pixels to scroll to.
73
+ * @param y - The Y-coordinate in pixels to scroll to.
74
+ *
75
+ * @example
76
+ * When I scroll window to position 0 500
77
+ *
78
+ * @remarks
79
+ * This step is functionally identical to {@link When_I_scroll_to_position | "When I scroll to position {int} {int}"}.
80
+ * It executes `window.scrollTo(x, y)` in the browser's context.
81
+ * @category Scrolling Steps
82
+ */
83
+ export async function When_I_scroll_window_to_position(this: CustomWorld, x: number, y: number) {
84
+ // FIX: Pass arguments as an object instead of an array
85
+ await this.page.evaluate(({ xCoord, yCoord }) => window.scrollTo(xCoord, yCoord), {
86
+ xCoord: x,
87
+ yCoord: y,
88
+ });
89
+ this.log?.(`Window scrolled to: ${x}, ${y}.`);
90
+ }
91
+ When("I scroll window to position {int} {int}", When_I_scroll_window_to_position);
92
+
93
+ /**
94
+ * Scrolls the main browser window to the given X (horizontal) and Y (vertical) pixel coordinates.
95
+ * This step is another alias for "When I scroll to position {int} {int}".
96
+ *
97
+ * ```gherkin
98
+ * When I scroll window to x {int} and y {int}
99
+ * ```
100
+ *
101
+ * @param x - The X-coordinate in pixels to scroll to.
102
+ * @param y - The Y-coordinate in pixels to scroll to.
103
+ *
104
+ * @example
105
+ * When I scroll window to x 0 and y 500
106
+ *
107
+ * @remarks
108
+ * This step is functionally identical to {@link When_I_scroll_to_position | "When I scroll to position {int} {int}"}
109
+ * and {@link When_I_scroll_window_to_position | "When I scroll window to position {int} {int}"}.
110
+ * It executes `window.scrollTo(x, y)` in the browser's context.
111
+ * It's recommended to choose one consistent step pattern for window scrolling.
112
+ * @category Scrolling Steps
113
+ */
114
+ export async function When_I_scroll_window_to_x_and_y(this: CustomWorld, x: number, y: number) {
115
+ // FIX: Pass arguments as an object instead of an array
116
+ await this.page.evaluate(({ xCoord, yCoord }) => window.scrollTo(xCoord, yCoord), {
117
+ xCoord: x,
118
+ yCoord: y,
119
+ });
120
+ this.log?.(`Window scrolled to coordinates: (${x}, ${y}).`);
121
+ }
122
+ When("I scroll window to x {int} and y {int}", When_I_scroll_window_to_x_and_y);
@@ -0,0 +1,308 @@
1
+ // e2e/step_definitions/common/actions/storageSteps.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { When } from "@cucumber/cucumber";
5
+ import { CustomWorld } from "../helpers/world"; // Assuming this path is correct
6
+
7
+ // ===================================================================================
8
+ // BROWSER STORAGE ACTIONS (LOCAL STORAGE, SESSION STORAGE, COOKIES)
9
+ // ===================================================================================
10
+
11
+ /**
12
+ * Clears all items from the browser's Local Storage for the current page's origin.
13
+ *
14
+ * ```gherkin
15
+ * When I clear all local storage
16
+ * ```
17
+ *
18
+ * @example
19
+ * When I clear all local storage
20
+ *
21
+ * @remarks
22
+ * This step executes `localStorage.clear()` in the browser's context.
23
+ * Local Storage items are persistent across browser sessions until explicitly cleared.
24
+ * This step will only affect local storage for the current page's origin.
25
+ * @category Storage Steps
26
+ */
27
+ export async function When_I_clear_all_local_storage(this: CustomWorld) {
28
+ await this.page.evaluate(() => localStorage.clear());
29
+ this.log?.("๐Ÿ—‘๏ธ Cleared all local storage.");
30
+ }
31
+ When("I clear all local storage", When_I_clear_all_local_storage);
32
+
33
+ /**
34
+ * Clears all items from the browser's Local Storage for the current page's origin.
35
+ * This is an alias for "When I clear all local storage".
36
+ *
37
+ * ```gherkin
38
+ * When I clear local storage
39
+ * ```
40
+ *
41
+ * @example
42
+ * When I clear local storage
43
+ *
44
+ * @remarks
45
+ * This step is functionally identical to {@link When_I_clear_all_local_storage | "When I clear all local storage"}.
46
+ * It executes `localStorage.clear()` in the browser's context.
47
+ * Consider using one consistent step pattern.
48
+ * @category Storage Steps
49
+ */
50
+ export async function When_I_clear_local_storage(this: CustomWorld) {
51
+ await this.page.evaluate(() => localStorage.clear());
52
+ this.log?.("๐Ÿ—‘๏ธ Cleared local storage (alias).");
53
+ }
54
+ // Note: You have two steps with the exact same Gherkin pattern:
55
+ // When("I clear local storage", async function () { ... });
56
+ // When("I clear local storage", async function (this: CustomWorld) { ... });
57
+ // I've consolidated them into one export and linked the When call.
58
+ When("I clear local storage", When_I_clear_local_storage);
59
+
60
+ /**
61
+ * Clears all items from the browser's Session Storage for the current page's origin.
62
+ *
63
+ * ```gherkin
64
+ * When I clear session storage
65
+ * ```
66
+ *
67
+ * @example
68
+ * When I clear session storage
69
+ *
70
+ * @remarks
71
+ * This step executes `sessionStorage.clear()` in the browser's context.
72
+ * Session Storage items are cleared when the browser session ends.
73
+ * This step will only affect session storage for the current page's origin.
74
+ * @category Storage Steps
75
+ */
76
+ export async function When_I_clear_session_storage(this: CustomWorld) {
77
+ await this.page.evaluate(() => sessionStorage.clear());
78
+ this.log?.("๐Ÿ—‘๏ธ Cleared session storage.");
79
+ }
80
+ When("I clear session storage", When_I_clear_session_storage);
81
+
82
+ /**
83
+ * Clears all browser storage: cookies, local storage, and session storage.
84
+ * It first navigates to the `BASE_URL` to ensure the correct origin's storage is cleared.
85
+ *
86
+ * ```gherkin
87
+ * When I clear all browser storage
88
+ * ```
89
+ *
90
+ * @example
91
+ * When I clear all browser storage
92
+ *
93
+ * @remarks
94
+ * This is a comprehensive cleanup step. It uses `context.clearCookies()` for cookies
95
+ * and `page.evaluate()` to clear `localStorage` and `sessionStorage`.
96
+ * Navigating to `BASE_URL` before clearing local/session storage is crucial to ensure
97
+ * the storage for the primary application domain is targeted. Ensure `process.env.BASE_URL` is set.
98
+ * @category Storage Steps
99
+ */
100
+ export async function When_I_clear_all_browser_storage(this: CustomWorld) {
101
+ const { context, page } = this;
102
+
103
+ // Clear cookies for the entire browser context
104
+ await context.clearCookies();
105
+ this.log?.("๐Ÿ—‘๏ธ Cleared all cookies.");
106
+
107
+ // Clear local/session storage by navigating to base URL first
108
+ const baseUrl = process.env.BASE_URL;
109
+ if (!baseUrl)
110
+ throw new Error(
111
+ "Missing BASE_URL environment variable. Cannot clear local/session storage effectively."
112
+ );
113
+ // Navigate to base URL to ensure we are on the correct origin to clear its storage
114
+ await page.goto(baseUrl);
115
+ this.log?.(
116
+ `๐ŸŒ Navigated to BASE_URL (${baseUrl}) to ensure correct origin for storage clearing.`
117
+ );
118
+
119
+ await page.evaluate(() => {
120
+ localStorage.clear();
121
+ sessionStorage.clear();
122
+ });
123
+ this.log?.("๐Ÿ—‘๏ธ Cleared all local and session storage.");
124
+
125
+ this.log?.("โœ… Cleared all browser cookies and storage.");
126
+ }
127
+ When("I clear all browser storage", When_I_clear_all_browser_storage);
128
+
129
+ /**
130
+ * Sets a specific item in the browser's Local Storage to the given value.
131
+ *
132
+ * ```gherkin
133
+ * When I set local storage item {string} to {string}
134
+ * ```
135
+ *
136
+ * @param key - The key of the local storage item.
137
+ * @param value - The value to set for the local storage item.
138
+ *
139
+ * @example
140
+ * When I set local storage item "token" to "abc123"
141
+ *
142
+ * @remarks
143
+ * This step executes `localStorage.setItem(key, value)` in the browser's context.
144
+ * This is useful for injecting authentication tokens, feature flags, or other data
145
+ * directly into local storage for test setup.
146
+ * @category Storage Steps
147
+ */
148
+ export async function When_I_set_local_storage_item(this: CustomWorld, key: string, value: string) {
149
+ // FIX: Use object for evaluate arguments to avoid TypeScript overload issues
150
+ await this.page.evaluate(([k, v]) => localStorage.setItem(k, v), [key, value]);
151
+ this.log?.(`๐Ÿ“ฆ Set local storage item "${key}" to "${value.slice(0, 50)}...".`);
152
+ }
153
+ When("I set local storage item {string} to {string}", When_I_set_local_storage_item);
154
+
155
+ /**
156
+ * Sets a specific item in the browser's Session Storage to the given value.
157
+ *
158
+ * ```gherkin
159
+ * When I set session storage item {string} to {string}
160
+ * ```
161
+ *
162
+ * @param key - The key of the session storage item.
163
+ * @param value - The value to set for the session storage item.
164
+ *
165
+ * @example
166
+ * When I set session storage item "sessionId" to "xyz789"
167
+ *
168
+ * @remarks
169
+ * This step executes `sessionStorage.setItem(key, value)` in the browser's context.
170
+ * This is useful for injecting data that needs to persist only for the current browser session.
171
+ * @category Storage Steps
172
+ */
173
+ export async function When_I_set_session_storage_item(
174
+ this: CustomWorld,
175
+ key: string,
176
+ value: string
177
+ ) {
178
+ // FIX: Use object for evaluate arguments to avoid TypeScript overload issues
179
+ await this.page.evaluate(([k, v]) => sessionStorage.setItem(k, v), [key, value]);
180
+ this.log?.(`๐Ÿ“ฆ Set session storage item "${key}" to "${value.slice(0, 50)}...".`);
181
+ }
182
+ When("I set session storage item {string} to {string}", When_I_set_session_storage_item);
183
+
184
+ /**
185
+ * Stores the value of the currently focused input or textarea as an alias in the test data.
186
+ *
187
+ * ```gherkin
188
+ * When I store input text as {string}
189
+ * ```
190
+ *
191
+ * @param alias - The alias name under which to store the input's value.
192
+ *
193
+ * @example
194
+ * Given I find element by placeholder text "Enter your email"
195
+ * And I type "user@example.com"
196
+ * When I store input text as "userEmail"
197
+ * Then the value of alias "userEmail" should be "user@example.com"
198
+ *
199
+ * @remarks
200
+ * This step requires an input or textarea element to be currently focused. It retrieves
201
+ * the `value` attribute of that element and stores it in {@link CustomWorld.data | this.data}
202
+ * under the provided `alias`. This is useful for capturing dynamically generated input values.
203
+ * @category Data Manipulation Steps
204
+ */
205
+ export async function When_I_store_input_text_as(this: CustomWorld, alias: string) {
206
+ const activeElementHandle = await this.page.evaluateHandle(() => document.activeElement);
207
+
208
+ // Check if activeElementHandle is not null and is an HTMLInputElement or HTMLTextAreaElement
209
+ const tagName = await activeElementHandle.evaluate((el) =>
210
+ el ? (el as HTMLElement).tagName.toLowerCase() : ""
211
+ );
212
+
213
+ if (tagName !== "input" && tagName !== "textarea") {
214
+ throw new Error(
215
+ `Active element is not an input or textarea (found: "${tagName || "none"}"). Cannot store text.`
216
+ );
217
+ }
218
+
219
+ // Cast el to HTMLInputElement as both input and textarea have a 'value' property
220
+ const value = await activeElementHandle.evaluate((el) => (el as HTMLInputElement).value);
221
+ this.data[alias] = value;
222
+ this.log?.(`๐Ÿ“ฅ Stored value from active input as "${alias}": "${value}".`);
223
+ }
224
+ When("I store input text as {string}", When_I_store_input_text_as);
225
+
226
+ /**
227
+ * Deletes a session file with the given name from the artifact directory.
228
+ * These session files are typically used for storing browser session state (e.g., cookies, local storage).
229
+ *
230
+ * ```gherkin
231
+ * When I clear session {string}
232
+ * ```
233
+ *
234
+ * @param fileName - The name of the session file to delete (e.g., "my-session.json").
235
+ *
236
+ * @example
237
+ * Given I save session as "admin-session.json"
238
+ * # ... later in a cleanup scenario
239
+ * When I clear session "admin-session.json"
240
+ *
241
+ * @remarks
242
+ * The `fileName` is resolved relative to a base directory, which defaults to
243
+ * `test-artifacts/auth-cookies` or can be configured via `this.parameters?.artifactDir`
244
+ * or `process.env.TEST_ARTIFACT_DIR`.
245
+ * This step ensures clean-up of saved session states, which is crucial for isolated tests.
246
+ * @category File System Steps
247
+ */
248
+ export async function When_I_clear_session_file(this: CustomWorld, fileName: string) {
249
+ const baseDir = this.parameters?.artifactDir || process.env.TEST_ARTIFACT_DIR || "test-artifacts";
250
+ const sessionDirPath = path.resolve(baseDir, "auth-cookies"); // Assuming sessions are stored here
251
+ const fullPath = path.resolve(sessionDirPath, fileName);
252
+
253
+ try {
254
+ if (fs.existsSync(fullPath)) {
255
+ fs.unlinkSync(fullPath);
256
+ this.log?.(`๐Ÿ—‘๏ธ Session file deleted: "${fullPath}".`);
257
+ } else {
258
+ this.log?.(`โ„น๏ธ Session file not found, nothing to delete: "${fullPath}".`);
259
+ }
260
+ } catch (err) {
261
+ const message = err instanceof Error ? err.message : String(err);
262
+ this.log?.(`โŒ Failed to delete session file "${fullPath}": ${message}`);
263
+ throw err; // Re-throw to fail the step if deletion truly failed
264
+ }
265
+ }
266
+ When("I clear session {string}", When_I_clear_session_file);
267
+ // ===================================================================================
268
+ // FILE SYSTEM ACTIONS: SAVED SESSIONS
269
+ // ===================================================================================
270
+
271
+ /**
272
+ * Clears all saved session files from the authentication directory.
273
+ * This is useful for ensuring a clean slate before or after tests that rely on persistent sessions.
274
+ *
275
+ * ```gherkin
276
+ * When I clear all saved session files
277
+ * ```
278
+ *
279
+ * @example
280
+ * When I clear all saved session files
281
+ *
282
+ * @remarks
283
+ * This step reads the `e2e/support/helper/auth` directory (hardcoded path) and deletes
284
+ * all files found within it. It's crucial for managing test artifacts related to user sessions.
285
+ * Ensure the directory path is correct for your project structure.
286
+ * @category File System Steps
287
+ */
288
+ export async function When_I_clear_all_saved_session_files(this: CustomWorld) {
289
+ // Hardcoded path based on your original snippet
290
+ const authDir = path.resolve("e2e/support/helper/auth");
291
+
292
+ if (fs.existsSync(authDir)) {
293
+ const files = fs.readdirSync(authDir);
294
+
295
+ for (const file of files) {
296
+ const filePath = path.join(authDir, file);
297
+ // Ensure it's a file, not a subdirectory
298
+ if (fs.lstatSync(filePath).isFile()) {
299
+ fs.unlinkSync(filePath);
300
+ this.log?.(`๐Ÿงน Deleted session file: "${file}".`);
301
+ }
302
+ }
303
+ this.log?.(`โœ… All saved session files cleared from "${authDir}".`);
304
+ } else {
305
+ this.log?.(`โš ๏ธ Auth directory not found at "${authDir}". No session files to clear.`);
306
+ }
307
+ }
308
+ When("I clear all saved session files", When_I_clear_all_saved_session_files);