playwright-cucumber-ts-steps 1.1.7 → 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 +133 -0
- package/dist/backend/actions/click.d.ts.map +1 -0
- package/dist/backend/actions/click.js +248 -0
- package/dist/backend/actions/find.d.ts +244 -0
- package/dist/backend/actions/find.d.ts.map +1 -0
- package/dist/backend/actions/find.js +415 -0
- package/dist/backend/actions/form.d.ts +38 -0
- package/dist/backend/actions/form.d.ts.map +1 -0
- package/dist/backend/actions/form.js +237 -0
- 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 +54 -0
- package/dist/backend/actions/frames.d.ts.map +1 -0
- package/dist/backend/actions/frames.js +97 -0
- package/dist/backend/actions/index.d.ts +10 -0
- package/dist/backend/actions/index.d.ts.map +1 -1
- package/dist/backend/actions/index.js +10 -0
- package/dist/backend/actions/inputs.d.ts +140 -0
- package/dist/backend/actions/inputs.d.ts.map +1 -0
- package/dist/backend/actions/inputs.js +247 -0
- 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 +71 -0
- package/dist/backend/actions/keyboard.d.ts.map +1 -0
- package/dist/backend/actions/keyboard.js +98 -0
- package/dist/backend/actions/misc.d.ts +135 -0
- package/dist/backend/actions/misc.d.ts.map +1 -0
- package/dist/backend/actions/misc.js +208 -0
- package/dist/backend/actions/mobile.d.ts +75 -0
- package/dist/backend/actions/mobile.d.ts.map +1 -0
- package/dist/backend/actions/mobile.js +148 -0
- package/dist/backend/actions/mouse.d.ts +80 -0
- package/dist/backend/actions/mouse.d.ts.map +1 -0
- package/dist/backend/actions/mouse.js +150 -0
- 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 +61 -10
- package/dist/backend/actions/waits.d.ts +56 -0
- package/dist/backend/actions/waits.d.ts.map +1 -0
- package/dist/backend/actions/waits.js +83 -0
- 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/index.d.ts +1 -0
- package/dist/backend/api/index.d.ts.map +1 -1
- package/dist/backend/api/index.js +1 -0
- 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 +61 -0
- package/dist/backend/api/network.d.ts.map +1 -0
- package/dist/backend/api/network.js +177 -0
- 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 +48 -16
- 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 +166 -12
- 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/backend/utils/state.d.ts +18 -0
- package/dist/backend/utils/state.d.ts.map +1 -0
- package/dist/backend/utils/state.js +84 -0
- package/dist/core/registry.d.ts +14 -14
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/registry.js +13 -4
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +91 -38
- package/package.json +52 -12
|
@@ -1,2 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module DatabaseSteps
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Executes a raw SQL query against the configured database.
|
|
6
|
+
* The results are stored in the internal `dbState` for subsequent assertions.
|
|
7
|
+
* * @example
|
|
8
|
+
* ```gherkin
|
|
9
|
+
* When I run the database query "SELECT * FROM users WHERE email = 'test@example.com'"
|
|
10
|
+
* ```
|
|
11
|
+
* * @param query - The SQL query string to execute.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RunDbQuery: void;
|
|
14
|
+
/**
|
|
15
|
+
* Asserts that the last executed database query returned a specific number of records.
|
|
16
|
+
* * @example
|
|
17
|
+
* ```gherkin
|
|
18
|
+
* Then I expect the database to return 1 record
|
|
19
|
+
* ```
|
|
20
|
+
* * @param count - The expected number of rows in the result set.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ExpectDbRecordCount: void;
|
|
23
|
+
/**
|
|
24
|
+
* Asserts that the first record of the last database result set contains specific column values.
|
|
25
|
+
* Performs a loose equality check (converts values to strings) to handle type mismatches.
|
|
26
|
+
* * @example
|
|
27
|
+
* ```gherkin
|
|
28
|
+
* Then I expect the first database record to contain
|
|
29
|
+
* | username | admin |
|
|
30
|
+
* | is_active| 1 |
|
|
31
|
+
* | role | superuser |
|
|
32
|
+
* ```
|
|
33
|
+
* * @param tableData - A Gherkin Data Table containing column names (keys) and expected values.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ExpectFirstDbRecordToContain: void;
|
|
2
36
|
//# sourceMappingURL=steps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/backend/db/steps.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../../src/backend/db/steps.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,MAGrB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,MAW/B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,MAgCxC,CAAC"}
|
package/dist/backend/db/steps.js
CHANGED
|
@@ -1,43 +1,76 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpectFirstDbRecordToContain = exports.ExpectDbRecordCount = exports.RunDbQuery = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
3
5
|
const registry_1 = require("../../core/registry");
|
|
4
6
|
const state_1 = require("./state");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @module DatabaseSteps
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Executes a raw SQL query against the configured database.
|
|
12
|
+
* The results are stored in the internal `dbState` for subsequent assertions.
|
|
13
|
+
* * @example
|
|
14
|
+
* ```gherkin
|
|
15
|
+
* When I run the database query "SELECT * FROM users WHERE email = 'test@example.com'"
|
|
16
|
+
* ```
|
|
17
|
+
* * @param query - The SQL query string to execute.
|
|
18
|
+
*/
|
|
19
|
+
exports.RunDbQuery = (0, registry_1.Step)("I run the database query {string}", async (page, query) => {
|
|
8
20
|
await state_1.dbState.executeQuery(query);
|
|
21
|
+
console.log(`🗄️ Executed DB Query: ${query}`);
|
|
9
22
|
});
|
|
10
|
-
|
|
11
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Asserts that the last executed database query returned a specific number of records.
|
|
25
|
+
* * @example
|
|
26
|
+
* ```gherkin
|
|
27
|
+
* Then I expect the database to return 1 record
|
|
28
|
+
* ```
|
|
29
|
+
* * @param count - The expected number of rows in the result set.
|
|
30
|
+
*/
|
|
31
|
+
exports.ExpectDbRecordCount = (0, registry_1.Step)("I expect the database to return {int} record(s)", async (page, count) => {
|
|
12
32
|
const result = state_1.dbState.getLastResult();
|
|
13
33
|
if (Array.isArray(result)) {
|
|
14
34
|
(0, test_1.expect)(result.length).toBe(count);
|
|
35
|
+
console.log(`✅ Database returned exactly ${count} record(s).`);
|
|
15
36
|
}
|
|
16
37
|
else {
|
|
17
|
-
throw new Error(`Expected array result but got: ${typeof result}`);
|
|
38
|
+
throw new Error(`Expected array result from database but got: ${typeof result}`);
|
|
18
39
|
}
|
|
19
40
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Asserts that the first record of the last database result set contains specific column values.
|
|
43
|
+
* Performs a loose equality check (converts values to strings) to handle type mismatches.
|
|
44
|
+
* * @example
|
|
45
|
+
* ```gherkin
|
|
46
|
+
* Then I expect the first database record to contain
|
|
47
|
+
* | username | admin |
|
|
48
|
+
* | is_active| 1 |
|
|
49
|
+
* | role | superuser |
|
|
50
|
+
* ```
|
|
51
|
+
* * @param tableData - A Gherkin Data Table containing column names (keys) and expected values.
|
|
52
|
+
*/
|
|
53
|
+
exports.ExpectFirstDbRecordToContain = (0, registry_1.Step)("I expect the first database record to contain", async (page, tableData) => {
|
|
23
54
|
const result = state_1.dbState.getLastResult();
|
|
24
55
|
// Guard Clauses
|
|
25
56
|
if (!Array.isArray(result) || result.length === 0) {
|
|
26
|
-
throw new Error("Database returned no records to check.");
|
|
57
|
+
throw new Error("❌ Database returned no records to check.");
|
|
27
58
|
}
|
|
28
59
|
if (!tableData) {
|
|
29
|
-
throw new Error("This step requires a Data Table.");
|
|
60
|
+
throw new Error("❌ This step requires a Data Table.");
|
|
30
61
|
}
|
|
31
|
-
const firstRow = result[0];
|
|
32
|
-
// tableData is [ ["
|
|
62
|
+
const firstRow = result[0];
|
|
63
|
+
// tableData is [ ["column", "value"], ... ]
|
|
33
64
|
for (const row of tableData) {
|
|
34
65
|
const key = row[0];
|
|
35
66
|
const expectedValue = row[1];
|
|
36
67
|
// Check if the key exists in the DB result
|
|
37
68
|
if (!(key in firstRow)) {
|
|
38
|
-
throw new Error(
|
|
69
|
+
throw new Error(`❌ DB Record does not have column: "${key}"`);
|
|
39
70
|
}
|
|
40
71
|
// Loose equality check (DB might return int, Gherkin sends string)
|
|
41
|
-
|
|
72
|
+
const actualValue = String(firstRow[key]);
|
|
73
|
+
(0, test_1.expect)(actualValue).toBe(expectedValue);
|
|
42
74
|
}
|
|
75
|
+
console.log("✅ First DB record matches the expected data table.");
|
|
43
76
|
});
|
|
@@ -1,2 +1,36 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module DialogActions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Sets up a listener to automatically click "OK" or "Accept" on the very next browser dialog
|
|
6
|
+
* (alert, confirm, or prompt) that appears.
|
|
7
|
+
* * **Note:** This must be called *before* the action that triggers the dialog.
|
|
8
|
+
* * * @example
|
|
9
|
+
* ```gherkin
|
|
10
|
+
* Given I accept the next dialog
|
|
11
|
+
* When I click "#delete-button"
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare const AcceptNextDialog: void;
|
|
15
|
+
/**
|
|
16
|
+
* Sets up a listener to automatically click "Cancel" or "Dismiss" on the very next browser dialog.
|
|
17
|
+
* * **Note:** This must be called *before* the action that triggers the dialog.
|
|
18
|
+
* * * @example
|
|
19
|
+
* ```gherkin
|
|
20
|
+
* Given I dismiss the next dialog
|
|
21
|
+
* When I click "#reset-settings"
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const DismissNextDialog: void;
|
|
25
|
+
/**
|
|
26
|
+
* Sets up a listener to type a specific string into the next browser prompt and then accept it.
|
|
27
|
+
* * **Note:** This must be called *before* the action that triggers the prompt.
|
|
28
|
+
* * * @example
|
|
29
|
+
* ```gherkin
|
|
30
|
+
* Given I type "My New Folder" into the next prompt and accept
|
|
31
|
+
* When I click "button:has-text('Create')"
|
|
32
|
+
* ```
|
|
33
|
+
* * @param text - The string to be entered into the prompt input field.
|
|
34
|
+
*/
|
|
35
|
+
export declare const TypeAndAcceptPrompt: void;
|
|
2
36
|
//# sourceMappingURL=alerts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../../src/backend/elements/alerts.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../../src/backend/elements/alerts.ts"],"names":[],"mappings":"AAEA;;GAEG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,MAK3B,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,MAK5B,CAAC;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,MAQ/B,CAAC"}
|
|
@@ -1,21 +1,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeAndAcceptPrompt = exports.DismissNextDialog = exports.AcceptNextDialog = void 0;
|
|
3
4
|
const registry_1 = require("../../core/registry");
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @module DialogActions
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Sets up a listener to automatically click "OK" or "Accept" on the very next browser dialog
|
|
10
|
+
* (alert, confirm, or prompt) that appears.
|
|
11
|
+
* * **Note:** This must be called *before* the action that triggers the dialog.
|
|
12
|
+
* * * @example
|
|
13
|
+
* ```gherkin
|
|
14
|
+
* Given I accept the next dialog
|
|
15
|
+
* When I click "#delete-button"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
exports.AcceptNextDialog = (0, registry_1.Step)("I accept the next dialog", async (page) => {
|
|
6
19
|
page.once("dialog", async (dialog) => {
|
|
7
20
|
await dialog.accept();
|
|
21
|
+
console.log(`✅ Accepted dialog: [${dialog.type()}] "${dialog.message()}"`);
|
|
8
22
|
});
|
|
9
23
|
});
|
|
10
|
-
|
|
11
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Sets up a listener to automatically click "Cancel" or "Dismiss" on the very next browser dialog.
|
|
26
|
+
* * **Note:** This must be called *before* the action that triggers the dialog.
|
|
27
|
+
* * * @example
|
|
28
|
+
* ```gherkin
|
|
29
|
+
* Given I dismiss the next dialog
|
|
30
|
+
* When I click "#reset-settings"
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
exports.DismissNextDialog = (0, registry_1.Step)("I dismiss the next dialog", async (page) => {
|
|
12
34
|
page.once("dialog", async (dialog) => {
|
|
13
35
|
await dialog.dismiss();
|
|
36
|
+
console.log(`❌ Dismissed dialog: [${dialog.type()}] "${dialog.message()}"`);
|
|
14
37
|
});
|
|
15
38
|
});
|
|
16
|
-
|
|
17
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Sets up a listener to type a specific string into the next browser prompt and then accept it.
|
|
41
|
+
* * **Note:** This must be called *before* the action that triggers the prompt.
|
|
42
|
+
* * * @example
|
|
43
|
+
* ```gherkin
|
|
44
|
+
* Given I type "My New Folder" into the next prompt and accept
|
|
45
|
+
* When I click "button:has-text('Create')"
|
|
46
|
+
* ```
|
|
47
|
+
* * @param text - The string to be entered into the prompt input field.
|
|
48
|
+
*/
|
|
49
|
+
exports.TypeAndAcceptPrompt = (0, registry_1.Step)("I type {string} into the next prompt and accept", async (page, text) => {
|
|
18
50
|
page.once("dialog", async (dialog) => {
|
|
19
51
|
await dialog.accept(text);
|
|
52
|
+
console.log(`✍️ Typed "${text}" into prompt and accepted.`);
|
|
20
53
|
});
|
|
21
54
|
});
|
|
@@ -1,2 +1,45 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module FormActions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Selects an option from a `<select>` dropdown menu.
|
|
6
|
+
* It first attempts to match by the visible label; if that fails, it tries to match by the underlying `value` attribute.
|
|
7
|
+
* * @example
|
|
8
|
+
* ```gherkin
|
|
9
|
+
* When I select option "Canada" from "#country-selector"
|
|
10
|
+
* When I select option "CA" from "#country-selector"
|
|
11
|
+
* ```
|
|
12
|
+
* * @param option - The visible text (label) or the value attribute of the option.
|
|
13
|
+
* @param selector - The CSS or Playwright selector for the select element.
|
|
14
|
+
*/
|
|
15
|
+
export declare const SelectDropdownOption: void;
|
|
16
|
+
/**
|
|
17
|
+
* Checks a checkbox or radio button.
|
|
18
|
+
* * @example
|
|
19
|
+
* ```gherkin
|
|
20
|
+
* When I check "#terms-and-conditions"
|
|
21
|
+
* ```
|
|
22
|
+
* * @param selector - The selector for the checkbox or radio input.
|
|
23
|
+
*/
|
|
24
|
+
export declare const CheckInput: void;
|
|
25
|
+
/**
|
|
26
|
+
* Unchecks a checkbox.
|
|
27
|
+
* * @example
|
|
28
|
+
* ```gherkin
|
|
29
|
+
* When I uncheck "#subscribe-newsletter"
|
|
30
|
+
* ```
|
|
31
|
+
* * @param selector - The selector for the checkbox input.
|
|
32
|
+
*/
|
|
33
|
+
export declare const UncheckInput: void;
|
|
34
|
+
/**
|
|
35
|
+
* Uploads a file to an `<input type="file">` element.
|
|
36
|
+
* The file path is resolved relative to the current working directory of the project.
|
|
37
|
+
* * @example
|
|
38
|
+
* ```gherkin
|
|
39
|
+
* When I upload file "test-data/profile.jpg" to "#avatar-upload"
|
|
40
|
+
* ```
|
|
41
|
+
* * @param fileName - The relative path to the file from the project root.
|
|
42
|
+
* @param selector - The selector for the file input element.
|
|
43
|
+
*/
|
|
44
|
+
export declare const UploadFile: void;
|
|
2
45
|
//# sourceMappingURL=forms.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../../../src/backend/elements/forms.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"forms.d.ts","sourceRoot":"","sources":["../../../src/backend/elements/forms.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,MAShC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,MAGrB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,MAGvB,CAAC;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,MAOtB,CAAC"}
|
|
@@ -33,27 +33,66 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
|
|
36
|
+
exports.UploadFile = exports.UncheckInput = exports.CheckInput = exports.SelectDropdownOption = void 0;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const registry_1 = require("../../core/registry");
|
|
39
|
+
/**
|
|
40
|
+
* @module FormActions
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Selects an option from a `<select>` dropdown menu.
|
|
44
|
+
* It first attempts to match by the visible label; if that fails, it tries to match by the underlying `value` attribute.
|
|
45
|
+
* * @example
|
|
46
|
+
* ```gherkin
|
|
47
|
+
* When I select option "Canada" from "#country-selector"
|
|
48
|
+
* When I select option "CA" from "#country-selector"
|
|
49
|
+
* ```
|
|
50
|
+
* * @param option - The visible text (label) or the value attribute of the option.
|
|
51
|
+
* @param selector - The CSS or Playwright selector for the select element.
|
|
52
|
+
*/
|
|
53
|
+
exports.SelectDropdownOption = (0, registry_1.Step)("I select option {string} from {string}", async (page, option, selector) => {
|
|
40
54
|
await page.selectOption(selector, { label: option }).catch(() => {
|
|
41
55
|
// Fallback: try selecting by value if label fails
|
|
42
56
|
return page.selectOption(selector, { value: option });
|
|
43
57
|
});
|
|
58
|
+
console.log(`✅ Selected option "${option}" from "${selector}"`);
|
|
44
59
|
});
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Checks a checkbox or radio button.
|
|
62
|
+
* * @example
|
|
63
|
+
* ```gherkin
|
|
64
|
+
* When I check "#terms-and-conditions"
|
|
65
|
+
* ```
|
|
66
|
+
* * @param selector - The selector for the checkbox or radio input.
|
|
67
|
+
*/
|
|
68
|
+
exports.CheckInput = (0, registry_1.Step)("I check {string}", async (page, selector) => {
|
|
47
69
|
await page.check(selector);
|
|
70
|
+
console.log(`✅ Checked "${selector}"`);
|
|
48
71
|
});
|
|
49
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Unchecks a checkbox.
|
|
74
|
+
* * @example
|
|
75
|
+
* ```gherkin
|
|
76
|
+
* When I uncheck "#subscribe-newsletter"
|
|
77
|
+
* ```
|
|
78
|
+
* * @param selector - The selector for the checkbox input.
|
|
79
|
+
*/
|
|
80
|
+
exports.UncheckInput = (0, registry_1.Step)("I uncheck {string}", async (page, selector) => {
|
|
50
81
|
await page.uncheck(selector);
|
|
82
|
+
console.log(`✅ Unchecked "${selector}"`);
|
|
51
83
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Uploads a file to an `<input type="file">` element.
|
|
86
|
+
* The file path is resolved relative to the current working directory of the project.
|
|
87
|
+
* * @example
|
|
88
|
+
* ```gherkin
|
|
89
|
+
* When I upload file "test-data/profile.jpg" to "#avatar-upload"
|
|
90
|
+
* ```
|
|
91
|
+
* * @param fileName - The relative path to the file from the project root.
|
|
92
|
+
* @param selector - The selector for the file input element.
|
|
93
|
+
*/
|
|
94
|
+
exports.UploadFile = (0, registry_1.Step)("I upload file {string} to {string}", async (page, fileName, selector) => {
|
|
57
95
|
const filePath = path.resolve(process.cwd(), fileName);
|
|
58
96
|
await page.setInputFiles(selector, filePath);
|
|
97
|
+
console.log(`📁 Uploaded file "${fileName}" to "${selector}"`);
|
|
59
98
|
});
|
|
@@ -1,2 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module FrameActions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Clicks an element located inside a specific `<iframe>`.
|
|
6
|
+
* * @example
|
|
7
|
+
* ```gherkin
|
|
8
|
+
* When I click "button#submit" inside frame "#payment-iframe"
|
|
9
|
+
* ```
|
|
10
|
+
* * @param elementSelector - The CSS/Playwright selector for the element to click.
|
|
11
|
+
* @param frameSelector - The selector for the iframe element itself.
|
|
12
|
+
*/
|
|
13
|
+
export declare const ClickInsideFrame: void;
|
|
14
|
+
/**
|
|
15
|
+
* Fills an input field located inside a specific `<iframe>`.
|
|
16
|
+
* * @example
|
|
17
|
+
* ```gherkin
|
|
18
|
+
* When I fill "input[name='card-number']" inside frame "#checkout-frame" with "42424242"
|
|
19
|
+
* ```
|
|
20
|
+
* * @param elementSelector - The selector for the input field inside the frame.
|
|
21
|
+
* @param frameSelector - The selector for the iframe.
|
|
22
|
+
* @param value - The text to type into the input.
|
|
23
|
+
*/
|
|
24
|
+
export declare const FillInsideFrame: void;
|
|
25
|
+
/**
|
|
26
|
+
* Asserts that an element inside a specific `<iframe>` contains the expected text.
|
|
27
|
+
* Uses Playwright's web-first assertions for automatic retries.
|
|
28
|
+
* * @example
|
|
29
|
+
* ```gherkin
|
|
30
|
+
* Then I expect ".success-msg" inside frame "#upload-frame" to have text "Upload Complete"
|
|
31
|
+
* ```
|
|
32
|
+
* * @param elementSelector - The selector for the element inside the frame.
|
|
33
|
+
* @param frameSelector - The selector for the iframe.
|
|
34
|
+
* @param text - The text expected to be found.
|
|
35
|
+
*/
|
|
36
|
+
export declare const ExpectTextInsideFrame: void;
|
|
2
37
|
//# sourceMappingURL=frames.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../../src/backend/elements/frames.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../../src/backend/elements/frames.ts"],"names":[],"mappings":"AAGA;;GAEG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,MAO5B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,MAO3B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,MAUjC,CAAC"}
|
|
@@ -1,25 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpectTextInsideFrame = exports.FillInsideFrame = exports.ClickInsideFrame = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
3
5
|
const registry_1 = require("../../core/registry");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @module FrameActions
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Clicks an element located inside a specific `<iframe>`.
|
|
11
|
+
* * @example
|
|
12
|
+
* ```gherkin
|
|
13
|
+
* When I click "button#submit" inside frame "#payment-iframe"
|
|
14
|
+
* ```
|
|
15
|
+
* * @param elementSelector - The CSS/Playwright selector for the element to click.
|
|
16
|
+
* @param frameSelector - The selector for the iframe element itself.
|
|
17
|
+
*/
|
|
18
|
+
exports.ClickInsideFrame = (0, registry_1.Step)("I click {string} inside frame {string}", async (page, elementSelector, frameSelector) => {
|
|
6
19
|
const frame = page.frameLocator(frameSelector);
|
|
7
20
|
await frame.locator(elementSelector).click();
|
|
21
|
+
console.log(`🖼️ Clicked "${elementSelector}" inside frame "${frameSelector}".`);
|
|
8
22
|
});
|
|
9
|
-
|
|
10
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Fills an input field located inside a specific `<iframe>`.
|
|
25
|
+
* * @example
|
|
26
|
+
* ```gherkin
|
|
27
|
+
* When I fill "input[name='card-number']" inside frame "#checkout-frame" with "42424242"
|
|
28
|
+
* ```
|
|
29
|
+
* * @param elementSelector - The selector for the input field inside the frame.
|
|
30
|
+
* @param frameSelector - The selector for the iframe.
|
|
31
|
+
* @param value - The text to type into the input.
|
|
32
|
+
*/
|
|
33
|
+
exports.FillInsideFrame = (0, registry_1.Step)("I fill {string} inside frame {string} with {string}", async (page, elementSelector, frameSelector, value) => {
|
|
11
34
|
const frame = page.frameLocator(frameSelector);
|
|
12
35
|
await frame.locator(elementSelector).fill(value);
|
|
36
|
+
console.log(`🖼️ Filled "${elementSelector}" inside frame "${frameSelector}" with value.`);
|
|
13
37
|
});
|
|
14
|
-
|
|
15
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Asserts that an element inside a specific `<iframe>` contains the expected text.
|
|
40
|
+
* Uses Playwright's web-first assertions for automatic retries.
|
|
41
|
+
* * @example
|
|
42
|
+
* ```gherkin
|
|
43
|
+
* Then I expect ".success-msg" inside frame "#upload-frame" to have text "Upload Complete"
|
|
44
|
+
* ```
|
|
45
|
+
* * @param elementSelector - The selector for the element inside the frame.
|
|
46
|
+
* @param frameSelector - The selector for the iframe.
|
|
47
|
+
* @param text - The text expected to be found.
|
|
48
|
+
*/
|
|
49
|
+
exports.ExpectTextInsideFrame = (0, registry_1.Step)("I expect {string} inside frame {string} to have text {string}", async (page, elementSelector, frameSelector, text) => {
|
|
16
50
|
const frame = page.frameLocator(frameSelector);
|
|
17
51
|
const locator = frame.locator(elementSelector);
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const actualText = await locator.textContent();
|
|
22
|
-
if (!actualText?.includes(text)) {
|
|
23
|
-
throw new Error(`Expected text "${text}" but found "${actualText}" in frame`);
|
|
24
|
-
}
|
|
52
|
+
// Using Playwright expect for robust retries
|
|
53
|
+
await (0, test_1.expect)(locator).toContainText(text);
|
|
54
|
+
console.log(`✅ Frame "${frameSelector}" element "${elementSelector}" contains "${text}".`);
|
|
25
55
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Page, Locator } from "@playwright/test";
|
|
2
|
+
export declare function setActiveElement(page: Page, element: Locator): void;
|
|
3
|
+
export declare function getActiveElement(page: Page): Locator;
|
|
4
|
+
export declare function setActiveElements(page: Page, elements: Locator): void;
|
|
5
|
+
export declare function getActiveElements(page: Page): Locator;
|
|
6
|
+
export declare function setVariable(page: Page, key: string, value: any): void;
|
|
7
|
+
export declare function getVariable(page: Page, key: string): any;
|
|
8
|
+
export declare function parseClickOptions(table: any): {
|
|
9
|
+
force?: boolean;
|
|
10
|
+
button?: "left" | "right" | "middle";
|
|
11
|
+
modifiers?: Array<"Alt" | "Control" | "Meta" | "Shift">;
|
|
12
|
+
position?: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
};
|
|
16
|
+
timeout?: number;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/backend/utils/state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAKjD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,QAE5D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAQpD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,QAE9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAMrD;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,QAK9D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAGxD;AAKD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,GAAG,GAAG;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACrC,SAAS,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACxD,QAAQ,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAwCA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setActiveElement = setActiveElement;
|
|
4
|
+
exports.getActiveElement = getActiveElement;
|
|
5
|
+
exports.setActiveElements = setActiveElements;
|
|
6
|
+
exports.getActiveElements = getActiveElements;
|
|
7
|
+
exports.setVariable = setVariable;
|
|
8
|
+
exports.getVariable = getVariable;
|
|
9
|
+
exports.parseClickOptions = parseClickOptions;
|
|
10
|
+
// 1. STATE MANAGEMENT
|
|
11
|
+
// We attach data to the Playwright Page object so it persists between steps.
|
|
12
|
+
function setActiveElement(page, element) {
|
|
13
|
+
page.__bdd_element = element;
|
|
14
|
+
}
|
|
15
|
+
function getActiveElement(page) {
|
|
16
|
+
const el = page.__bdd_element;
|
|
17
|
+
if (!el) {
|
|
18
|
+
throw new Error("❌ No stored element found. Did you forget a 'When I find...' step?");
|
|
19
|
+
}
|
|
20
|
+
return el;
|
|
21
|
+
}
|
|
22
|
+
function setActiveElements(page, elements) {
|
|
23
|
+
page.__bdd_elements = elements;
|
|
24
|
+
}
|
|
25
|
+
function getActiveElements(page) {
|
|
26
|
+
const els = page.__bdd_elements;
|
|
27
|
+
if (!els) {
|
|
28
|
+
throw new Error("❌ No stored elements list found.");
|
|
29
|
+
}
|
|
30
|
+
return els;
|
|
31
|
+
}
|
|
32
|
+
// 2. DATA / ALIAS MANAGEMENT (for @variable support)
|
|
33
|
+
function setVariable(page, key, value) {
|
|
34
|
+
if (!page.__bdd_data) {
|
|
35
|
+
page.__bdd_data = {};
|
|
36
|
+
}
|
|
37
|
+
page.__bdd_data[key] = value;
|
|
38
|
+
}
|
|
39
|
+
function getVariable(page, key) {
|
|
40
|
+
const data = page.__bdd_data;
|
|
41
|
+
return data ? data[key] : undefined;
|
|
42
|
+
}
|
|
43
|
+
// 3. OPTION PARSERS
|
|
44
|
+
// Converts Gherkin DataTables into Playwright ClickOptions
|
|
45
|
+
function parseClickOptions(table) {
|
|
46
|
+
if (!table)
|
|
47
|
+
return {};
|
|
48
|
+
let hash = {};
|
|
49
|
+
// Handle Cucumber DataTable object (legacy) or raw Array
|
|
50
|
+
if (typeof table.rowsHash === "function") {
|
|
51
|
+
hash = table.rowsHash();
|
|
52
|
+
}
|
|
53
|
+
else if (Array.isArray(table)) {
|
|
54
|
+
// Convert Array of Arrays [['force', 'true']] to Object { force: 'true' }
|
|
55
|
+
table.forEach((row) => {
|
|
56
|
+
if (Array.isArray(row) && row.length >= 2) {
|
|
57
|
+
hash[row[0].toString()] = row[1].toString();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
const options = {};
|
|
65
|
+
// Parse specific boolean/number values
|
|
66
|
+
if (hash["force"] === "true")
|
|
67
|
+
options.force = true;
|
|
68
|
+
if (hash["button"])
|
|
69
|
+
options.button = hash["button"];
|
|
70
|
+
if (hash["timeout"])
|
|
71
|
+
options.timeout = parseInt(hash["timeout"], 10);
|
|
72
|
+
// Handle modifiers (comma separated)
|
|
73
|
+
if (hash["modifiers"]) {
|
|
74
|
+
options.modifiers = hash["modifiers"].split(",").map((m) => m.trim());
|
|
75
|
+
}
|
|
76
|
+
// Handle position (x,y)
|
|
77
|
+
if (hash["x"] && hash["y"]) {
|
|
78
|
+
options.position = {
|
|
79
|
+
x: parseInt(hash["x"], 10),
|
|
80
|
+
y: parseInt(hash["y"], 10),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return options;
|
|
84
|
+
}
|
package/dist/core/registry.d.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { CucumberExpression } from "@cucumber/cucumber-expressions";
|
|
2
2
|
import { Page } from "@playwright/test";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @param fn - The async function to execute. It receives the Playwright Page object as the first argument.
|
|
7
|
-
* * @example
|
|
8
|
-
* ```ts
|
|
9
|
-
* Step('I scroll to bottom', async (page) => {
|
|
10
|
-
* await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
11
|
-
* });
|
|
12
|
-
* ```
|
|
4
|
+
* Define the type of function for our steps.
|
|
5
|
+
* Every step automatically gets 'page' as the first argument.
|
|
13
6
|
*/
|
|
14
7
|
export type StepAction = (page: Page, ...args: any[]) => Promise<void>;
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
/**
|
|
9
|
+
* 1. StepDefinition Interface
|
|
10
|
+
* Updated to allow both CucumberExpression (legacy) AND RegExp (standard)
|
|
11
|
+
*/
|
|
12
|
+
export interface StepDefinition {
|
|
13
|
+
expression: CucumberExpression | RegExp;
|
|
17
14
|
fn: StepAction;
|
|
18
|
-
pattern: string;
|
|
15
|
+
pattern: string | RegExp;
|
|
19
16
|
}
|
|
20
17
|
export declare const stepRegistry: StepDefinition[];
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
/**
|
|
19
|
+
* 3. The Function to Register Steps
|
|
20
|
+
* Supports passing a string (converted to CucumberExpression) OR a direct RegExp.
|
|
21
|
+
*/
|
|
22
|
+
export declare function Step(pattern: string | RegExp, fn: StepAction): void;
|
|
23
23
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAEnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAEnB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvE;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAAC;IACxC,EAAE,EAAE,UAAU,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAGD,eAAO,MAAM,YAAY,EAAE,cAAc,EAAO,CAAC;AAIjD;;;GAGG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,EAAE,UAAU,QAgB5D"}
|