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,436 @@
1
+ import { Then } from "@cucumber/cucumber";
2
+ import { expect } from "@playwright/test";
3
+ import { evaluateFaker } from "../helpers/utils/fakerUtils"; // Assuming this path is correct
4
+ import type { CustomWorld } from "../helpers/world"; // Assuming this path is correct
5
+
6
+ // ===================================================================================
7
+ // ASSERTIONS: ELEMENT COUNT
8
+ // ===================================================================================
9
+
10
+ /**
11
+ * Asserts that the previously stored collection of elements has an exact expected count.
12
+ *
13
+ * ```gherkin
14
+ * Then I count {int} elements
15
+ * ```
16
+ *
17
+ * @param expectedCount - The expected number of elements in the collection.
18
+ *
19
+ * @example
20
+ * Given I find elements by selector ".list-item"
21
+ * Then I count 5 elements
22
+ *
23
+ * @remarks
24
+ * This step requires a preceding step that populates {@link CustomWorld.elements | this.elements}
25
+ * (e.g., "When I find elements by selector"). It then asserts that the number of
26
+ * elements in that collection matches `expectedCount`. It also waits for `networkidle`
27
+ * to ensure all elements that might affect the count have loaded.
28
+ * @category Assertion Steps
29
+ */
30
+ export async function Then_I_count_elements(this: CustomWorld, expectedCount: number) {
31
+ if (!this.elements)
32
+ throw new Error("No element collection found to count. Use a 'find elements' step first.");
33
+ const count = await this.elements.count();
34
+ await this.page.waitForLoadState("networkidle"); // Wait for network to settle before asserting count
35
+
36
+ expect(count).toBe(expectedCount);
37
+ this.log?.(`✅ Verified element count: Expected ${expectedCount}, Found ${count}.`);
38
+ }
39
+ Then("I count {int} elements", Then_I_count_elements);
40
+
41
+ // ===================================================================================
42
+ // ASSERTIONS: BUTTON VISIBILITY
43
+ // ===================================================================================
44
+
45
+ /**
46
+ * Asserts that a button with the given text (or text from an alias) is visible on the page.
47
+ * The text matching is case-insensitive and can be partial.
48
+ *
49
+ * ```gherkin
50
+ * Then I see button {string}
51
+ * ```
52
+ *
53
+ * @param rawText - The text of the button, or an alias prefixed with "@" (e.g., "Submit", "@submitButtonLabel").
54
+ *
55
+ * @example
56
+ * Then I see button "Sign In"
57
+ * Then I see button "@myLoginButton"
58
+ *
59
+ * @remarks
60
+ * This step uses `page.getByRole("button", { name: ..., exact: false })`.
61
+ * It waits for the page to be network idle and then asserts that the button is visible.
62
+ * @category Assertion Steps
63
+ */
64
+ export async function Then_I_see_button(this: CustomWorld, rawText: string) {
65
+ let buttonText = rawText.startsWith("@") ? this.data[rawText.slice(1)] : rawText;
66
+
67
+ if (!buttonText) {
68
+ throw new Error(`No value found for alias: "${rawText}". Cannot assert button visibility.`);
69
+ }
70
+
71
+ const button = this.page.getByRole("button", {
72
+ name: buttonText,
73
+ exact: false, // Allows partial match, e.g., "Submit" finds "Submit Form"
74
+ });
75
+
76
+ await this.page.waitForLoadState("networkidle"); // Wait for network to settle
77
+ await expect(button).toBeVisible({ timeout: 5000 }); // Assert visibility with a timeout
78
+ this.log?.(`✅ Verified button "${buttonText}" is visible.`);
79
+ }
80
+ Then(/^I see button "(.*)"$/, Then_I_see_button);
81
+
82
+ /**
83
+ * Asserts that a button with the given text (or text from an alias) is NOT visible on the page.
84
+ * The text matching is case-insensitive and can be partial.
85
+ *
86
+ * ```gherkin
87
+ * Then I do not see button {string}
88
+ * ```
89
+ *
90
+ * @param rawText - The text of the button, or an alias prefixed with "@".
91
+ *
92
+ * @example
93
+ * Then I do not see button "Delete Account"
94
+ * Then I do not see button "@hiddenAdminButton"
95
+ *
96
+ * @remarks
97
+ * This step checks for the absence of a visible button. It first waits for the page
98
+ * to be network idle, then finds potential buttons by role and name. If any matching
99
+ * button is found and is visible, the step will fail.
100
+ * @category Assertion Steps
101
+ */
102
+ export async function Then_I_do_not_see_button(this: CustomWorld, rawText: string) {
103
+ let buttonText = rawText.startsWith("@") ? this.data[rawText.slice(1)] : rawText;
104
+
105
+ if (!buttonText) {
106
+ throw new Error(`No value found for alias: "${rawText}". Cannot assert button non-visibility.`);
107
+ }
108
+
109
+ const button = this.page.getByRole("button", {
110
+ name: buttonText,
111
+ exact: false,
112
+ });
113
+
114
+ await this.page.waitForLoadState("networkidle"); // Wait for network to settle
115
+ // Check if *any* matching button is visible. If so, throw an error.
116
+ await expect(button).not.toBeVisible({ timeout: 5000 }); // Playwright's native assertion is more robust here
117
+
118
+ this.log?.(`✅ Verified button "${buttonText}" is not visible.`);
119
+ }
120
+ Then(/^I do not see button "(.*)"$/, Then_I_do_not_see_button);
121
+
122
+ // ===================================================================================
123
+ // ASSERTIONS: TEXT VISIBILITY
124
+ // ===================================================================================
125
+
126
+ /**
127
+ * Asserts that specific text is visible on the current page or within the current frame/scope.
128
+ *
129
+ * ```gherkin
130
+ * Then I see text {string}
131
+ * ```
132
+ *
133
+ * @param expectedText - The text string expected to be visible.
134
+ *
135
+ * @example
136
+ * Then I see text "Welcome to your Dashboard"
137
+ *
138
+ * @remarks
139
+ * This step uses `locator.waitFor({ state: "visible" })` to ensure the text is present
140
+ * and displayed within the current Playwright scope (main page or active iframe).
141
+ * Text matching is a substring match by default.
142
+ * @category Assertion Steps
143
+ */
144
+ export async function Then_I_see_text(this: CustomWorld, expectedText: string) {
145
+ const scope = this.getScope(); // Supports iframe OR main page
146
+ const locator = scope.locator(`text=${expectedText}`); // Playwright's text locator is robust
147
+
148
+ // Use Playwright's expect for robust waiting and assertion
149
+ await expect(locator).toBeVisible({ timeout: 5000 });
150
+
151
+ this.log?.(`✅ Verified text visible: "${expectedText}".`);
152
+ }
153
+ Then("I see text {string}", Then_I_see_text);
154
+
155
+ /**
156
+ * Asserts that the exact visible text is present on the page.
157
+ * This is similar to "I see text", but emphasizes "visible" for clarity.
158
+ *
159
+ * ```gherkin
160
+ * Then I see visible text {string}
161
+ * ```
162
+ *
163
+ * @param text - The exact text string expected to be visible.
164
+ *
165
+ * @example
166
+ * Then I see visible text "Dashboard"
167
+ *
168
+ * @remarks
169
+ * This step uses `:text-is()` pseudo-class for exact text matching and `isVisible()`
170
+ * to confirm presence. It also waits for `networkidle` beforehand.
171
+ * Consider consolidating with `Then I see text {string}` if you prefer `toBeVisible`
172
+ * which handles exact matching via options or `text-is` more flexibly.
173
+ * @category Assertion Steps
174
+ */
175
+ export async function Then_I_see_visible_text(this: CustomWorld, text: string) {
176
+ await this.page.waitForLoadState("networkidle"); // Wait for network to settle
177
+
178
+ const locator = this.page.locator(`:text-is("${text}")`);
179
+ // Use Playwright's expect for robust waiting and assertion
180
+ await expect(locator).toBeVisible({ timeout: 5000 });
181
+
182
+ this.log?.(`✅ Verified exact visible text: "${text}".`);
183
+ }
184
+ Then("I see visible text {string}", Then_I_see_visible_text);
185
+
186
+ /**
187
+ * Asserts that specific exact visible text is NOT present on the page.
188
+ *
189
+ * ```gherkin
190
+ * Then I do not see visible text {string}
191
+ * ```
192
+ *
193
+ * @param text - The exact text string expected NOT to be visible.
194
+ *
195
+ * @example
196
+ * Then I do not see visible text "Logout"
197
+ *
198
+ * @remarks
199
+ * This step uses `:text-is()` for exact text matching. It asserts that no element
200
+ * with this exact text is visible.
201
+ * @category Assertion Steps
202
+ */
203
+ export async function Then_I_do_not_see_visible_text(this: CustomWorld, text: string) {
204
+ const locator = this.page.locator(`:text-is("${text}")`);
205
+ // Use Playwright's expect for robust assertion
206
+ await expect(locator).not.toBeVisible({ timeout: 5000 });
207
+
208
+ this.log?.(`✅ Verified exact visible text NOT present: "${text}".`);
209
+ }
210
+ Then("I do not see visible text {string}", Then_I_do_not_see_visible_text);
211
+
212
+ // ===================================================================================
213
+ // ASSERTIONS: ELEMENT VALUE
214
+ // ===================================================================================
215
+
216
+ /**
217
+ * Asserts that the previously selected element has a specific input value.
218
+ *
219
+ * ```gherkin
220
+ * Then I see value {string}
221
+ * ```
222
+ *
223
+ * @param expectedValue - The expected exact value of the input or textarea.
224
+ *
225
+ * @example
226
+ * When I find element by selector "input[name='email']"
227
+ * Then I see value "test@example.com"
228
+ *
229
+ * @remarks
230
+ * This step requires a preceding step that sets the {@link CustomWorld.element | current element}
231
+ * to an input, textarea, or other element that has an input value.
232
+ * It uses Playwright's `locator.inputValue()`.
233
+ * @category Assertion Steps
234
+ */
235
+ export async function Then_I_see_value(this: CustomWorld, expectedValue: string) {
236
+ if (!this.element) throw new Error("No element selected to check its value.");
237
+
238
+ // Use Playwright's expect.toHaveValue for robust assertion
239
+ await expect(this.element).toHaveValue(expectedValue, { timeout: 5000 });
240
+
241
+ this.log?.(`✅ Verified element has value: "${expectedValue}".`);
242
+ }
243
+ Then("I see value {string}", Then_I_see_value);
244
+
245
+ /**
246
+ * Asserts that the previously selected element does NOT have a specific input value.
247
+ *
248
+ * ```gherkin
249
+ * Then I do not see value {string}
250
+ * ```
251
+ *
252
+ * @param unwantedValue - The value that is expected NOT to be present in the input or textarea.
253
+ *
254
+ * @example
255
+ * When I find element by selector "input[name='password']"
256
+ * Then I do not see value "admin123"
257
+ *
258
+ * @remarks
259
+ * This step requires a preceding step that sets the {@link CustomWorld.element | current element}.
260
+ * It asserts that the element's current input value does not match `unwantedValue`.
261
+ * @category Assertion Steps
262
+ */
263
+ export async function Then_I_do_not_see_value(this: CustomWorld, unwantedValue: string) {
264
+ if (!this.element) throw new Error("No element selected to check its value.");
265
+
266
+ // Use Playwright's expect.not.toHaveValue for robust assertion
267
+ await expect(this.element).not.toHaveValue(unwantedValue, { timeout: 5000 });
268
+
269
+ this.log?.(`✅ Verified element does NOT have value: "${unwantedValue}".`);
270
+ }
271
+ Then("I do not see value {string}", Then_I_do_not_see_value);
272
+
273
+ // ===================================================================================
274
+ // ASSERTIONS: TEXT PRESENCE (Absence)
275
+ // ===================================================================================
276
+
277
+ /**
278
+ * Asserts that specific text is NOT present on the page. This checks for complete absence,
279
+ * not just visibility.
280
+ *
281
+ * ```gherkin
282
+ * Then I do not see text {string}
283
+ * ```
284
+ *
285
+ * @param unexpectedText - The text string that is expected NOT to be found on the page.
286
+ *
287
+ * @example
288
+ * Then I do not see text "Error Message"
289
+ *
290
+ * @remarks
291
+ * This step uses `page.getByText` with `exact: true` and then asserts that the count
292
+ * of matching elements is 0. This confirms the text is entirely absent from the DOM.
293
+ * @category Assertion Steps
294
+ */
295
+ export async function Then_I_do_not_see_text(this: CustomWorld, unexpectedText: string) {
296
+ const el = this.page.getByText(unexpectedText, { exact: true });
297
+ await expect(el).toHaveCount(0); // This directly asserts that no such element exists
298
+ this.log?.(`✅ Verified text NOT present in DOM: "${unexpectedText}".`);
299
+ }
300
+ Then(/^I do not see text "(.*)"$/, Then_I_do_not_see_text);
301
+
302
+ // ===================================================================================
303
+ // ASSERTIONS: TEXT IN ELEMENT (with Alias/Faker)
304
+ // ===================================================================================
305
+
306
+ /**
307
+ * Asserts that the previously selected element contains the given text,
308
+ * which can be a literal string, an alias, or a Faker.js expression.
309
+ *
310
+ * ```gherkin
311
+ * Then I see {string} in the element
312
+ * ```
313
+ *
314
+ * @param expected - The text string, alias (prefixed with "@"), or Faker.js expression expected to be contained within the element's text content.
315
+ *
316
+ * @example
317
+ * When I find element by selector "#welcome-message"
318
+ * Then I see "Welcome, John Doe!" in the element
319
+ * Given I store "user.name" as "loggedInUserName"
320
+ * When I find element by selector "#user-profile-name"
321
+ * Then I see "@loggedInUserName" in the element
322
+ * Then I see "Hello, {{person.firstName}}!" in the element
323
+ *
324
+ * @remarks
325
+ * This step requires a preceding step that sets the {@link CustomWorld.element | current element}.
326
+ * It resolves aliases and Faker expressions before comparing the `textContent` of the element.
327
+ * It uses `expect(textContent).toContain(expected)` for partial matching.
328
+ * @category Assertion Steps
329
+ */
330
+ export async function Then_I_see_text_in_the_element(this: CustomWorld, expected: string) {
331
+ const element = this.element;
332
+ if (!element) throw new Error("No element selected to check its text content.");
333
+
334
+ // ✅ Resolve alias
335
+ if (expected.startsWith("@")) {
336
+ const alias = expected.substring(1);
337
+ expected = this.data[alias];
338
+ if (!expected) throw new Error(`No data stored for alias "@${alias}".`);
339
+ }
340
+
341
+ // ✅ Resolve faker syntax
342
+ expected = evaluateFaker(expected);
343
+
344
+ // Use Playwright's expect.toContainText for robust assertion on visible text
345
+ await expect(element).toContainText(expected, { timeout: 5000 });
346
+
347
+ this.log?.(`✅ Verified "${expected}" is contained in element text.`);
348
+ }
349
+ Then("I see {string} in the element", Then_I_see_text_in_the_element);
350
+
351
+ /**
352
+ * Asserts that the previously selected element contains the value retrieved from a specific alias.
353
+ *
354
+ * ```gherkin
355
+ * Then I see @{word} in the element
356
+ * ```
357
+ *
358
+ * @param alias - The alias name from which to retrieve the expected text value.
359
+ *
360
+ * @example
361
+ * Given I store "Generated Name" as "tempName"
362
+ * When I find element by selector "#display-name"
363
+ * Then I see @tempName in the element
364
+ *
365
+ * @remarks
366
+ * This step requires a preceding step that sets the {@link CustomWorld.element | current element}.
367
+ * It fetches the value from `this.data[alias]` and then asserts that the element's
368
+ * `textContent` (trimmed) contains this stored value. This is a specialized version of
369
+ * `Then I see {string} in the element` specifically for aliases.
370
+ * @category Assertion Steps
371
+ */
372
+ export async function Then_I_see_alias_in_the_element(this: CustomWorld, alias: string) {
373
+ const storedValue = this.data[alias];
374
+
375
+ if (storedValue === undefined || storedValue === null) {
376
+ throw new Error(
377
+ `No value found in data storage under alias "@${alias}". Alias might be undefined or null.`
378
+ );
379
+ }
380
+
381
+ if (!this.element) {
382
+ throw new Error(
383
+ "No element selected to check its text content. You must get an element before asserting its contents."
384
+ );
385
+ }
386
+
387
+ // Use Playwright's expect.toContainText for robust assertion
388
+ // Convert storedValue to string for reliable comparison
389
+ await expect(this.element).toContainText(String(storedValue), { timeout: 5000 });
390
+
391
+ this.log?.(`✅ Verified element contains value from "@${alias}" ("${storedValue}").`);
392
+ }
393
+ Then("I see @{word} in the element", Then_I_see_alias_in_the_element);
394
+
395
+ // ===================================================================================
396
+ // ASSERTIONS: BUTTON STATE
397
+ // ===================================================================================
398
+
399
+ /**
400
+ * Asserts that a button with the given text (or text from an alias) is disabled.
401
+ *
402
+ * ```gherkin
403
+ * Then I see button {string} is disabled
404
+ * ```
405
+ *
406
+ * @param rawText - The text of the button, or an alias prefixed with "@".
407
+ *
408
+ * @example
409
+ * Then I see button "Submit" is disabled
410
+ * Then I see button "@checkoutButton" is disabled
411
+ *
412
+ * @remarks
413
+ * This step first locates the button by its role and name, asserts it's visible,
414
+ * and then checks its disabled state using Playwright's `isDisabled()` method.
415
+ * @category Assertion Steps
416
+ */
417
+ export async function Then_I_see_button_is_disabled(this: CustomWorld, rawText: string) {
418
+ // Resolve alias
419
+ let buttonText = rawText.startsWith("@") ? this.data[rawText.slice(1)] : rawText;
420
+
421
+ if (!buttonText) {
422
+ throw new Error(`No value found for alias: "${rawText}". Cannot check button disabled state.`);
423
+ }
424
+
425
+ const button = this.page.getByRole("button", {
426
+ name: buttonText,
427
+ exact: false,
428
+ });
429
+
430
+ // Assert visibility first, then disabled state
431
+ await expect(button).toBeVisible({ timeout: 5000 });
432
+ await expect(button).toBeDisabled({ timeout: 5000 }); // Playwright's direct assertion is best
433
+
434
+ this.log?.(`✅ Verified button "${buttonText}" is disabled.`);
435
+ }
436
+ Then("I see button {string} is disabled", Then_I_see_button_is_disabled);
@@ -0,0 +1,131 @@
1
+ import { Then } from "@cucumber/cucumber";
2
+ import { expect } from "@playwright/test"; // Import expect for more robust assertions where applicable
3
+ import type { CustomWorld } from "../helpers/world"; // Assuming this path is correct
4
+
5
+ // ===================================================================================
6
+ // ASSERTIONS: COOKIES
7
+ // ===================================================================================
8
+
9
+ /**
10
+ * Asserts that a cookie with the given name exists in the browser context.
11
+ *
12
+ * ```gherkin
13
+ * Then I see cookie {string}
14
+ * ```
15
+ *
16
+ * @param cookieName - The name of the cookie expected to exist.
17
+ *
18
+ * @example
19
+ * Then I see cookie "session_id"
20
+ *
21
+ * @remarks
22
+ * This step retrieves all cookies from the current Playwright browser context
23
+ * and checks if a cookie with `cookieName` is present.
24
+ * @category Cookie Assertion Steps
25
+ */
26
+ export async function Then_I_see_cookie(this: CustomWorld, cookieName: string) {
27
+ const cookies = await this.context.cookies();
28
+ const cookie = cookies.find((c) => c.name === cookieName);
29
+
30
+ // Using Playwright's expect for better assertion messages and retries (if configured)
31
+ expect(cookie, `Cookie "${cookieName}" should exist but was not found.`).toBeDefined();
32
+ this.log?.(`✅ Verified cookie "${cookieName}" exists.`);
33
+ }
34
+ Then("I see cookie {string}", Then_I_see_cookie);
35
+
36
+ /**
37
+ * Asserts that a cookie with the given name does NOT exist in the browser context.
38
+ *
39
+ * ```gherkin
40
+ * Then I do not see cookie {string}
41
+ * ```
42
+ *
43
+ * @param cookieName - The name of the cookie expected NOT to exist.
44
+ *
45
+ * @example
46
+ * Then I do not see cookie "expired_token"
47
+ *
48
+ * @remarks
49
+ * This step retrieves all cookies from the current Playwright browser context
50
+ * and asserts that no cookie with `cookieName` is present.
51
+ * @category Cookie Assertion Steps
52
+ */
53
+ export async function Then_I_do_not_see_cookie(this: CustomWorld, cookieName: string) {
54
+ const cookies = await this.context.cookies();
55
+ const cookie = cookies.find((c) => c.name === cookieName);
56
+
57
+ // Using Playwright's expect for better assertion messages and retries
58
+ expect(cookie, `Cookie "${cookieName}" should NOT exist but was found.`).toBeUndefined();
59
+ this.log?.(`✅ Verified cookie "${cookieName}" does not exist.`);
60
+ }
61
+ Then("I do not see cookie {string}", Then_I_do_not_see_cookie);
62
+
63
+ /**
64
+ * Asserts that a cookie with the given name exists and has an exact expected value.
65
+ *
66
+ * ```gherkin
67
+ * Then I see cookie {string} has value {string}
68
+ * ```
69
+ *
70
+ * @param cookieName - The name of the cookie to check.
71
+ * @param expectedValue - The exact value the cookie is expected to have.
72
+ *
73
+ * @example
74
+ * Then I see cookie "sessionId" has value "abc123"
75
+ *
76
+ * @remarks
77
+ * This step finds the cookie by name and then asserts that its `value` property
78
+ * strictly matches `expectedValue`.
79
+ * @category Cookie Assertion Steps
80
+ */
81
+ export async function Then_I_see_cookie_has_value(
82
+ this: CustomWorld,
83
+ cookieName: string,
84
+ expectedValue: string
85
+ ) {
86
+ const cookies = await this.context.cookies();
87
+ const cookie = cookies.find((c) => c.name === cookieName);
88
+
89
+ expect(cookie, `Cookie "${cookieName}" not found.`).toBeDefined();
90
+ expect(
91
+ cookie?.value,
92
+ `Expected cookie "${cookieName}" to have value "${expectedValue}", but got "${cookie?.value}".`
93
+ ).toBe(expectedValue);
94
+ this.log?.(`✅ Verified cookie "${cookieName}" has value "${expectedValue}".`);
95
+ }
96
+ Then("I see cookie {string} has value {string}", Then_I_see_cookie_has_value);
97
+
98
+ /**
99
+ * Asserts that a cookie with the given name exists and its value contains a specific substring.
100
+ *
101
+ * ```gherkin
102
+ * Then I see cookie {string} contains value {string}
103
+ * ```
104
+ *
105
+ * @param cookieName - The name of the cookie to check.
106
+ * @param valuePart - The substring expected to be present within the cookie's value.
107
+ *
108
+ * @example
109
+ * Then I see cookie "token" contains value "auth_type"
110
+ *
111
+ * @remarks
112
+ * This step finds the cookie by name and then asserts that its `value` property
113
+ * includes the `valuePart` string. Useful for tokens or complex cookie values.
114
+ * @category Cookie Assertion Steps
115
+ */
116
+ export async function Then_I_see_cookie_contains_value(
117
+ this: CustomWorld,
118
+ cookieName: string,
119
+ valuePart: string
120
+ ) {
121
+ const cookies = await this.context.cookies();
122
+ const cookie = cookies.find((c) => c.name === cookieName);
123
+
124
+ expect(cookie, `Cookie "${cookieName}" not found.`).toBeDefined();
125
+ expect(
126
+ cookie?.value,
127
+ `Expected cookie "${cookieName}" to contain "${valuePart}", but got "${cookie?.value}".`
128
+ ).toContain(valuePart);
129
+ this.log?.(`✅ Verified cookie "${cookieName}" contains value "${valuePart}".`);
130
+ }
131
+ Then("I see cookie {string} contains value {string}", Then_I_see_cookie_contains_value);