playwright-cucumber-ts-steps 1.1.6 → 1.1.8

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 (53) hide show
  1. package/README.md +10 -15
  2. package/dist/backend/actions/click.d.ts +2 -0
  3. package/dist/backend/actions/click.d.ts.map +1 -0
  4. package/dist/backend/actions/click.js +179 -0
  5. package/dist/backend/actions/find.d.ts +2 -0
  6. package/dist/backend/actions/find.d.ts.map +1 -0
  7. package/dist/backend/actions/find.js +291 -0
  8. package/dist/backend/actions/form.d.ts +2 -0
  9. package/dist/backend/actions/form.d.ts.map +1 -0
  10. package/dist/backend/actions/form.js +185 -0
  11. package/dist/backend/actions/formTable.js +1 -1
  12. package/dist/backend/actions/frames.d.ts +2 -0
  13. package/dist/backend/actions/frames.d.ts.map +1 -0
  14. package/dist/backend/actions/frames.js +60 -0
  15. package/dist/backend/actions/index.d.ts +10 -0
  16. package/dist/backend/actions/index.d.ts.map +1 -1
  17. package/dist/backend/actions/index.js +10 -0
  18. package/dist/backend/actions/inputs.d.ts +2 -0
  19. package/dist/backend/actions/inputs.d.ts.map +1 -0
  20. package/dist/backend/actions/inputs.js +177 -0
  21. package/dist/backend/actions/keyboard.d.ts +2 -0
  22. package/dist/backend/actions/keyboard.d.ts.map +1 -0
  23. package/dist/backend/actions/keyboard.js +62 -0
  24. package/dist/backend/actions/misc.d.ts +2 -0
  25. package/dist/backend/actions/misc.d.ts.map +1 -0
  26. package/dist/backend/actions/misc.js +144 -0
  27. package/dist/backend/actions/mobile.d.ts +2 -0
  28. package/dist/backend/actions/mobile.d.ts.map +1 -0
  29. package/dist/backend/actions/mobile.js +87 -0
  30. package/dist/backend/actions/mouse.d.ts +2 -0
  31. package/dist/backend/actions/mouse.d.ts.map +1 -0
  32. package/dist/backend/actions/mouse.js +105 -0
  33. package/dist/backend/actions/navigation.js +31 -7
  34. package/dist/backend/actions/waits.d.ts +2 -0
  35. package/dist/backend/actions/waits.d.ts.map +1 -0
  36. package/dist/backend/actions/waits.js +51 -0
  37. package/dist/backend/api/index.d.ts +1 -0
  38. package/dist/backend/api/index.d.ts.map +1 -1
  39. package/dist/backend/api/index.js +1 -0
  40. package/dist/backend/api/network.d.ts +2 -0
  41. package/dist/backend/api/network.d.ts.map +1 -0
  42. package/dist/backend/api/network.js +145 -0
  43. package/dist/backend/assertions/pageState.js +25 -14
  44. package/dist/backend/assertions/visibility.js +116 -12
  45. package/dist/backend/utils/state.d.ts +18 -0
  46. package/dist/backend/utils/state.d.ts.map +1 -0
  47. package/dist/backend/utils/state.js +84 -0
  48. package/dist/core/registry.d.ts +14 -14
  49. package/dist/core/registry.d.ts.map +1 -1
  50. package/dist/core/registry.js +13 -4
  51. package/dist/core/runner.d.ts.map +1 -1
  52. package/dist/core/runner.js +91 -37
  53. package/package.json +1 -1
package/README.md CHANGED
@@ -104,34 +104,29 @@ npx playwright test
104
104
 
105
105
  We support a **Friendly Syntax** for filtering tests via the `TAGS` environment variable.
106
106
 
