playwright-cucumber-ts-steps 0.1.5 → 0.1.7

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 (35) hide show
  1. package/package.json +6 -6
  2. package/src/actions/clickSteps.ts +207 -0
  3. package/src/actions/cookieSteps.ts +29 -0
  4. package/src/actions/debugSteps.ts +7 -0
  5. package/src/actions/elementFindSteps.ts +256 -0
  6. package/src/actions/fillFormSteps.ts +213 -0
  7. package/src/actions/inputSteps.ts +118 -0
  8. package/src/actions/interceptionSteps.ts +87 -0
  9. package/src/actions/miscSteps.ts +414 -0
  10. package/src/actions/mouseSteps.ts +99 -0
  11. package/src/actions/scrollSteps.ts +24 -0
  12. package/src/actions/storageSteps.ts +83 -0
  13. package/src/assertions/buttonAndTextVisibilitySteps.ts +178 -0
  14. package/src/assertions/cookieSteps.ts +52 -0
  15. package/src/assertions/elementSteps.ts +103 -0
  16. package/src/assertions/formInputSteps.ts +110 -0
  17. package/src/assertions/interceptionRequestsSteps.ts +216 -0
  18. package/src/assertions/locationSteps.ts +99 -0
  19. package/src/assertions/roleTestIdSteps.ts +36 -0
  20. package/src/assertions/semanticSteps.ts +79 -0
  21. package/src/assertions/storageSteps.ts +89 -0
  22. package/src/assertions/visualSteps.ts +98 -0
  23. package/src/custom_setups/loginHooks.ts +135 -0
  24. package/src/helpers/checkPeerDeps.ts +19 -0
  25. package/src/helpers/compareSnapshots.ts +35 -0
  26. package/src/helpers/hooks.ts +212 -0
  27. package/src/helpers/utils/fakerUtils.ts +64 -0
  28. package/src/helpers/utils/index.ts +4 -0
  29. package/src/helpers/utils/optionsUtils.ts +104 -0
  30. package/src/helpers/utils/resolveUtils.ts +74 -0
  31. package/src/helpers/utils/sessionUtils.ts +36 -0
  32. package/src/helpers/world.ts +93 -0
  33. package/src/iframes/frames.ts +15 -0
  34. package/src/index.ts +39 -0
  35. package/src/register.ts +4 -0
package/package.json CHANGED
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "name": "playwright-cucumber-ts-steps",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
8
  "publishConfig": {
9
9
  "access": "public"
10
10
  },
11
11
  "exports": {
12
12
  ".": {
13
- "import": "./dist/index.js"
13
+ "import": "./lib/index.js"
14
14
  },
15
15
  "./register": {
16
- "import": "./dist/register.js"
16
+ "import": "./lib/register.js"
17
17
  }
18
18
  },
19
19
  "sideEffects": false,
20
20
  "typesVersions": {
21
21
  "*": {
22
22
  "*": [
23
- "dist/*"
23
+ "lib/*"
24
24
  ]
25
25
  }
26
26
  },
