playwright-cucumber-ts-steps 1.1.8 → 1.1.9
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.
- package/LICENSE +21 -0
- package/dist/backend/actions/click.d.ts +132 -1
- package/dist/backend/actions/click.d.ts.map +1 -1
- package/dist/backend/actions/click.js +122 -53
- package/dist/backend/actions/find.d.ts +243 -1
- package/dist/backend/actions/find.d.ts.map +1 -1
- package/dist/backend/actions/find.js +196 -72
- package/dist/backend/actions/form.d.ts +37 -1
- package/dist/backend/actions/form.d.ts.map +1 -1
- package/dist/backend/actions/form.js +55 -3
- package/dist/backend/actions/formTable.d.ts +25 -1
- package/dist/backend/actions/formTable.d.ts.map +1 -1
- package/dist/backend/actions/formTable.js +27 -5
- package/dist/backend/actions/frames.d.ts +53 -1
- package/dist/backend/actions/frames.d.ts.map +1 -1
- package/dist/backend/actions/frames.js +48 -11
- package/dist/backend/actions/inputs.d.ts +139 -1
- package/dist/backend/actions/inputs.d.ts.map +1 -1
- package/dist/backend/actions/inputs.js +113 -43
- package/dist/backend/actions/interactions.d.ts +61 -1
- package/dist/backend/actions/interactions.d.ts.map +1 -1
- package/dist/backend/actions/interactions.js +65 -10
- package/dist/backend/actions/keyboard.d.ts +70 -1
- package/dist/backend/actions/keyboard.d.ts.map +1 -1
- package/dist/backend/actions/keyboard.js +59 -23
- package/dist/backend/actions/misc.d.ts +134 -1
- package/dist/backend/actions/misc.d.ts.map +1 -1
- package/dist/backend/actions/misc.js +106 -42
- package/dist/backend/actions/mobile.d.ts +74 -1
- package/dist/backend/actions/mobile.d.ts.map +1 -1
- package/dist/backend/actions/mobile.js +74 -13
- package/dist/backend/actions/mouse.d.ts +79 -1
- package/dist/backend/actions/mouse.d.ts.map +1 -1
- package/dist/backend/actions/mouse.js +66 -21
- package/dist/backend/actions/navigation.d.ts +48 -1
- package/dist/backend/actions/navigation.d.ts.map +1 -1
- package/dist/backend/actions/navigation.js +42 -15
- package/dist/backend/actions/waits.d.ts +55 -1
- package/dist/backend/actions/waits.d.ts.map +1 -1
- package/dist/backend/actions/waits.js +49 -17
- package/dist/backend/api/assertions.d.ts +32 -1
- package/dist/backend/api/assertions.d.ts.map +1 -1
- package/dist/backend/api/assertions.js +37 -9
- package/dist/backend/api/mock.d.ts +34 -1
- package/dist/backend/api/mock.d.ts.map +1 -1
- package/dist/backend/api/mock.js +37 -10
- package/dist/backend/api/network.d.ts +60 -1
- package/dist/backend/api/network.d.ts.map +1 -1
- package/dist/backend/api/network.js +53 -21
- package/dist/backend/api/requests.d.ts +43 -1
- package/dist/backend/api/requests.d.ts.map +1 -1
- package/dist/backend/api/requests.js +49 -17
- package/dist/backend/assertions/pageState.d.ts +40 -1
- package/dist/backend/assertions/pageState.d.ts.map +1 -1
- package/dist/backend/assertions/pageState.js +33 -12
- package/dist/backend/assertions/text.d.ts +46 -1
- package/dist/backend/assertions/text.d.ts.map +1 -1
- package/dist/backend/assertions/text.js +51 -8
- package/dist/backend/assertions/visibility.d.ts +102 -1
- package/dist/backend/assertions/visibility.d.ts.map +1 -1
- package/dist/backend/assertions/visibility.js +86 -36
- package/dist/backend/auth/index.js +2 -2
- package/dist/backend/db/steps.d.ts +35 -1
- package/dist/backend/db/steps.d.ts.map +1 -1
- package/dist/backend/db/steps.js +48 -15
- package/dist/backend/elements/alerts.d.ts +35 -1
- package/dist/backend/elements/alerts.d.ts.map +1 -1
- package/dist/backend/elements/alerts.js +39 -6
- package/dist/backend/elements/forms.d.ts +44 -1
- package/dist/backend/elements/forms.d.ts.map +1 -1
- package/dist/backend/elements/forms.js +50 -11
- package/dist/backend/elements/frames.d.ts +36 -1
- package/dist/backend/elements/frames.d.ts.map +1 -1
- package/dist/backend/elements/frames.js +43 -13
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +3 -4
- package/package.json +52 -12
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StoreElementText = exports.FindTextareaByLabel = exports.FindInputByValue = exports.FindInputByPlaceholder = exports.FindInputByName = exports.FindInputById = exports.GetFocusedElement = exports.GetNthElement = exports.GetLastElement = exports.GetFirstElement = exports.FindButtonsByText = exports.FindHeadingsByText = exports.FindElementsBySelector = exports.FindElementByName = exports.FindHeadingByText = exports.FindLinkByText = exports.FindElementByAltText = exports.FindElementByLabel = exports.FindElementByPlaceholder = exports.FindElementByRole = exports.FindElementByTestId = exports.FindElementByTitle = exports.FindElementByText = exports.FindElementBySelector = void 0;
|
|
3
4
|
const test_1 = require("@playwright/test");
|
|
4
5
|
const registry_1 = require("../../core/registry");
|
|
5
6
|
const state_1 = require("../utils/state");
|
|
@@ -7,80 +8,121 @@ const state_1 = require("../utils/state");
|
|
|
7
8
|
// 1. GENERAL FINDING (Single)
|
|
8
9
|
// =============================
|
|
9
10
|
/**
|
|
10
|
-
* Finds
|
|
11
|
-
*
|
|
11
|
+
* Finds a single element using a CSS or XPath selector.
|
|
12
|
+
* Asserts that exactly one element is found.
|
|
13
|
+
*
|
|
14
|
+
* ```gherkin
|
|
15
|
+
* When I find element by selector ".nav-bar"
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @param selector - The CSS or XPath selector string.
|
|
12
19
|
*/
|
|
13
|
-
(0, registry_1.Step)("I find element by selector {string}", async (page, selector) => {
|
|
20
|
+
exports.FindElementBySelector = (0, registry_1.Step)("I find element by selector {string}", async (page, selector) => {
|
|
14
21
|
const element = page.locator(selector);
|
|
15
22
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
16
23
|
(0, state_1.setActiveElement)(page, element);
|
|
17
24
|
console.log(`🔍 Found element by selector: "${selector}"`);
|
|
18
25
|
});
|
|
19
26
|
/**
|
|
20
|
-
* Finds an element
|
|
21
|
-
*
|
|
27
|
+
* Finds an element containing the exact text provided.
|
|
28
|
+
*
|
|
29
|
+
* ```gherkin
|
|
30
|
+
* When I find element by text "Submit Order"
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @param text - The exact text content to match.
|
|
22
34
|
*/
|
|
23
|
-
(0, registry_1.Step)("I find element by text {string}", async (page, text) => {
|
|
35
|
+
exports.FindElementByText = (0, registry_1.Step)("I find element by text {string}", async (page, text) => {
|
|
24
36
|
const element = page.getByText(text, { exact: true });
|
|
25
37
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
26
38
|
(0, state_1.setActiveElement)(page, element);
|
|
27
39
|
console.log(`🔍 Found element by exact text: "${text}"`);
|
|
28
40
|
});
|
|
29
41
|
/**
|
|
30
|
-
* Finds an element by title attribute.
|
|
31
|
-
*
|
|
42
|
+
* Finds an element by its `title` attribute.
|
|
43
|
+
*
|
|
44
|
+
* ```gherkin
|
|
45
|
+
* When I find element by title "Close Modal"
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @param title - The value of the title attribute.
|
|
32
49
|
*/
|
|
33
|
-
(0, registry_1.Step)("I find element by title {string}", async (page, title) => {
|
|
50
|
+
exports.FindElementByTitle = (0, registry_1.Step)("I find element by title {string}", async (page, title) => {
|
|
34
51
|
const element = page.getByTitle(title);
|
|
35
52
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
36
53
|
(0, state_1.setActiveElement)(page, element);
|
|
37
54
|
console.log(`🔍 Found element by title: "${title}"`);
|
|
38
55
|
});
|
|
39
56
|
/**
|
|
40
|
-
* Finds an element by test
|
|
41
|
-
*
|
|
57
|
+
* Finds an element by its test ID (usually `data-testid`).
|
|
58
|
+
*
|
|
59
|
+
* ```gherkin
|
|
60
|
+
* When I find element by testid "login-form"
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @param testid - The data-testid attribute value.
|
|
42
64
|
*/
|
|
43
|
-
(0, registry_1.Step)("I find element by testid {string}", async (page, testid) => {
|
|
65
|
+
exports.FindElementByTestId = (0, registry_1.Step)("I find element by testid {string}", async (page, testid) => {
|
|
44
66
|
const element = page.getByTestId(testid);
|
|
45
67
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
46
68
|
(0, state_1.setActiveElement)(page, element);
|
|
47
69
|
console.log(`🔍 Found element by testid: "${testid}"`);
|
|
48
70
|
});
|
|
49
71
|
/**
|
|
50
|
-
* Finds an element by ARIA role.
|
|
51
|
-
*
|
|
72
|
+
* Finds an element by its ARIA role.
|
|
73
|
+
*
|
|
74
|
+
* ```gherkin
|
|
75
|
+
* When I find element by role "button"
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @param role - The ARIA role (e.g., "button", "link", "heading").
|
|
52
79
|
*/
|
|
53
|
-
(0, registry_1.Step)("I find element by role {string}", async (page, role) => {
|
|
80
|
+
exports.FindElementByRole = (0, registry_1.Step)("I find element by role {string}", async (page, role) => {
|
|
54
81
|
const element = page.getByRole(role);
|
|
55
82
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
56
83
|
(0, state_1.setActiveElement)(page, element);
|
|
57
84
|
console.log(`🔍 Found element by role: "${role}"`);
|
|
58
85
|
});
|
|
59
86
|
/**
|
|
60
|
-
* Finds an element by placeholder.
|
|
61
|
-
*
|
|
87
|
+
* Finds an input element by its placeholder text.
|
|
88
|
+
*
|
|
89
|
+
* ```gherkin
|
|
90
|
+
* When I find element by placeholder text "Enter your email"
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @param text - The placeholder text value.
|
|
62
94
|
*/
|
|
63
|
-
(0, registry_1.Step)("I find element by placeholder text {string}", async (page, text) => {
|
|
95
|
+
exports.FindElementByPlaceholder = (0, registry_1.Step)("I find element by placeholder text {string}", async (page, text) => {
|
|
64
96
|
const element = page.getByPlaceholder(text);
|
|
65
97
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
66
98
|
(0, state_1.setActiveElement)(page, element);
|
|
67
99
|
console.log(`🔍 Found element by placeholder: "${text}"`);
|
|
68
100
|
});
|
|
69
101
|
/**
|
|
70
|
-
* Finds
|
|
71
|
-
*
|
|
102
|
+
* Finds a form control associated with a specific label text.
|
|
103
|
+
*
|
|
104
|
+
* ```gherkin
|
|
105
|
+
* When I find element by label text "Password"
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @param label - The visible text of the label.
|
|
72
109
|
*/
|
|
73
|
-
(0, registry_1.Step)("I find element by label text {string}", async (page, label) => {
|
|
110
|
+
exports.FindElementByLabel = (0, registry_1.Step)("I find element by label text {string}", async (page, label) => {
|
|
74
111
|
const element = page.getByLabel(label);
|
|
75
112
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
76
113
|
(0, state_1.setActiveElement)(page, element);
|
|
77
114
|
console.log(`🔍 Found element by label: "${label}"`);
|
|
78
115
|
});
|
|
79
116
|
/**
|
|
80
|
-
* Finds an element by alt text
|
|
81
|
-
*
|
|
117
|
+
* Finds an element (usually an image) by its alt text.
|
|
118
|
+
*
|
|
119
|
+
* ```gherkin
|
|
120
|
+
* When I find element by alt text "Company Logo"
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @param alt - The value of the alt attribute.
|
|
82
124
|
*/
|
|
83
|
-
(0, registry_1.Step)("I find element by alt text {string}", async (page, alt) => {
|
|
125
|
+
exports.FindElementByAltText = (0, registry_1.Step)("I find element by alt text {string}", async (page, alt) => {
|
|
84
126
|
const element = page.getByAltText(alt);
|
|
85
127
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
86
128
|
(0, state_1.setActiveElement)(page, element);
|
|
@@ -90,10 +132,16 @@ const state_1 = require("../utils/state");
|
|
|
90
132
|
// 2. SPECIFIC ELEMENTS (Link/Heading/Name)
|
|
91
133
|
// =============================
|
|
92
134
|
/**
|
|
93
|
-
* Finds a link by text.
|
|
94
|
-
*
|
|
135
|
+
* Finds a specific link by its visible text.
|
|
136
|
+
* If multiple links match, selects the first one.
|
|
137
|
+
*
|
|
138
|
+
* ```gherkin
|
|
139
|
+
* When I find link by text "Read More"
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @param text - The visible text of the link.
|
|
95
143
|
*/
|
|
96
|
-
(0, registry_1.Step)("I find link by text {string}", async (page, text) => {
|
|
144
|
+
exports.FindLinkByText = (0, registry_1.Step)("I find link by text {string}", async (page, text) => {
|
|
97
145
|
const element = page.getByRole("link", { name: text });
|
|
98
146
|
// We use .first() here because links often have duplicates (e.g. footer/header)
|
|
99
147
|
// but strict mode usually prefers uniqueness.
|
|
@@ -101,19 +149,31 @@ const state_1 = require("../utils/state");
|
|
|
101
149
|
console.log(`🔍 Found link by text: "${text}"`);
|
|
102
150
|
});
|
|
103
151
|
/**
|
|
104
|
-
* Finds a heading by text.
|
|
105
|
-
*
|
|
152
|
+
* Finds a heading (h1-h6) by its text content.
|
|
153
|
+
* If multiple headings match, selects the first one.
|
|
154
|
+
*
|
|
155
|
+
* ```gherkin
|
|
156
|
+
* When I find heading by text "Dashboard"
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @param text - The text content of the heading.
|
|
106
160
|
*/
|
|
107
|
-
(0, registry_1.Step)("I find heading by text {string}", async (page, text) => {
|
|
161
|
+
exports.FindHeadingByText = (0, registry_1.Step)("I find heading by text {string}", async (page, text) => {
|
|
108
162
|
const element = page.getByRole("heading", { name: text });
|
|
109
163
|
(0, state_1.setActiveElement)(page, element.first());
|
|
110
164
|
console.log(`🔍 Found heading by text: "${text}"`);
|
|
111
165
|
});
|
|
112
166
|
/**
|
|
113
|
-
* Finds an element by name attribute.
|
|
114
|
-
*
|
|
167
|
+
* Finds an element by its `name` attribute.
|
|
168
|
+
* Useful for form fields not easily accessible by label.
|
|
169
|
+
*
|
|
170
|
+
* ```gherkin
|
|
171
|
+
* When I find element by name "csrf_token"
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* @param name - The value of the name attribute.
|
|
115
175
|
*/
|
|
116
|
-
(0, registry_1.Step)("I find element by name {string}", async (page, name) => {
|
|
176
|
+
exports.FindElementByName = (0, registry_1.Step)("I find element by name {string}", async (page, name) => {
|
|
117
177
|
// Broad selector for name attribute
|
|
118
178
|
const element = page.locator(`[name="${name}"]`);
|
|
119
179
|
await (0, test_1.expect)(element).toHaveCount(1);
|
|
@@ -124,29 +184,45 @@ const state_1 = require("../utils/state");
|
|
|
124
184
|
// 3. GENERAL FINDING (Multiple)
|
|
125
185
|
// =============================
|
|
126
186
|
/**
|
|
127
|
-
* Finds all elements
|
|
128
|
-
*
|
|
187
|
+
* Finds all elements matching a CSS selector and stores them as a list.
|
|
188
|
+
*
|
|
189
|
+
* ```gherkin
|
|
190
|
+
* When I find elements by selector "ul > li"
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* @param selector - The CSS selector.
|
|
129
194
|
*/
|
|
130
|
-
(0, registry_1.Step)("I find elements by selector {string}", async (page, selector) => {
|
|
195
|
+
exports.FindElementsBySelector = (0, registry_1.Step)("I find elements by selector {string}", async (page, selector) => {
|
|
131
196
|
const elements = page.locator(selector);
|
|
132
197
|
const count = await elements.count();
|
|
133
198
|
(0, state_1.setActiveElements)(page, elements);
|
|
134
199
|
console.log(`🔍 Found ${count} elements with selector: "${selector}"`);
|
|
135
200
|
});
|
|
136
201
|
/**
|
|
137
|
-
* Finds all headings
|
|
138
|
-
*
|
|
202
|
+
* Finds all headings matching specific text.
|
|
203
|
+
*
|
|
204
|
+
* ```gherkin
|
|
205
|
+
* When I find headings by text "Article Title"
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @param text - The text to match headings against.
|
|
139
209
|
*/
|
|
140
|
-
(0, registry_1.Step)("I find headings by text {string}", async (page, text) => {
|
|
210
|
+
exports.FindHeadingsByText = (0, registry_1.Step)("I find headings by text {string}", async (page, text) => {
|
|
141
211
|
const elements = page.getByRole("heading", { name: text });
|
|
142
212
|
(0, state_1.setActiveElements)(page, elements);
|
|
143
213
|
console.log(`🔍 Found headings matching "${text}"`);
|
|
144
214
|
});
|
|
145
215
|
/**
|
|
146
|
-
* Finds all buttons
|
|
147
|
-
*
|
|
216
|
+
* Finds all buttons matching specific text.
|
|
217
|
+
* Supports variable aliasing (e.g., "@buttonName").
|
|
218
|
+
*
|
|
219
|
+
* ```gherkin
|
|
220
|
+
* When I find buttons by text "Add to Cart"
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* @param text - The button text or an alias (e.g., "@myBtn").
|
|
148
224
|
*/
|
|
149
|
-
(0, registry_1.Step)("I find buttons by text {string}", async (page, text) => {
|
|
225
|
+
exports.FindButtonsByText = (0, registry_1.Step)("I find buttons by text {string}", async (page, text) => {
|
|
150
226
|
let searchText = text;
|
|
151
227
|
// Handle Alias
|
|
152
228
|
if (text.startsWith("@")) {
|
|
@@ -164,30 +240,43 @@ const state_1 = require("../utils/state");
|
|
|
164
240
|
// 4. GET / REFINE SELECTION
|
|
165
241
|
// =============================
|
|
166
242
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
243
|
+
* Selects the first element from the currently stored list of elements.
|
|
244
|
+
*
|
|
245
|
+
* ```gherkin
|
|
246
|
+
* When I get first element
|
|
247
|
+
* ```
|
|
169
248
|
*/
|
|
170
|
-
(0, registry_1.Step)("I get first element", async (page) => {
|
|
249
|
+
exports.GetFirstElement = (0, registry_1.Step)("I get first element", async (page) => {
|
|
171
250
|
const elements = (0, state_1.getActiveElements)(page);
|
|
172
251
|
const element = elements.first();
|
|
173
252
|
(0, state_1.setActiveElement)(page, element);
|
|
174
253
|
console.log("👉 Selected FIRST element");
|
|
175
254
|
});
|
|
176
255
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
256
|
+
* Selects the last element from the currently stored list of elements.
|
|
257
|
+
*
|
|
258
|
+
* ```gherkin
|
|
259
|
+
* When I get last element
|
|
260
|
+
* ```
|
|
179
261
|
*/
|
|
180
|
-
(0, registry_1.Step)("I get last element", async (page) => {
|
|
262
|
+
exports.GetLastElement = (0, registry_1.Step)("I get last element", async (page) => {
|
|
181
263
|
const elements = (0, state_1.getActiveElements)(page);
|
|
182
264
|
const element = elements.last();
|
|
183
265
|
(0, state_1.setActiveElement)(page, element);
|
|
184
266
|
console.log("👉 Selected LAST element");
|
|
185
267
|
});
|
|
186
268
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
269
|
+
* Selects the nth element from the currently stored list.
|
|
270
|
+
* Uses 1-based indexing (e.g., 1st, 2nd, 3rd).
|
|
271
|
+
*
|
|
272
|
+
* ```gherkin
|
|
273
|
+
* When I get 2nd element
|
|
274
|
+
* When I get 10th element
|
|
275
|
+
* ```
|
|
276
|
+
*
|
|
277
|
+
* @param indexStr - The number captured from the regex (e.g., "2").
|
|
189
278
|
*/
|
|
190
|
-
(0, registry_1.Step)(/^I get (\d+)(?:st|nd|rd|th) element$/, async (page, indexStr) => {
|
|
279
|
+
exports.GetNthElement = (0, registry_1.Step)(/^I get (\d+)(?:st|nd|rd|th) element$/, async (page, indexStr) => {
|
|
191
280
|
const index = parseInt(indexStr, 10);
|
|
192
281
|
const elements = (0, state_1.getActiveElements)(page);
|
|
193
282
|
const count = await elements.count();
|
|
@@ -200,10 +289,13 @@ const state_1 = require("../utils/state");
|
|
|
200
289
|
console.log(`👉 Selected element #${index}`);
|
|
201
290
|
});
|
|
202
291
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
292
|
+
* Selects the element that currently has browser focus.
|
|
293
|
+
*
|
|
294
|
+
* ```gherkin
|
|
295
|
+
* When I get focused element
|
|
296
|
+
* ```
|
|
205
297
|
*/
|
|
206
|
-
(0, registry_1.Step)("I get focused element", async (page) => {
|
|
298
|
+
exports.GetFocusedElement = (0, registry_1.Step)("I get focused element", async (page) => {
|
|
207
299
|
// Use CSS selector for focused element
|
|
208
300
|
const element = page.locator("*:focus");
|
|
209
301
|
(0, state_1.setActiveElement)(page, element);
|
|
@@ -213,37 +305,58 @@ const state_1 = require("../utils/state");
|
|
|
213
305
|
// 5. INPUTS & TEXTAREAS SPECIFICS
|
|
214
306
|
// =============================
|
|
215
307
|
/**
|
|
216
|
-
* Finds input by ID.
|
|
217
|
-
*
|
|
308
|
+
* Finds an input field by its ID attribute.
|
|
309
|
+
*
|
|
310
|
+
* ```gherkin
|
|
311
|
+
* When I find input by ID "user_email"
|
|
312
|
+
* ```
|
|
313
|
+
*
|
|
314
|
+
* @param id - The ID string.
|
|
218
315
|
*/
|
|
219
|
-
(0, registry_1.Step)("I find input by ID {string}", async (page, id) => {
|
|
316
|
+
exports.FindInputById = (0, registry_1.Step)("I find input by ID {string}", async (page, id) => {
|
|
220
317
|
const element = page.locator(`input#${id}`);
|
|
221
318
|
(0, state_1.setActiveElement)(page, element);
|
|
222
319
|
console.log(`🔍 Found input by ID: "${id}"`);
|
|
223
320
|
});
|
|
224
321
|
/**
|
|
225
|
-
* Finds input by name.
|
|
226
|
-
*
|
|
322
|
+
* Finds an input field by its name attribute.
|
|
323
|
+
*
|
|
324
|
+
* ```gherkin
|
|
325
|
+
* When I find input by name "password"
|
|
326
|
+
* ```
|
|
327
|
+
*
|
|
328
|
+
* @param name - The name attribute value.
|
|
227
329
|
*/
|
|
228
|
-
(0, registry_1.Step)("I find input by name {string}", async (page, name) => {
|
|
330
|
+
exports.FindInputByName = (0, registry_1.Step)("I find input by name {string}", async (page, name) => {
|
|
229
331
|
const element = page.locator(`input[name="${name}"]`);
|
|
230
332
|
(0, state_1.setActiveElement)(page, element);
|
|
231
333
|
console.log(`🔍 Found input by name: "${name}"`);
|
|
232
334
|
});
|
|
233
335
|
/**
|
|
234
|
-
* Finds input by placeholder.
|
|
235
|
-
*
|
|
336
|
+
* Finds an input field by its placeholder text.
|
|
337
|
+
*
|
|
338
|
+
* ```gherkin
|
|
339
|
+
* When I find input by placeholder text "Search products..."
|
|
340
|
+
* ```
|
|
341
|
+
*
|
|
342
|
+
* @param placeholder - The placeholder text.
|
|
236
343
|
*/
|
|
237
|
-
(0, registry_1.Step)("I find input by placeholder text {string}", async (page, placeholder) => {
|
|
344
|
+
exports.FindInputByPlaceholder = (0, registry_1.Step)("I find input by placeholder text {string}", async (page, placeholder) => {
|
|
238
345
|
const element = page.locator(`input[placeholder="${placeholder}"]`);
|
|
239
346
|
(0, state_1.setActiveElement)(page, element);
|
|
240
347
|
console.log(`🔍 Found input by placeholder: "${placeholder}"`);
|
|
241
348
|
});
|
|
242
349
|
/**
|
|
243
|
-
* Finds input
|
|
244
|
-
*
|
|
350
|
+
* Finds an input field that currently has a specific value.
|
|
351
|
+
* Supports variable aliasing (e.g., "@storedValue").
|
|
352
|
+
*
|
|
353
|
+
* ```gherkin
|
|
354
|
+
* When I find input by display value "John"
|
|
355
|
+
* ```
|
|
356
|
+
*
|
|
357
|
+
* @param value - The value to match.
|
|
245
358
|
*/
|
|
246
|
-
(0, registry_1.Step)("I find input by display value {string}", async (page, value) => {
|
|
359
|
+
exports.FindInputByValue = (0, registry_1.Step)("I find input by display value {string}", async (page, value) => {
|
|
247
360
|
let searchValue = value;
|
|
248
361
|
if (value.startsWith("@")) {
|
|
249
362
|
const alias = value.slice(1);
|
|
@@ -258,10 +371,16 @@ const state_1 = require("../utils/state");
|
|
|
258
371
|
console.log(`🔍 Found input with value: "${searchValue}"`);
|
|
259
372
|
});
|
|
260
373
|
/**
|
|
261
|
-
* Finds textarea
|
|
262
|
-
*
|
|
374
|
+
* Finds a textarea associated with a specific label.
|
|
375
|
+
* Fallback mechanism attempts to find the textarea via label if the standard getByLabel returns a generic element.
|
|
376
|
+
*
|
|
377
|
+
* ```gherkin
|
|
378
|
+
* When I find textarea by label text "Description"
|
|
379
|
+
* ```
|
|
380
|
+
*
|
|
381
|
+
* @param label - The visible text of the label.
|
|
263
382
|
*/
|
|
264
|
-
(0, registry_1.Step)("I find textarea by label text {string}", async (page, label) => {
|
|
383
|
+
exports.FindTextareaByLabel = (0, registry_1.Step)("I find textarea by label text {string}", async (page, label) => {
|
|
265
384
|
const element = page.getByLabel(label).locator("textarea").first();
|
|
266
385
|
// Fallback if strict label matching fails, try locator strategy
|
|
267
386
|
const count = await element.count();
|
|
@@ -279,10 +398,15 @@ const state_1 = require("../utils/state");
|
|
|
279
398
|
// 6. UTILITIES (Store Text)
|
|
280
399
|
// =============================
|
|
281
400
|
/**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
401
|
+
* Reads the text content of the currently active element and stores it in a variable.
|
|
402
|
+
*
|
|
403
|
+
* ```gherkin
|
|
404
|
+
* When I store element text as "confirmationCode"
|
|
405
|
+
* ```
|
|
406
|
+
*
|
|
407
|
+
* @param alias - The name of the variable to store the text in (without "@").
|
|
284
408
|
*/
|
|
285
|
-
(0, registry_1.Step)("I store element text as {string}", async (page, alias) => {
|
|
409
|
+
exports.StoreElementText = (0, registry_1.Step)("I store element text as {string}", async (page, alias) => {
|
|
286
410
|
const element = (0, state_1.getActiveElement)(page);
|
|
287
411
|
const text = await element.textContent();
|
|
288
412
|
const cleanText = text?.trim() || "";
|
|
@@ -1,2 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* A "Swiss Army Knife" step for filling forms, performing assertions, and executing mixed workflows.
|
|
3
|
+
* It iterates through a Data Table and performs actions based on the `Target` and `Value` columns.
|
|
4
|
+
*
|
|
5
|
+
* ```gherkin
|
|
6
|
+
* When I fill the following {string} form data
|
|
7
|
+
* ```
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* **Columns:**
|
|
11
|
+
* - `Target`: The CSS selector, or a special keyword (request:, set:localStorage:, wait).
|
|
12
|
+
* - `Value`: The value to input, the action (click, check), or assertion pattern.
|
|
13
|
+
*
|
|
14
|
+
* **Supported UI Actions:**
|
|
15
|
+
* - **Fill:** Default behavior. Types `Value` into `Target`.
|
|
16
|
+
* - **Click:** Set `Value` to "click".
|
|
17
|
+
* - **Check:** Set `Value` to "check".
|
|
18
|
+
* - **Select:** Set `Value` to "select" (selects first option).
|
|
19
|
+
* - **Assert Visible:** Set `Value` to "assert:visible".
|
|
20
|
+
* - **Assert Text:** Set `Value` to "assert:text:Expected Text".
|
|
21
|
+
*
|
|
22
|
+
* **Supported Special Actions:**
|
|
23
|
+
* - **API Request:** Target = `request:METHOD:URL`, Value = `payload_filename.json`.
|
|
24
|
+
* - **Local Storage:** Target = `set:localStorage:key`, Value = `value`.
|
|
25
|
+
* - **Wait:** Target = `wait`, Value = `wait:1000` (ms).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* When I fill the following "Login Flow" form data:
|
|
29
|
+
* | Target | Value |
|
|
30
|
+
* | #username | myuser |
|
|
31
|
+
* | #password | @secretPassword |
|
|
32
|
+
* | #login-btn | click |
|
|
33
|
+
* | wait | wait:500 |
|
|
34
|
+
* | .error-msg | assert:visible |
|
|
35
|
+
* | request:GET:/api/status | body: {} |
|
|
36
|
+
*/
|
|
37
|
+
export declare const FillFormData: void;
|
|
2
38
|
//# sourceMappingURL=form.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/form.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/form.ts"],"names":[],"mappings":"AAkFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,YAAY,MAgIxB,CAAC"}
|
|
@@ -33,14 +33,19 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FillFormData = void 0;
|
|
36
37
|
const fs = __importStar(require("fs"));
|
|
37
38
|
const path = __importStar(require("path"));
|
|
38
39
|
const test_1 = require("@playwright/test");
|
|
39
40
|
const registry_1 = require("../../core/registry");
|
|
40
41
|
const state_1 = require("../utils/state");
|
|
41
42
|
/**
|
|
42
|
-
* Helper to convert raw runner table into Objects (ActionRow[])
|
|
43
|
-
* Handles whitespace in headers (e.g., "| Target |" -> "Target")
|
|
43
|
+
* Helper to convert raw runner table into Objects (ActionRow[]).
|
|
44
|
+
* Handles whitespace in headers (e.g., "| Target |" -> "Target").
|
|
45
|
+
* Supports both Cucumber DataTables (hashes) and Raw Arrays (Custom Runner).
|
|
46
|
+
*
|
|
47
|
+
* @param table - The raw table object from the test runner.
|
|
48
|
+
* @returns An array of ActionRow objects.
|
|
44
49
|
*/
|
|
45
50
|
function parseDataTable(table) {
|
|
46
51
|
// Debug Log: See exactly what the runner is passing
|
|
@@ -65,6 +70,14 @@ function parseDataTable(table) {
|
|
|
65
70
|
}
|
|
66
71
|
return [];
|
|
67
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Helper to resolve values, handling variable aliases.
|
|
75
|
+
* If a value starts with "@", it retrieves it from the global state.
|
|
76
|
+
*
|
|
77
|
+
* @param page - The Playwright Page object (for context).
|
|
78
|
+
* @param rawValue - The value string from the Gherkin table.
|
|
79
|
+
* @returns The resolved string value.
|
|
80
|
+
*/
|
|
68
81
|
function resolveValue(page, rawValue) {
|
|
69
82
|
if (!rawValue)
|
|
70
83
|
return "";
|
|
@@ -81,7 +94,43 @@ function resolveValue(page, rawValue) {
|
|
|
81
94
|
}
|
|
82
95
|
return trimmed;
|
|
83
96
|
}
|
|
84
|
-
|
|
97
|
+
/**
|
|
98
|
+
* A "Swiss Army Knife" step for filling forms, performing assertions, and executing mixed workflows.
|
|
99
|
+
* It iterates through a Data Table and performs actions based on the `Target` and `Value` columns.
|
|
100
|
+
*
|
|
101
|
+
* ```gherkin
|
|
102
|
+
* When I fill the following {string} form data
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* **Columns:**
|
|
107
|
+
* - `Target`: The CSS selector, or a special keyword (request:, set:localStorage:, wait).
|
|
108
|
+
* - `Value`: The value to input, the action (click, check), or assertion pattern.
|
|
109
|
+
*
|
|
110
|
+
* **Supported UI Actions:**
|
|
111
|
+
* - **Fill:** Default behavior. Types `Value` into `Target`.
|
|
112
|
+
* - **Click:** Set `Value` to "click".
|
|
113
|
+
* - **Check:** Set `Value` to "check".
|
|
114
|
+
* - **Select:** Set `Value` to "select" (selects first option).
|
|
115
|
+
* - **Assert Visible:** Set `Value` to "assert:visible".
|
|
116
|
+
* - **Assert Text:** Set `Value` to "assert:text:Expected Text".
|
|
117
|
+
*
|
|
118
|
+
* **Supported Special Actions:**
|
|
119
|
+
* - **API Request:** Target = `request:METHOD:URL`, Value = `payload_filename.json`.
|
|
120
|
+
* - **Local Storage:** Target = `set:localStorage:key`, Value = `value`.
|
|
121
|
+
* - **Wait:** Target = `wait`, Value = `wait:1000` (ms).
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* When I fill the following "Login Flow" form data:
|
|
125
|
+
* | Target | Value |
|
|
126
|
+
* | #username | myuser |
|
|
127
|
+
* | #password | @secretPassword |
|
|
128
|
+
* | #login-btn | click |
|
|
129
|
+
* | wait | wait:500 |
|
|
130
|
+
* | .error-msg | assert:visible |
|
|
131
|
+
* | request:GET:/api/status | body: {} |
|
|
132
|
+
*/
|
|
133
|
+
exports.FillFormData = (0, registry_1.Step)("I fill the following {string} form data", async (page, formName, table) => {
|
|
85
134
|
console.log(`📝 Processing Form: "${formName}"`);
|
|
86
135
|
// Parse the table
|
|
87
136
|
const rows = parseDataTable(table);
|
|
@@ -101,6 +150,7 @@ function resolveValue(page, rawValue) {
|
|
|
101
150
|
// ============================================
|
|
102
151
|
// 1. SPECIAL ACTIONS
|
|
103
152
|
// ============================================
|
|
153
|
+
// ✅ API Requests
|
|
104
154
|
if (target.startsWith("request:")) {
|
|
105
155
|
const parts = target.replace("request:", "").split(":");
|
|
106
156
|
const method = parts[0].toUpperCase();
|
|
@@ -126,6 +176,7 @@ function resolveValue(page, rawValue) {
|
|
|
126
176
|
}
|
|
127
177
|
continue;
|
|
128
178
|
}
|
|
179
|
+
// ✅ Local Storage
|
|
129
180
|
if (target.startsWith("set:localStorage:")) {
|
|
130
181
|
const key = target.split(":")[2];
|
|
131
182
|
await page.evaluate(({ k, v }) => localStorage.setItem(k, v), {
|
|
@@ -135,6 +186,7 @@ function resolveValue(page, rawValue) {
|
|
|
135
186
|
console.log(`📦 localStorage: Set "${key}"`);
|
|
136
187
|
continue;
|
|
137
188
|
}
|
|
189
|
+
// ✅ Explicit Waits
|
|
138
190
|
if (target === "wait") {
|
|
139
191
|
const time = parseInt(rawValue.replace("wait:", ""), 10);
|
|
140
192
|
if (!isNaN(time)) {
|
|
@@ -1,2 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Iterates through a provided Data Table to fill inputs, click elements, or perform assertions.
|
|
3
|
+
* This step is designed for bulk form interaction without writing repetitive "When I..." steps.
|
|
4
|
+
*
|
|
5
|
+
* ```gherkin
|
|
6
|
+
* When I fill the following "Login" test form data
|
|
7
|
+
* | #username | tomsmith |
|
|
8
|
+
* | #password | SuperSecretPassword! |
|
|
9
|
+
* | #login | click |
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @param formName - A descriptive name for the form being filled (used for logging only).
|
|
13
|
+
* @param tableData - A 2D array representing the data table rows (automatically passed by the runner).
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* **Supported Values in Column 2:**
|
|
17
|
+
* - `Any String`: Fills the input found by the selector in Column 1.
|
|
18
|
+
* - `"click"`: Clicks the element.
|
|
19
|
+
* - `"check"`: Checks a checkbox or radio button.
|
|
20
|
+
* - `"assert:visible"`: Asserts that the element is visible.
|
|
21
|
+
* - `"assert:text:EXPECTED"`: Asserts that the element contains the specific text.
|
|
22
|
+
*
|
|
23
|
+
* @throws {Error} If the Data Table is missing or invalid.
|
|
24
|
+
*/
|
|
25
|
+
export declare const FillTestFormData: void;
|
|
2
26
|
//# sourceMappingURL=formTable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formTable.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/formTable.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"formTable.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/formTable.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gBAAgB,MA8B5B,CAAC"}
|
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
exports.FillTestFormData = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const registry_1 = require("../../core/registry");
|
|
6
|
+
/**
|
|
7
|
+
* Iterates through a provided Data Table to fill inputs, click elements, or perform assertions.
|
|
8
|
+
* This step is designed for bulk form interaction without writing repetitive "When I..." steps.
|
|
9
|
+
*
|
|
10
|
+
* ```gherkin
|
|
11
|
+
* When I fill the following "Login" test form data
|
|
12
|
+
* | #username | tomsmith |
|
|
13
|
+
* | #password | SuperSecretPassword! |
|
|
14
|
+
* | #login | click |
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @param formName - A descriptive name for the form being filled (used for logging only).
|
|
18
|
+
* @param tableData - A 2D array representing the data table rows (automatically passed by the runner).
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* **Supported Values in Column 2:**
|
|
22
|
+
* - `Any String`: Fills the input found by the selector in Column 1.
|
|
23
|
+
* - `"click"`: Clicks the element.
|
|
24
|
+
* - `"check"`: Checks a checkbox or radio button.
|
|
25
|
+
* - `"assert:visible"`: Asserts that the element is visible.
|
|
26
|
+
* - `"assert:text:EXPECTED"`: Asserts that the element contains the specific text.
|
|
27
|
+
*
|
|
28
|
+
* @throws {Error} If the Data Table is missing or invalid.
|
|
29
|
+
*/
|
|
30
|
+
exports.FillTestFormData = (0, registry_1.Step)("I fill the following {string} test form data", async (page, formName, tableData) => {
|
|
7
31
|
console.log(`📝 Processing Form: ${formName}`);
|
|
8
|
-
// The runner passes the table data as the last argument
|
|
9
|
-
// tableData = [ ['#username', 'tomsmith'], ['#password', '...'] ]
|
|
10
32
|
// Guard clause: Ensure tableData exists to prevent crashes if user forgets the table
|
|
11
33
|
if (!tableData || !Array.isArray(tableData)) {
|
|
12
34
|
throw new Error(`❌ The step "I fill the following '${formName}' form data" requires a Data Table below it.`);
|