107
- | Logic | Symbol | Example | Description |
108
- | ------- | ------- | ---------------- | ----------------------------------------------------- |
109
- | **OR** | `,` | `@login,@signup` | Run tests that have `@login` **OR** `@signup`. |
110
- | **AND** | `+` | `@smoke+@api` | Run tests that have **BOTH** `@smoke` **AND** `@api`. |
111
- | **MIX** | `,` `+` | `@a+@b, @c` | Run tests with (`@a` AND `@b`) **OR** just `@c`. |
107
+ | Logic | Symbol | Example | Description |
108
+ | ------- | ------ | ---------------- | ------------------------------------------------ |
109
+ | **AND** | `,` | `@login,@signup` | Run tests that have `@login` **AND** `@signup`. |
110
+ | |
111
+ | **MIX** | `,` | `@a,@b, @c` | Run tests with (`@a` AND `@b`) **OR** just `@c`. |
112
112
 
113
113
  **Usage:**
114
114
 
115
115
  ```bash
116
116
  # Run only smoke tests
117
117
  TAGS='@smoke' npx playwright test
118
+ OR
118
119
  npx playwright test -g "@smoke"
119
120
 
120
121
  # Run smoke tests that are also critical
121
- TAGS='@smoke+@critical' npx playwright test
122
- npx playwright test -g "(?=.*@smoke)(?=.*@critical)"
123
-
124
- # Run login OR regression tests
125
- TAGS='@login,@regression' npx playwright test
126
-
127
- npx playwright test -g "@login|@regression"
122
+ TAGS='@smoke,@critical' npx playwright test
123
+ OR
124
+ npx playwright test -g "@smoke|@critical"
128
125
 
129
126
  ```
130
127
 
131
128
  _(On Windows PowerShell, use `$env:TAGS="@smoke"; npx playwright test`)_
132
129
 
133
- ````
134
-
135
130
  **In your Test Runner (`tests/bdd.spec.ts`):**
136
131
 
137
132
  ```typescript
@@ -142,7 +137,7 @@ import { runTests } from "playwright-cucumber-ts-steps";
142
137
 
143
138
  // OPTION 2: Run only Smoke tests
144
139
  runTests("features/*.feature", { tags: "@smoke" });
145
- ````
140
+ ```
146
141
 
147
142
  ---