@@ -0,0 +1,207 @@
1
+ // e2e/step_definitions/common/actions/clickSteps.ts
2
+ import { When, DataTable } from "@cucumber/cucumber";
3
+ import { parseClickOptions } from "../helpers/utils/optionsUtils";
4
+ import { CustomWorld } from "../helpers/world";
5
+
6
+ When("I click", async function (this: CustomWorld, ...rest: any[]) {
7
+ const maybeTable = rest[0];
8
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
9
+ if (!this.element) throw new Error("❌ No stored element to click.");
10
+ await this.element.click(options);
11
+ 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
+ );
36
+
37
+ When("I click on link {string}", async function (this: CustomWorld, text: string, ...rest: any[]) {
38
+ const maybeTable = rest[0];
39
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
40
+ const link = await this.page.getByRole("link", { name: text });
41
+ await link.click(options);
42
+ this.element = link;
43
+ 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}"`);
90
+ }
91
+ );
92
+
93
+ When("I click all", async function (this: CustomWorld, ...rest: any[]) {
94
+ const maybeTable = rest[0];
95
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
96
+ if (!this.elements) throw new Error("❌ No stored elements to click.");
97
+ const count = await this.elements.count();
98
+ if (count === 0) throw new Error("⚠️ No elements found to click.");
99
+ for (let i = 0; i < count; i++) {
100
+ const el = this.elements.nth(i);
101
+ await el.waitFor({ state: "visible", timeout: 5000 });
102
+ await el.click(options);
103
+ this.log?.(`🖱️ Clicked element #${i + 1}`);
104
+ }
105
+ 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
+ );
128
+
129
+ When("I double click", async function (this: CustomWorld, ...rest: any[]) {
130
+ const maybeTable = rest[0];
131
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
132
+ if (!this.element) throw new Error("❌ No stored element to double-click.");
133
+ await this.element.dblclick(options);
134
+ this.log?.("🖱️ Double-clicked on stored element");
135
+ });
136
+
137
+ When("I right click", async function (this: CustomWorld, ...rest: any[]) {
138
+ const maybeTable = rest[0];
139
+ const options = maybeTable?.rowsHash ? parseClickOptions(maybeTable) : {};
140
+ if (!this.element) throw new Error("❌ No stored element to right-click.");
141
+ await this.element.click({ button: "right", ...options });
142
+ 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) {
183
+ const options = parseClickOptions(dataTable);
184
+
185
+ if (!this.elements) {
186
+ throw new Error("❌ No elements stored. Use a 'find' step before 'I click all'.");
187
+ }
188
+
189
+ const count = await this.elements.count();
190
+ if (count === 0) {
191
+ throw new Error("⚠️ Stored elements are empty. Nothing to click.");
192
+ }
193
+
194
+ for (let i = 0; i < count; i++) {
195
+ const element = this.elements.nth(i);
196
+ await element.waitFor({ state: "visible", timeout: 5000 });
197
+ await element.click(options);
198
+ this.log?.(`🖱️ Clicked element #${i + 1}`);
199
+ }
200
+
201
+ this.log?.(`✅ Clicked all ${count} stored elements.`);
202
+ });
203
+ When(/^I click on selector "([^"]+)"$/, async function (this: CustomWorld, selector: string) {
204
+ const locator = this.getLocator(selector);
205
+ await locator.click();
206
+ this.log?.(`🖱️ Clicked on selector: ${selector}`);
207
+ });
@@ -0,0 +1,29 @@
1
+ // e2e/step_definitions/common/actions/cookieSteps.ts
2
+ import { When } from "@cucumber/cucumber";
3
+
4
+ When("I clear all cookies", async function () {
5
+ await this.page.context().clearCookies();
6
+ this.log("Cleared all cookies");
7
+ });
8
+
9
+ When("I clear cookies", async function () {
10
+ await this.page.context().clearCookies();
11
+ this.log("Cleared cookies (alias)");
12
+ });
13
+
14
+ When("I clear cookie {string}", async function (name: string) {
15
+ await this.page.context().addCookies([
16
+ {
17
+ name,
18
+ value: "",
19
+ domain: new URL(this.page.url()).hostname,
20
+ path: "/",
21
+ expires: 0,
22
+ },
23
+ ]);
24
+ this.log(`Cleared cookie: ${name}`);
25
+ });
26
+ When("I log all cookies", async function () {
27
+ const cookies = await this.page.context().cookies();
28
+ console.log("Cookies:", cookies);
29
+ });
@@ -0,0 +1,7 @@
1
+ // e2e/step_definitions/common/actions/debugSteps.ts
2
+ import { When } from "@cucumber/cucumber";
3
+
4
+ When("I debug with message {string}", async function (message: string) {
5
+ await this.page.pause();
6
+ this.log(`Paused test for debugging: ${message}`);
7
+ });
@@ -0,0 +1,256 @@
1
+ import { When } from "@cucumber/cucumber";
2
+ import { expect, Locator } from "@playwright/test";
3
+ import { CustomWorld } from "../helpers/world";
4
+
5
+ // =============================
6
+ // WHEN I FIND ELEMENT(S)
7
+ // =============================
8
+
9
+ When("I find element by selector {string}", async function (this: CustomWorld, selector: string) {
10
+ this.element = this.page.locator(selector);
11
+ await expect(this.element).toHaveCount(1);
12
+ });
13
+ When("I find link by text {string}", async function (text: string) {
14
+ this.currentLocator = this.getScope().getByRole("link", { name: text });
15
+ });
16
+
17
+ When("I find heading by text {string}", async function (text: string) {
18
+ this.currentLocator = this.getScope().getByRole("heading", { name: text });
19
+ });
20
+
21
+ When("I find headings by text {string}", async function (text: string) {
22
+ this.currentLocator = this.getScope().getByRole("heading", { name: text });
23
+ });
24
+ When("I find elements by selector {string}", async function (this: CustomWorld, selector: string) {
25
+ this.elements = this.page.locator(selector);
26
+ const count = await this.elements.count();
27
+ this.log?.(`Found ${count} elements with selector ${selector}`);
28
+ });
29
+
30
+ When("I find element by text {string}", async function (this: CustomWorld, text: string) {
31
+ this.element = this.page.getByText(text, { exact: true });
32
+ await expect(this.element).toHaveCount(1);
33
+ });
34
+
35
+ When("I find element by title {string}", async function (this: CustomWorld, title: string) {
36
+ this.element = this.page.getByTitle(title);
37
+ await expect(this.element).toHaveCount(1);
38
+ });
39
+
40
+ When("I find element by testid {string}", async function (this: CustomWorld, testid: string) {
41
+ this.element = this.page.getByTestId(testid);
42
+ await expect(this.element).toHaveCount(1);
43
+ });
44
+
45
+ When("I find element by role {string}", async function (this: CustomWorld, role: string) {
46
+ this.element = this.page.getByRole(role as any);
47
+ await expect(this.element).toHaveCount(1);
48
+ });
49
+
50
+ When(
51
+ "I find element by placeholder text {string}",
52
+ async function (this: CustomWorld, text: string) {
53
+ this.element = this.page.getByPlaceholder(text);
54
+ await expect(this.element).toHaveCount(1);
55
+ }
56
+ );
57
+
58
+ When("I find element by label text {string}", async function (this: CustomWorld, label: string) {
59
+ this.element = this.page.getByLabel(label);
60
+ await expect(this.element).toHaveCount(1);
61
+ });
62
+ When("I find elements by label text {string}", async function (label: string) {
63
+ this.currentLocator = this.getScope().getByLabel(label);
64
+ });
65
+ When("I find element by alt text {string}", async function (this: CustomWorld, alt: string) {
66
+ this.element = this.page.getByAltText(alt);
67
+ await expect(this.element).toHaveCount(1);
68
+ });
69
+
70
+ When("I find element by name {string}", async function (this: CustomWorld, name: string) {
71
+ this.element = this.page.getByRole("textbox", { name });
72
+ await expect(this.element).toHaveCount(1);
73
+ });
74
+ When("I find elements by name {string}", async function (name: string) {
75
+ this.currentLocator = this.getScope().locator(`[name="${name}"]`);
76
+ });
77
+
78
+ When("I find buttons by text {string}", async function (this: CustomWorld, buttonText: string) {
79
+ // 🧠 Resolve alias
80
+ if (buttonText.startsWith("@")) {
81
+ const alias = buttonText.slice(1);
82
+ buttonText = this.data?.[alias];
83
+ if (!buttonText) {
84
+ throw new Error(`No value found for alias "@${alias}"`);
85
+ }
86
+ }
87
+
88
+ // 🔍 Locate all matching buttons
89
+ this.elements = this.page.getByRole("button", {
90
+ name: buttonText,
91
+ exact: false,
92
+ });
93
+
94
+ this.log?.(`🔘 Stored all buttons matching text "${buttonText}"`);
95
+ });
96
+ // =============================
97
+ // WHEN I GET ELEMENT(S)
98
+ // =============================
99
+
100
+ When("I get element by selector {string}", async function (this: CustomWorld, selector: string) {
101
+ this.element = this.page.locator(selector).first();
102
+ });
103
+
104
+ When("I get elements by selector {string}", async function (this: CustomWorld, selector: string) {
105
+ this.elements = this.page.locator(selector);
106
+ });
107
+
108
+ When("I get first element", async function (this: CustomWorld) {
109
+ if (!this.elements) throw new Error("No element collection found");
110
+ this.element = this.elements.first();
111
+ });
112
+
113
+ When("I get last element", async function (this: CustomWorld) {
114
+ if (!this.elements) throw new Error("No element collection found");
115
+ this.element = this.elements.last();
116
+ });
117
+
118
+ When(/^I get (\d+)(?:st|nd|rd|th) element$/, async function (this: CustomWorld, index: number) {
119
+ if (!this.elements) throw new Error("No elements stored to pick from");
120
+ const count = await this.elements.count();
121
+ if (index < 1 || index > count) {
122
+ throw new Error(`Cannot get element ${index} — only ${count} found`);
123
+ }
124
+ this.element = this.elements.nth(index - 1);
125
+ this.log?.(`Selected ${index} element from stored elements`);
126
+ });
127
+
128
+ When("I find elements by role {string}", async function (this: CustomWorld, role: string) {
129
+ const locator = this.page.getByRole(role as any);
130
+ const count = await locator.count();
131
+
132
+ if (count === 0) {
133
+ throw new Error(`No elements found with role "${role}"`);
134
+ }
135
+
136
+ this.elements = locator;
137
+ this.log?.(`Stored ${count} elements with role "${role}"`);
138
+ });
139
+
140
+ When("I get {int}rd element", async function (this: CustomWorld, index: number) {
141
+ if (!this.elements) throw new Error("No element collection found");
142
+ this.element = this.elements.nth(index);
143
+ });
144
+
145
+ When("I get focused element", async function (this: CustomWorld) {
146
+ this.element = (await this.page.evaluateHandle(
147
+ () => document.activeElement
148
+ )) as unknown as Locator;
149
+ });
150
+ When("I store element text as {string}", async function (this: CustomWorld, alias: string) {
151
+ const element = this.element;
152
+ if (!element) throw new Error("No element selected");
153
+ const text = await element.textContent();
154
+ this.data[alias] = text?.trim();
155
+ this.log?.(`Stored text "${text}" as "${alias}"`);
156
+ });
157
+ When("I find textarea by label text {string}", async function (this: CustomWorld, label: string) {
158
+ this.element = this.page.getByLabel(label);
159
+ this.log?.(`Stored textarea with label "${label}"`);
160
+ });
161
+ When(
162
+ "I find textarea by placeholder text {string}",
163
+ async function (this: CustomWorld, placeholder: string) {
164
+ this.element = this.page.getByPlaceholder(placeholder);
165
+ this.log?.(`Stored textarea with placeholder "${placeholder}"`);
166
+ }
167
+ );
168
+ When("I find textareas by label text {string}", async function (this: CustomWorld, label: string) {
169
+ this.elements = this.page.locator(`label:has-text("${label}") + textarea`);
170
+ this.log?.(`Stored multiple textareas with label "${label}"`);
171
+ });
172
+ When("I find textarea by name {string}", async function (this: CustomWorld, name: string) {
173
+ this.element = this.page.locator(`textarea[name="${name}"]`);
174
+ this.log?.(`Stored textarea with name "${name}"`);
175
+ });
176
+ When("I find textareas by ID {string}", async function (this: CustomWorld, id: string) {
177
+ this.elements = this.page.locator(`textarea#${id}`);
178
+ this.log?.(`Stored multiple textareas with ID "${id}"`);
179
+ });
180
+ When("I find input by ID {string}", async function (this: CustomWorld, id: string) {
181
+ this.element = this.page.locator(`input#${id}`);
182
+ this.log?.(`Stored input with ID "${id}"`);
183
+ });
184
+ When("I find inputs by ID {string}", async function (this: CustomWorld, id: string) {
185
+ this.elements = this.page.locator(`input#${id}`);
186
+ this.log?.(`Stored multiple inputs with ID "${id}"`);
187
+ });
188
+ When(
189
+ "I find textareas by placeholder text {string}",
190
+ async function (this: CustomWorld, placeholder: string) {
191
+ this.elements = this.page.locator(`textarea[placeholder="${placeholder}"]`);
192
+ this.log?.(`Stored multiple textareas with placeholder "${placeholder}"`);
193
+ }
194
+ );
195
+ When("I find input by label text {string}", async function (this: CustomWorld, label: string) {
196
+ this.element = this.page.getByLabel(label);
197
+ this.log?.(`Stored input with label "${label}"`);
198
+ });
199
+ When("I find input by name {string}", async function (this: CustomWorld, name: string) {
200
+ this.element = this.page.locator(`input[name="${name}"]`);
201
+ this.log?.(`Stored input with name "${name}"`);
202
+ });
203
+ When(
204
+ "I find input by placeholder text {string}",
205
+ async function (this: CustomWorld, placeholder: string) {
206
+ this.element = this.page.getByPlaceholder(placeholder);
207
+ this.log?.(`Stored input with placeholder "${placeholder}"`);
208
+ }
209
+ );
210
+ When("I find inputs by name {string}", async function (this: CustomWorld, name: string) {
211
+ this.elements = this.page.locator(`input[name="${name}"]`);
212
+ this.log?.(`Stored multiple inputs with name "${name}"`);
213
+ });
214
+ When(
215
+ "I find inputs by placeholder text {string}",
216
+ async function (this: CustomWorld, placeholder: string) {
217
+ this.elements = this.page.locator(`input[placeholder="${placeholder}"]`);
218
+ this.log?.(`Stored multiple inputs with placeholder "${placeholder}"`);
219
+ }
220
+ );
221
+ When("I find inputs by label text {string}", async function (this: CustomWorld, label: string) {
222
+ this.elements = this.page.locator(`label:has-text("${label}") + input`);
223
+ this.log?.(`Stored multiple inputs with label "${label}"`);
224
+ });
225
+ When("I find inputs by display value {string}", async function (this: CustomWorld, value: string) {
226
+ // 🧠 Handle alias
227
+ if (value.startsWith("@")) {
228
+ const alias = value.slice(1);
229
+ value = this.data?.[alias];
230
+ if (!value) {
231
+ throw new Error(`No value found for alias "@${alias}"`);
232
+ }
233
+ }
234
+
235
+ // 🔍 Find all matching inputs
236
+ this.elements = this.page.locator(`input[value="${value}"]`);
237
+
238
+ this.log?.(`📦 Stored multiple inputs with display value "${value}"`);
239
+ });
240
+ When("I find input by display value {string}", async function (this: CustomWorld, value: string) {
241
+ // 🧠 Handle alias
242
+ if (value.startsWith("@")) {
243
+ const alias = value.slice(1);
244
+ value = this.data?.[alias];
245
+ if (!value) {
246
+ throw new Error(`No value found for alias "@${alias}"`);
247
+ }
248
+ }
249
+
250
+ // 🎯 Try to find input element with matching display value
251
+ const locator = this.page.locator(`input[value="${value}"]`);
252
+
253
+ await expect(locator).toBeVisible({ timeout: 5000 });
254
+ this.element = locator;
255
+ this.log?.(`🔍 Found input with value: "${value}"`);
256
+ });