148
143
 
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=click.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/click.ts"],"names":[],"mappings":""}
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const registry_1 = require("../../core/registry");
4
+ const state_1 = require("../utils/state");
5
+ /**
6
+ * Clicks on the previously stored element.
7
+ * Pattern: When I click
8
+ */
9
+ (0, registry_1.Step)("I click", async (page, table) => {
10
+ const options = (0, state_1.parseClickOptions)(table);
11
+ const element = (0, state_1.getActiveElement)(page);
12
+ await element.click(options);
13
+ console.log("🖱️ Clicked on stored element");
14
+ });
15
+ /**
16
+ * Clicks on an element matching the given selector.
17
+ * Pattern: When I click on element {string}
18
+ */
19
+ (0, registry_1.Step)("I click on element {string}", async (page, selector, table) => {
20
+ const options = (0, state_1.parseClickOptions)(table);
21
+ const element = page.locator(selector);
22
+ await element.click(options);
23
+ (0, state_1.setActiveElement)(page, element);
24
+ console.log(`🖱️ Clicked on element "${selector}"`);
25
+ });
26
+ /**
27
+ * Clicks on a button with the given label.
28
+ * Pattern: When I click on button {string}
29
+ */
30
+ (0, registry_1.Step)("I click on button {string}", async (page, label, table) => {
31
+ const options = (0, state_1.parseClickOptions)(table);
32
+ const button = page.getByRole("button", { name: label });
33
+ await button.click(options);
34
+ (0, state_1.setActiveElement)(page, button);
35
+ console.log(`🖱️ Clicked on button "${label}"`);
36
+ });
37
+ /**
38
+ * Clicks on a link with the given text.
39
+ * Pattern: When I click on link {string}
40
+ */
41
+ (0, registry_1.Step)("I click on link {string}", async (page, text, table) => {
42
+ const options = (0, state_1.parseClickOptions)(table);
43
+ const link = page.getByRole("link", { name: text });
44
+ await link.click(options);
45
+ (0, state_1.setActiveElement)(page, link);
46
+ console.log(`✅ Clicked on link "${text}"`);
47
+ });
48
+ /**
49
+ * Clicks on a label with the given text.
50
+ * Pattern: When I click on label {string}
51
+ */
52
+ (0, registry_1.Step)("I click on label {string}", async (page, labelText, table) => {
53
+ const options = (0, state_1.parseClickOptions)(table);
54
+ const label = page.getByLabel(labelText);
55
+ await label.click(options);
56
+ (0, state_1.setActiveElement)(page, label);
57
+ console.log(`🏷️ Clicked on label "${labelText}"`);
58
+ });
59
+ /**
60
+ * Clicks on an element containing the given text (fuzzy match).
61
+ * Supports aliasing with @alias.
62
+ * Pattern: When I click on text {string}
63
+ */
64
+ (0, registry_1.Step)("I click on text {string}", async (page, rawText, table) => {
65
+ const options = (0, state_1.parseClickOptions)(table);
66
+ let text = rawText;
67
+ // Handle Alias (e.g., "@username")
68
+ if (rawText.startsWith("@")) {
69
+ const aliasKey = rawText.slice(1);
70
+ const storedValue = (0, state_1.getVariable)(page, aliasKey);
71
+ if (!storedValue) {
72
+ throw new Error(`❌ No value found for alias "@${aliasKey}"`);
73
+ }
74
+ text = storedValue;
75
+ }
76
+ const locator = page.getByText(text, { exact: false }).first();
77
+ await locator.waitFor({ state: "visible", timeout: 5000 });
78
+ await locator.click(options);
79
+ (0, state_1.setActiveElement)(page, locator);
80
+ console.log(`🖱️ Clicked on text "${text}"`);
81
+ });
82
+ /**
83
+ * Clicks on an element containing the exact given text.
84
+ * Pattern: When I click on exact text {string}
85
+ */
86
+ (0, registry_1.Step)("I click on exact text {string}", async (page, exactText, table) => {
87
+ const options = (0, state_1.parseClickOptions)(table);
88
+ const locator = page.getByText(exactText, { exact: true });
89
+ await locator.waitFor({ state: "visible", timeout: 5000 });
90
+ await locator.click(options);
91
+ (0, state_1.setActiveElement)(page, locator);
92
+ console.log(`🖱️ Clicked on exact text "${exactText}"`);
93
+ });
94
+ /**
95
+ * Clicks all previously stored elements.
96
+ * Pattern: When I click all
97
+ */
98
+ (0, registry_1.Step)("I click all", async (page, table) => {
99
+ const options = (0, state_1.parseClickOptions)(table);
100
+ const elements = (0, state_1.getActiveElements)(page);
101
+ const count = await elements.count();
102
+ if (count === 0)
103
+ throw new Error("⚠️ No elements found to click.");
104
+ for (let i = 0; i < count; i++) {
105
+ const el = elements.nth(i);
106
+ await el.waitFor({ state: "visible", timeout: 5000 });
107
+ await el.click(options);
108
+ console.log(`🖱️ Clicked element #${i + 1}`);
109
+ }
110
+ console.log(`✅ Clicked all ${count} elements.`);
111
+ });
112
+ /**
113
+ * Double-clicks on the previously stored element.
114
+ * Pattern: When I double click
115
+ */
116
+ (0, registry_1.Step)("I double click", async (page, table) => {
117
+ const options = (0, state_1.parseClickOptions)(table);
118
+ const element = (0, state_1.getActiveElement)(page);
119
+ await element.dblclick(options);
120
+ console.log("🖱️ Double-clicked on stored element");
121
+ });
122
+ /**
123
+ * Double-clicks on an element containing the given text.
124
+ * Pattern: When I double click on text {string}
125
+ */
126
+ (0, registry_1.Step)("I double click on text {string}", async (page, text, table) => {
127
+ const options = (0, state_1.parseClickOptions)(table);
128
+ const element = page.getByText(text).first();
129
+ await element.dblclick(options);
130
+ console.log(`🖱️ Double-clicked on text "${text}"`);
131
+ });
132
+ /**
133
+ * Double-clicks at the given page coordinates.
134
+ * Pattern: When I double click position {int} {int}
135
+ */
136
+ (0, registry_1.Step)("I double click position {int} {int}", async (page, x, y, table) => {
137
+ const options = (0, state_1.parseClickOptions)(table);
138
+ await page.mouse.dblclick(x, y, options);
139
+ console.log(`🖱️ Double-clicked at (${x}, ${y})`);
140
+ });
141
+ /**
142
+ * Right-clicks on the previously stored element.
143
+ * Pattern: When I right click
144
+ */
145
+ (0, registry_1.Step)("I right click", async (page, table) => {
146
+ const options = (0, state_1.parseClickOptions)(table);
147
+ const element = (0, state_1.getActiveElement)(page);
148
+ await element.click({ button: "right", ...options });
149
+ console.log("🖱️ Right-clicked on stored element");
150
+ });
151
+ /**
152
+ * Right-clicks on an element containing the given text.
153
+ * Pattern: When I right click on text {string}
154
+ */
155
+ (0, registry_1.Step)("I right click on text {string}", async (page, text, table) => {
156
+ const options = (0, state_1.parseClickOptions)(table);
157
+ const element = page.getByText(text).first();
158
+ await element.click({ button: "right", ...options });
159
+ console.log(`🖱️ Right-clicked on text "${text}"`);
160
+ });
161
+ /**
162
+ * Right-clicks at the given page coordinates.
163
+ * Pattern: When I right click position {int} {int}
164
+ */
165
+ (0, registry_1.Step)("I right click position {int} {int}", async (page, x, y, table) => {
166
+ const options = (0, state_1.parseClickOptions)(table);
167
+ await page.mouse.click(x, y, { button: "right", ...options });
168
+ console.log(`🖱️ Right-clicked at (${x}, ${y})`);
169
+ });
170
+ /**
171
+ * Clicks on an element matching the given selector (Regex Version).
172
+ * Pattern: I click on selector "..."
173
+ */
174
+ (0, registry_1.Step)(/^I click on selector "([^"]+)"$/, async (page, selector) => {
175
+ const locator = page.locator(selector);
176
+ await locator.click();
177
+ (0, state_1.setActiveElement)(page, locator);
178
+ console.log(`🖱️ Clicked on selector: ${selector}`);
179
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=find.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/find.ts"],"names":[],"mappings":""}
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ const registry_1 = require("../../core/registry");
5
+ const state_1 = require("../utils/state");
6
+ // =============================
7
+ // 1. GENERAL FINDING (Single)
8
+ // =============================
9
+ /**
10
+ * Finds an element by CSS selector.
11
+ * Pattern: When I find element by selector ".my-class"
12
+ */
13
+ (0, registry_1.Step)("I find element by selector {string}", async (page, selector) => {
14
+ const element = page.locator(selector);
15
+ await (0, test_1.expect)(element).toHaveCount(1);
16
+ (0, state_1.setActiveElement)(page, element);
17
+ console.log(`🔍 Found element by selector: "${selector}"`);
18
+ });
19
+ /**
20
+ * Finds an element by exact text.
21
+ * Pattern: When I find element by text "Submit"
22
+ */
23
+ (0, registry_1.Step)("I find element by text {string}", async (page, text) => {
24
+ const element = page.getByText(text, { exact: true });
25
+ await (0, test_1.expect)(element).toHaveCount(1);
26
+ (0, state_1.setActiveElement)(page, element);
27
+ console.log(`🔍 Found element by exact text: "${text}"`);
28
+ });
29
+ /**
30
+ * Finds an element by title attribute.
31
+ * Pattern: When I find element by title "Tooltip"
32
+ */
33
+ (0, registry_1.Step)("I find element by title {string}", async (page, title) => {
34
+ const element = page.getByTitle(title);
35
+ await (0, test_1.expect)(element).toHaveCount(1);
36
+ (0, state_1.setActiveElement)(page, element);
37
+ console.log(`🔍 Found element by title: "${title}"`);
38
+ });
39
+ /**
40
+ * Finds an element by test id (data-testid).
41
+ * Pattern: When I find element by testid "submit-btn"
42
+ */
43
+ (0, registry_1.Step)("I find element by testid {string}", async (page, testid) => {
44
+ const element = page.getByTestId(testid);
45
+ await (0, test_1.expect)(element).toHaveCount(1);
46
+ (0, state_1.setActiveElement)(page, element);
47
+ console.log(`🔍 Found element by testid: "${testid}"`);
48
+ });
49
+ /**
50
+ * Finds an element by ARIA role.
51
+ * Pattern: When I find element by role "button"
52
+ */
53
+ (0, registry_1.Step)("I find element by role {string}", async (page, role) => {
54
+ const element = page.getByRole(role);
55
+ await (0, test_1.expect)(element).toHaveCount(1);
56
+ (0, state_1.setActiveElement)(page, element);
57
+ console.log(`🔍 Found element by role: "${role}"`);
58
+ });
59
+ /**
60
+ * Finds an element by placeholder.
61
+ * Pattern: When I find element by placeholder text "Search..."
62
+ */
63
+ (0, registry_1.Step)("I find element by placeholder text {string}", async (page, text) => {
64
+ const element = page.getByPlaceholder(text);
65
+ await (0, test_1.expect)(element).toHaveCount(1);
66
+ (0, state_1.setActiveElement)(page, element);
67
+ console.log(`🔍 Found element by placeholder: "${text}"`);
68
+ });
69
+ /**
70
+ * Finds an element by label.
71
+ * Pattern: When I find element by label text "Username"
72
+ */
73
+ (0, registry_1.Step)("I find element by label text {string}", async (page, label) => {
74
+ const element = page.getByLabel(label);
75
+ await (0, test_1.expect)(element).toHaveCount(1);
76
+ (0, state_1.setActiveElement)(page, element);
77
+ console.log(`🔍 Found element by label: "${label}"`);
78
+ });
79
+ /**
80
+ * Finds an element by alt text (images).
81
+ * Pattern: When I find element by alt text "Logo"
82
+ */
83
+ (0, registry_1.Step)("I find element by alt text {string}", async (page, alt) => {
84
+ const element = page.getByAltText(alt);
85
+ await (0, test_1.expect)(element).toHaveCount(1);
86
+ (0, state_1.setActiveElement)(page, element);
87
+ console.log(`🔍 Found element by alt text: "${alt}"`);
88
+ });
89
+ // =============================
90
+ // 2. SPECIFIC ELEMENTS (Link/Heading/Name)
91
+ // =============================
92
+ /**
93
+ * Finds a link by text.
94
+ * Pattern: When I find link by text "Home"
95
+ */
96
+ (0, registry_1.Step)("I find link by text {string}", async (page, text) => {
97
+ const element = page.getByRole("link", { name: text });
98
+ // We use .first() here because links often have duplicates (e.g. footer/header)
99
+ // but strict mode usually prefers uniqueness.
100
+ (0, state_1.setActiveElement)(page, element.first());
101
+ console.log(`🔍 Found link by text: "${text}"`);
102
+ });
103
+ /**
104
+ * Finds a heading by text.
105
+ * Pattern: When I find heading by text "Welcome"
106
+ */
107
+ (0, registry_1.Step)("I find heading by text {string}", async (page, text) => {
108
+ const element = page.getByRole("heading", { name: text });
109
+ (0, state_1.setActiveElement)(page, element.first());
110
+ console.log(`🔍 Found heading by text: "${text}"`);
111
+ });
112
+ /**
113
+ * Finds an element by name attribute.
114
+ * Pattern: When I find element by name "email"
115
+ */
116
+ (0, registry_1.Step)("I find element by name {string}", async (page, name) => {
117
+ // Broad selector for name attribute
118
+ const element = page.locator(`[name="${name}"]`);
119
+ await (0, test_1.expect)(element).toHaveCount(1);
120
+ (0, state_1.setActiveElement)(page, element);
121
+ console.log(`🔍 Found element by name: "${name}"`);
122
+ });
123
+ // =============================
124
+ // 3. GENERAL FINDING (Multiple)
125
+ // =============================
126
+ /**
127
+ * Finds all elements by selector.
128
+ * Pattern: When I find elements by selector ".items"
129
+ */
130
+ (0, registry_1.Step)("I find elements by selector {string}", async (page, selector) => {
131
+ const elements = page.locator(selector);
132
+ const count = await elements.count();
133
+ (0, state_1.setActiveElements)(page, elements);
134
+ console.log(`🔍 Found ${count} elements with selector: "${selector}"`);
135
+ });
136
+ /**
137
+ * Finds all headings by text.
138
+ * Pattern: When I find headings by text "Chapter"
139
+ */
140
+ (0, registry_1.Step)("I find headings by text {string}", async (page, text) => {
141
+ const elements = page.getByRole("heading", { name: text });
142
+ (0, state_1.setActiveElements)(page, elements);
143
+ console.log(`🔍 Found headings matching "${text}"`);
144
+ });
145
+ /**
146
+ * Finds all buttons by text (supports alias).
147
+ * Pattern: When I find buttons by text "Save"
148
+ */
149
+ (0, registry_1.Step)("I find buttons by text {string}", async (page, text) => {
150
+ let searchText = text;
151
+ // Handle Alias
152
+ if (text.startsWith("@")) {
153
+ const alias = text.slice(1);
154
+ const val = (0, state_1.getVariable)(page, alias);
155
+ if (!val)
156
+ throw new Error(`❌ No value found for alias "@${alias}"`);
157
+ searchText = val;
158
+ }
159
+ const elements = page.getByRole("button", { name: searchText });
160
+ (0, state_1.setActiveElements)(page, elements);
161
+ console.log(`🔍 Found buttons matching "${searchText}"`);
162
+ });
163
+ // =============================
164
+ // 4. GET / REFINE SELECTION
165
+ // =============================
166
+ /**
167
+ * Gets the first element from a stored list.
168
+ * Pattern: When I get first element
169
+ */
170
+ (0, registry_1.Step)("I get first element", async (page) => {
171
+ const elements = (0, state_1.getActiveElements)(page);
172
+ const element = elements.first();
173
+ (0, state_1.setActiveElement)(page, element);
174
+ console.log("👉 Selected FIRST element");
175
+ });
176
+ /**
177
+ * Gets the last element from a stored list.
178
+ * Pattern: When I get last element
179
+ */
180
+ (0, registry_1.Step)("I get last element", async (page) => {
181
+ const elements = (0, state_1.getActiveElements)(page);
182
+ const element = elements.last();
183
+ (0, state_1.setActiveElement)(page, element);
184
+ console.log("👉 Selected LAST element");
185
+ });
186
+ /**
187
+ * Gets the nth element (1-based index).
188
+ * Pattern: When I get 2nd element
189
+ */
190
+ (0, registry_1.Step)(/^I get (\d+)(?:st|nd|rd|th) element$/, async (page, indexStr) => {
191
+ const index = parseInt(indexStr, 10);
192
+ const elements = (0, state_1.getActiveElements)(page);
193
+ const count = await elements.count();
194
+ if (index < 1 || index > count) {
195
+ throw new Error(`❌ Cannot get element #${index} — only ${count} found.`);
196
+ }
197
+ // Playwright is 0-based, Gherkin is 1-based
198
+ const element = elements.nth(index - 1);
199
+ (0, state_1.setActiveElement)(page, element);
200
+ console.log(`👉 Selected element #${index}`);
201
+ });
202
+ /**
203
+ * Gets the currently focused element.
204
+ * Pattern: When I get focused element
205
+ */
206
+ (0, registry_1.Step)("I get focused element", async (page) => {
207
+ // Use CSS selector for focused element
208
+ const element = page.locator("*:focus");
209
+ (0, state_1.setActiveElement)(page, element);
210
+ console.log("👉 Selected FOCUSED element");
211
+ });
212
+ // =============================
213
+ // 5. INPUTS & TEXTAREAS SPECIFICS
214
+ // =============================
215
+ /**
216
+ * Finds input by ID.
217
+ * Pattern: When I find input by ID "username"
218
+ */
219
+ (0, registry_1.Step)("I find input by ID {string}", async (page, id) => {
220
+ const element = page.locator(`input#${id}`);
221
+ (0, state_1.setActiveElement)(page, element);
222
+ console.log(`🔍 Found input by ID: "${id}"`);
223
+ });
224
+ /**
225
+ * Finds input by name.
226
+ * Pattern: When I find input by name "email"
227
+ */
228
+ (0, registry_1.Step)("I find input by name {string}", async (page, name) => {
229
+ const element = page.locator(`input[name="${name}"]`);
230
+ (0, state_1.setActiveElement)(page, element);
231
+ console.log(`🔍 Found input by name: "${name}"`);
232
+ });
233
+ /**
234
+ * Finds input by placeholder.
235
+ * Pattern: When I find input by placeholder text "Enter email"
236
+ */
237
+ (0, registry_1.Step)("I find input by placeholder text {string}", async (page, placeholder) => {
238
+ const element = page.locator(`input[placeholder="${placeholder}"]`);
239
+ (0, state_1.setActiveElement)(page, element);
240
+ console.log(`🔍 Found input by placeholder: "${placeholder}"`);
241
+ });
242
+ /**
243
+ * Finds input by display value (supports alias).
244
+ * Pattern: When I find input by display value "John Doe"
245
+ */
246
+ (0, registry_1.Step)("I find input by display value {string}", async (page, value) => {
247
+ let searchValue = value;
248
+ if (value.startsWith("@")) {
249
+ const alias = value.slice(1);
250
+ const val = (0, state_1.getVariable)(page, alias);
251
+ if (!val)
252
+ throw new Error(`❌ No value found for alias "@${alias}"`);
253
+ searchValue = val;
254
+ }
255
+ const element = page.locator(`input[value="${searchValue}"]`);
256
+ await (0, test_1.expect)(element).toBeVisible();
257
+ (0, state_1.setActiveElement)(page, element);
258
+ console.log(`🔍 Found input with value: "${searchValue}"`);
259
+ });
260
+ /**
261
+ * Finds textarea by label.
262
+ * Pattern: When I find textarea by label text "Comments"
263
+ */
264
+ (0, registry_1.Step)("I find textarea by label text {string}", async (page, label) => {
265
+ const element = page.getByLabel(label).locator("textarea").first();
266
+ // Fallback if strict label matching fails, try locator strategy
267
+ const count = await element.count();
268
+ if (count === 0) {
269
+ // Try generic label finding
270
+ const altElement = page.getByLabel(label);
271
+ (0, state_1.setActiveElement)(page, altElement);
272
+ }
273
+ else {
274
+ (0, state_1.setActiveElement)(page, element);
275
+ }
276
+ console.log(`🔍 Found textarea by label: "${label}"`);
277
+ });
278
+ // =============================
279
+ // 6. UTILITIES (Store Text)
280
+ // =============================
281
+ /**
282
+ * Stores the text of the current element into a variable.
283
+ * Pattern: When I store element text as "myVar"
284
+ */
285
+ (0, registry_1.Step)("I store element text as {string}", async (page, alias) => {
286
+ const element = (0, state_1.getActiveElement)(page);
287
+ const text = await element.textContent();
288
+ const cleanText = text?.trim() || "";
289
+ (0, state_1.setVariable)(page, alias, cleanText);
290
+ console.log(`💾 Stored text "${cleanText}" as variable "@${alias}"`);
291
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/form.ts"],"names":[],"mappings":""}