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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WaitForUrlContain = exports.WaitForElementHidden = exports.WaitForElementVisible = exports.WaitForLoadState = exports.WaitForNetworkIdle = void 0;
|
|
4
|
+
const registry_1 = require("../../core/registry");
|
|
5
|
+
const state_1 = require("../utils/state");
|
|
6
|
+
// =============================
|
|
7
|
+
// WAIT STRATEGIES
|
|
8
|
+
// =============================
|
|
9
|
+
/**
|
|
10
|
+
* Waits for the network to reach an "idle" state.
|
|
11
|
+
* In Playwright terms, this means there are no new network connections for at least 500ms.
|
|
12
|
+
*
|
|
13
|
+
* ```gherkin
|
|
14
|
+
* When I wait for network idle
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* **Warning:** This can be flaky on pages that have constant background polling (e.g., real-time chats, analytics).
|
|
19
|
+
* If the test times out here, consider using `I wait for element to be visible` instead.
|
|
20
|
+
*/
|
|
21
|
+
exports.WaitForNetworkIdle = (0, registry_1.Step)("I wait for network idle", async (page) => {
|
|
22
|
+
await page.waitForLoadState("networkidle");
|
|
23
|
+
console.log("⏳ Network is idle");
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Waits for the page to reach a specific load lifecycle event.
|
|
27
|
+
*
|
|
28
|
+
* ```gherkin
|
|
29
|
+
* When I wait for load state "domcontentloaded"
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @param state - The state to wait for. Options:
|
|
33
|
+
* - `"load"`: Window load event fired.
|
|
34
|
+
* - `"domcontentloaded"`: DOM is ready (scripts might still be loading).
|
|
35
|
+
* - `"networkidle"`: No network connections for 500ms.
|
|
36
|
+
*/
|
|
37
|
+
exports.WaitForLoadState = (0, registry_1.Step)("I wait for load state {string}", async (page, state) => {
|
|
38
|
+
if (!["load", "domcontentloaded", "networkidle"].includes(state)) {
|
|
39
|
+
throw new Error(`❌ Invalid load state: "${state}". Use load, domcontentloaded, or networkidle.`);
|
|
40
|
+
}
|
|
41
|
+
await page.waitForLoadState(state);
|
|
42
|
+
console.log(`⏳ Reached load state: "${state}"`);
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Explicitly waits for the currently stored (active) element to become visible.
|
|
46
|
+
* Useful for ensuring animations complete or modals appear before proceeding.
|
|
47
|
+
*
|
|
48
|
+
* ```gherkin
|
|
49
|
+
* When I wait for element to be visible
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
exports.WaitForElementVisible = (0, registry_1.Step)("I wait for element to be visible", async (page) => {
|
|
53
|
+
const element = (0, state_1.getActiveElement)(page);
|
|
54
|
+
await element.waitFor({ state: "visible" });
|
|
55
|
+
console.log("⏳ Element is now visible");
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Explicitly waits for the currently stored (active) element to become hidden or detached from the DOM.
|
|
59
|
+
* Useful for verifying that loading spinners have disappeared.
|
|
60
|
+
*
|
|
61
|
+
* ```gherkin
|
|
62
|
+
* When I wait for element to be hidden
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
exports.WaitForElementHidden = (0, registry_1.Step)("I wait for element to be hidden", async (page) => {
|
|
66
|
+
const element = (0, state_1.getActiveElement)(page);
|
|
67
|
+
await element.waitFor({ state: "hidden" });
|
|
68
|
+
console.log("⏳ Element is now hidden");
|
|
69
|
+
});
|
|
70
|
+
/**
|
|
71
|
+
* Waits until the page URL contains the specified substring (Regex match).
|
|
72
|
+
* Useful for verifying redirects (e.g., after login).
|
|
73
|
+
*
|
|
74
|
+
* ```gherkin
|
|
75
|
+
* When I wait for URL to contain "dashboard"
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @param urlPart - The substring to look for in the current URL.
|
|
79
|
+
*/
|
|
80
|
+
exports.WaitForUrlContain = (0, registry_1.Step)("I wait for URL to contain {string}", async (page, urlPart) => {
|
|
81
|
+
await page.waitForURL(new RegExp(urlPart));
|
|
82
|
+
console.log(`⏳ URL now contains: "${urlPart}"`);
|
|
83
|
+
});
|
|
@@ -1,2 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Asserts that the HTTP status code of the last API response matches the expected integer.
|
|
3
|
+
*
|
|
4
|
+
* ```gherkin
|
|
5
|
+
* Then I expect the response status to be 200
|
|
6
|
+
* ```
|
|
7
|
+
*
|
|
8
|
+
* @param statusCode - The expected HTTP status code (e.g., 200, 404, 500).
|
|
9
|
+
*/
|
|
10
|
+
export declare const ExpectResponseStatus: void;
|
|
11
|
+
/**
|
|
12
|
+
* Asserts that the body text of the last API response contains a specific substring.
|
|
13
|
+
*
|
|
14
|
+
* ```gherkin
|
|
15
|
+
* Then I expect the response body to contain "success"
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @param text - The text substring to look for in the response body.
|
|
19
|
+
*/
|
|
20
|
+
export declare const ExpectResponseBodyContain: void;
|
|
21
|
+
/**
|
|
22
|
+
* Asserts that a specific property in the JSON response matches a string value.
|
|
23
|
+
* Supports dot notation for nested properties.
|
|
24
|
+
*
|
|
25
|
+
* ```gherkin
|
|
26
|
+
* Then I expect the response property "user.id" to be "12345"
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @param jsonPath - The dot-notation path to the JSON property (e.g., "data.user.name").
|
|
30
|
+
* @param value - The expected string value of the property.
|
|
31
|
+
*/
|
|
32
|
+
export declare const ExpectResponseProperty: void;
|
|
2
33
|
//# sourceMappingURL=assertions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../../../src/backend/api/assertions.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../../../src/backend/api/assertions.ts"],"names":[],"mappings":"AAQA;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,MAMhC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,MAOrC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,MAWlC,CAAC"}
|
|
@@ -1,26 +1,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpectResponseProperty = exports.ExpectResponseBodyContain = exports.ExpectResponseStatus = void 0;
|
|
3
4
|
const test_1 = require("@playwright/test");
|
|
4
5
|
const registry_1 = require("../../core/registry");
|
|
5
6
|
const state_1 = require("./state");
|
|
6
|
-
//
|
|
7
|
-
|
|
7
|
+
// =============================
|
|
8
|
+
// API ASSERTIONS
|
|
9
|
+
// =============================
|
|
10
|
+
/**
|
|
11
|
+
* Asserts that the HTTP status code of the last API response matches the expected integer.
|
|
12
|
+
*
|
|
13
|
+
* ```gherkin
|
|
14
|
+
* Then I expect the response status to be 200
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @param statusCode - The expected HTTP status code (e.g., 200, 404, 500).
|
|
18
|
+
*/
|
|
19
|
+
exports.ExpectResponseStatus = (0, registry_1.Step)("I expect the response status to be {int}", async (page, statusCode) => {
|
|
8
20
|
const response = state_1.apiState.getResponse();
|
|
9
21
|
(0, test_1.expect)(response.status()).toBe(statusCode);
|
|
10
22
|
});
|
|
11
|
-
|
|
12
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Asserts that the body text of the last API response contains a specific substring.
|
|
25
|
+
*
|
|
26
|
+
* ```gherkin
|
|
27
|
+
* Then I expect the response body to contain "success"
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @param text - The text substring to look for in the response body.
|
|
31
|
+
*/
|
|
32
|
+
exports.ExpectResponseBodyContain = (0, registry_1.Step)("I expect the response body to contain {string}", async (page, text) => {
|
|
13
33
|
const response = state_1.apiState.getResponse();
|
|
14
34
|
const body = await response.text();
|
|
15
35
|
(0, test_1.expect)(body).toContain(text);
|
|
16
36
|
});
|
|
17
|
-
|
|
18
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Asserts that a specific property in the JSON response matches a string value.
|
|
39
|
+
* Supports dot notation for nested properties.
|
|
40
|
+
*
|
|
41
|
+
* ```gherkin
|
|
42
|
+
* Then I expect the response property "user.id" to be "12345"
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @param jsonPath - The dot-notation path to the JSON property (e.g., "data.user.name").
|
|
46
|
+
* @param value - The expected string value of the property.
|
|
47
|
+
*/
|
|
48
|
+
exports.ExpectResponseProperty = (0, registry_1.Step)("I expect the response property {string} to be {string}", async (page, jsonPath, value) => {
|
|
19
49
|
const response = state_1.apiState.getResponse();
|
|
20
50
|
const json = await response.json();
|
|
21
51
|
// FIX: Added ': string' to the 'i' parameter
|
|
22
|
-
const actualValue = jsonPath
|
|
23
|
-
.split(".")
|
|
24
|
-
.reduce((o, i) => o[i], json);
|
|
52
|
+
const actualValue = jsonPath.split(".").reduce((o, i) => o[i], json);
|
|
25
53
|
(0, test_1.expect)(String(actualValue)).toBe(value);
|
|
26
54
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/backend/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,CAAC;AACpB,OAAO,cAAc,CAAC;AACtB,OAAO,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/backend/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,CAAC;AACpB,OAAO,cAAc,CAAC;AACtB,OAAO,QAAQ,CAAC;AAChB,OAAO,WAAW,CAAC"}
|
|
@@ -1,2 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module NetworkMocking
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Mocks a specific API endpoint with a hardcoded inline JSON response body.
|
|
6
|
+
* * @example
|
|
7
|
+
* ```gherkin
|
|
8
|
+
* Given I mock the API endpoint "/api/users" with body '{"id": 1, "name": "Fake"}'
|
|
9
|
+
* ```
|
|
10
|
+
* * @param urlPattern - The URL or glob pattern to intercept.
|
|
11
|
+
* @param jsonBody - The raw JSON string to return as the response.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MockApiWithInlineJson: void;
|
|
14
|
+
/**
|
|
15
|
+
* Mocks an API endpoint using the contents of a local JSON file.
|
|
16
|
+
* * @example
|
|
17
|
+
* ```gherkin
|
|
18
|
+
* Given I mock the API endpoint "/api/users" with response from "mocks/users.json"
|
|
19
|
+
* ```
|
|
20
|
+
* * @param urlPattern - The URL pattern to intercept.
|
|
21
|
+
* @param filePath - Path to the JSON file relative to the project root.
|
|
22
|
+
*/
|
|
23
|
+
export declare const MockApiWithFile: void;
|
|
24
|
+
/**
|
|
25
|
+
* Mocks an API endpoint to return a specific HTTP status code only.
|
|
26
|
+
* Useful for simulating server errors like 500 or 404.
|
|
27
|
+
* * @example
|
|
28
|
+
* ```gherkin
|
|
29
|
+
* Given I mock the API endpoint "/api/broken" with status 500
|
|
30
|
+
* ```
|
|
31
|
+
* * @param urlPattern - The URL pattern to intercept.
|
|
32
|
+
* @param statusCode - The HTTP status code to return.
|
|
33
|
+
*/
|
|
34
|
+
export declare const MockApiStatus: void;
|
|
2
35
|
//# sourceMappingURL=mock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../../src/backend/api/mock.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../../src/backend/api/mock.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,MAajC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,MAoB3B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,MAQzB,CAAC"}
|
package/dist/backend/api/mock.js
CHANGED
|
@@ -33,12 +33,23 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
|
|
36
|
+
exports.MockApiStatus = exports.MockApiWithFile = exports.MockApiWithInlineJson = void 0;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const registry_1 = require("../../core/registry");
|
|
40
|
+
/**
|
|
41
|
+
* @module NetworkMocking
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Mocks a specific API endpoint with a hardcoded inline JSON response body.
|
|
45
|
+
* * @example
|
|
46
|
+
* ```gherkin
|
|
47
|
+
* Given I mock the API endpoint "/api/users" with body '{"id": 1, "name": "Fake"}'
|
|
48
|
+
* ```
|
|
49
|
+
* * @param urlPattern - The URL or glob pattern to intercept.
|
|
50
|
+
* @param jsonBody - The raw JSON string to return as the response.
|
|
51
|
+
*/
|
|
52
|
+
exports.MockApiWithInlineJson = (0, registry_1.Step)("I mock the API endpoint {string} with body {string}", async (page, urlPattern, jsonBody) => {
|
|
42
53
|
await page.route(urlPattern, async (route) => {
|
|
43
54
|
const json = JSON.parse(jsonBody);
|
|
44
55
|
await route.fulfill({
|
|
@@ -49,9 +60,16 @@ const path = __importStar(require("path"));
|
|
|
49
60
|
});
|
|
50
61
|
console.log(`🎭 Mocked ${urlPattern} with inline JSON`);
|
|
51
62
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Mocks an API endpoint using the contents of a local JSON file.
|
|
65
|
+
* * @example
|
|
66
|
+
* ```gherkin
|
|
67
|
+
* Given I mock the API endpoint "/api/users" with response from "mocks/users.json"
|
|
68
|
+
* ```
|
|
69
|
+
* * @param urlPattern - The URL pattern to intercept.
|
|
70
|
+
* @param filePath - Path to the JSON file relative to the project root.
|
|
71
|
+
*/
|
|
72
|
+
exports.MockApiWithFile = (0, registry_1.Step)("I mock the API endpoint {string} with response from {string}", async (page, urlPattern, filePath) => {
|
|
55
73
|
const fullPath = path.resolve(process.cwd(), filePath);
|
|
56
74
|
if (!fs.existsSync(fullPath)) {
|
|
57
75
|
throw new Error(`❌ Mock file not found at: ${fullPath}`);
|
|
@@ -66,10 +84,19 @@ const path = __importStar(require("path"));
|
|
|
66
84
|
});
|
|
67
85
|
console.log(`🎭 Mocked ${urlPattern} with file: ${filePath}`);
|
|
68
86
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Mocks an API endpoint to return a specific HTTP status code only.
|
|
89
|
+
* Useful for simulating server errors like 500 or 404.
|
|
90
|
+
* * @example
|
|
91
|
+
* ```gherkin
|
|
92
|
+
* Given I mock the API endpoint "/api/broken" with status 500
|
|
93
|
+
* ```
|
|
94
|
+
* * @param urlPattern - The URL pattern to intercept.
|
|
95
|
+
* @param statusCode - The HTTP status code to return.
|
|
96
|
+
*/
|
|
97
|
+
exports.MockApiStatus = (0, registry_1.Step)("I mock the API endpoint {string} with status {int}", async (page, urlPattern, statusCode) => {
|
|
72
98
|
await page.route(urlPattern, async (route) => {
|
|
73
99
|
await route.fulfill({ status: statusCode });
|
|
74
100
|
});
|
|
101
|
+
console.log(`🎭 Mocked ${urlPattern} with status ${statusCode}`);
|
|
75
102
|
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intercepts a network URL and returns a stubbed JSON response.
|
|
3
|
+
* Supports Gherkin DocStrings for the body content.
|
|
4
|
+
* * @example
|
|
5
|
+
* ```gherkin
|
|
6
|
+
* When I intercept URL "/api/user" and stub body:
|
|
7
|
+
* """
|
|
8
|
+
* { "id": 101, "status": "active" }
|
|
9
|
+
* """
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare const InterceptStubJson: void;
|
|
13
|
+
/**
|
|
14
|
+
* Intercepts a URL and stubs it with a raw string (non-JSON).
|
|
15
|
+
* * @example
|
|
16
|
+
* ```gherkin
|
|
17
|
+
* When I intercept URL "/health" and stub body "OK"
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const InterceptStubRaw: void;
|
|
21
|
+
/**
|
|
22
|
+
* Intercepts a URL but allows it to continue (Network Spying).
|
|
23
|
+
* Useful for monitoring traffic without changing the response.
|
|
24
|
+
* * @example
|
|
25
|
+
* ```gherkin
|
|
26
|
+
* When I intercept URL "/api/*"
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare const InterceptSpy: void;
|
|
30
|
+
/**
|
|
31
|
+
* Makes a GET request and stores the response in the test state.
|
|
32
|
+
* Stores values in `lastResponse` and `lastStatusCode`.
|
|
33
|
+
* * @example
|
|
34
|
+
* ```gherkin
|
|
35
|
+
* When I make request to "[https://api.example.com/v1/users](https://api.example.com/v1/users)"
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare const ApiGetRequest: void;
|
|
39
|
+
/**
|
|
40
|
+
* Makes a POST request with a JSON body provided via DocString.
|
|
41
|
+
* * @example
|
|
42
|
+
* ```gherkin
|
|
43
|
+
* When I make a POST request to "/api/login" with JSON body:
|
|
44
|
+
* """
|
|
45
|
+
* { "username": "admin", "password": "password123" }
|
|
46
|
+
* """
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare const ApiPostRequest: void;
|
|
50
|
+
/**
|
|
51
|
+
* Makes a generic HTTP request using the browser's `fetch` API.
|
|
52
|
+
* Supports a data table for headers and an optional body.
|
|
53
|
+
* * @example
|
|
54
|
+
* ```gherkin
|
|
55
|
+
* When I make a "PUT" request to "/api/settings"
|
|
56
|
+
* | Authorization | Bearer my-token |
|
|
57
|
+
* | body | {"theme": "dark"} |
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare const BrowserFetchRequest: void;
|
|
61
|
+
//# sourceMappingURL=network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../src/backend/api/network.ts"],"names":[],"mappings":"AAkCA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,MAe7B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,MAY5B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,MAKvB,CAAC;AAMH;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,MAexB,CAAC;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,MAoB1B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,MA+C/B,CAAC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BrowserFetchRequest = exports.ApiPostRequest = exports.ApiGetRequest = exports.InterceptSpy = exports.InterceptStubRaw = exports.InterceptStubJson = void 0;
|
|
4
|
+
const registry_1 = require("../../core/registry");
|
|
5
|
+
const state_1 = require("../utils/state");
|
|
6
|
+
/**
|
|
7
|
+
* Helper: Safely parse JSON even if it comes with DocString quotes or is undefined.
|
|
8
|
+
* Used internally by API steps to process Gherkin DocStrings.
|
|
9
|
+
*/
|
|
10
|
+
function safeJsonParse(input, context) {
|
|
11
|
+
if (!input) {
|
|
12
|
+
throw new Error(`❌ Missing JSON input for ${context}. Did you forget the DocString?`);
|
|
13
|
+
}
|
|
14
|
+
let text = typeof input === "string" ? input : JSON.stringify(input);
|
|
15
|
+
// Clean up DocString artifacts
|
|
16
|
+
text = text.replace(/^"""/g, "").replace(/"""$/g, "");
|
|
17
|
+
text = text.trim();
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(text);
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
throw new Error(`❌ Invalid JSON for ${context}.\nReceived: ${text.slice(0, 50)}...\nError: ${e.message}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// =============================
|
|
26
|
+
// 1. INTERCEPTION / MOCKING
|
|
27
|
+
// =============================
|
|
28
|
+
/**
|
|
29
|
+
* Intercepts a network URL and returns a stubbed JSON response.
|
|
30
|
+
* Supports Gherkin DocStrings for the body content.
|
|
31
|
+
* * @example
|
|
32
|
+
* ```gherkin
|
|
33
|
+
* When I intercept URL "/api/user" and stub body:
|
|
34
|
+
* """
|
|
35
|
+
* { "id": 101, "status": "active" }
|
|
36
|
+
* """
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
exports.InterceptStubJson = (0, registry_1.Step)(/^I intercept URL "([^"]+)" and stub body:?$/, async (page, url, body) => {
|
|
40
|
+
const parsedBody = safeJsonParse(body, `stubbing "${url}"`);
|
|
41
|
+
await page.route(url, (route) => {
|
|
42
|
+
route.fulfill({
|
|
43
|
+
status: 200,
|
|
44
|
+
contentType: "application/json",
|
|
45
|
+
body: JSON.stringify(parsedBody),
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
console.log(`📡 Stubbed "${url}" with JSON response.`);
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Intercepts a URL and stubs it with a raw string (non-JSON).
|
|
52
|
+
* * @example
|
|
53
|
+
* ```gherkin
|
|
54
|
+
* When I intercept URL "/health" and stub body "OK"
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
exports.InterceptStubRaw = (0, registry_1.Step)("I intercept URL {string} and stub body {string}", async (page, url, body) => {
|
|
58
|
+
await page.route(url, (route) => {
|
|
59
|
+
route.fulfill({
|
|
60
|
+
status: 200,
|
|
61
|
+
contentType: "text/plain",
|
|
62
|
+
body: body,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
console.log(`📡 Stubbed "${url}" with raw text: "${body}"`);
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* Intercepts a URL but allows it to continue (Network Spying).
|
|
69
|
+
* Useful for monitoring traffic without changing the response.
|
|
70
|
+
* * @example
|
|
71
|
+
* ```gherkin
|
|
72
|
+
* When I intercept URL "/api/*"
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
exports.InterceptSpy = (0, registry_1.Step)("I intercept URL {string}", async (page, url) => {
|
|
76
|
+
await page.route(url, async (route) => {
|
|
77
|
+
await route.continue();
|
|
78
|
+
});
|
|
79
|
+
console.log(`📡 Spying on URL "${url}" (allowed to continue).`);
|
|
80
|
+
});
|
|
81
|
+
// =============================
|
|
82
|
+
// 2. MAKING API REQUESTS
|
|
83
|
+
// =============================
|
|
84
|
+
/**
|
|
85
|
+
* Makes a GET request and stores the response in the test state.
|
|
86
|
+
* Stores values in `lastResponse` and `lastStatusCode`.
|
|
87
|
+
* * @example
|
|
88
|
+
* ```gherkin
|
|
89
|
+
* When I make request to "[https://api.example.com/v1/users](https://api.example.com/v1/users)"
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
exports.ApiGetRequest = (0, registry_1.Step)("I make request to {string}", async (page, url) => {
|
|
93
|
+
console.log(`⚡ GET request to: ${url}`);
|
|
94
|
+
const response = await page.request.get(url);
|
|
95
|
+
const status = response.status();
|
|
96
|
+
const body = await response.text();
|
|
97
|
+
let jsonBody;
|
|
98
|
+
try {
|
|
99
|
+
jsonBody = JSON.parse(body);
|
|
100
|
+
}
|
|
101
|
+
catch { }
|
|
102
|
+
(0, state_1.setVariable)(page, "lastResponse", { status, body, json: jsonBody });
|
|
103
|
+
(0, state_1.setVariable)(page, "lastStatusCode", status);
|
|
104
|
+
console.log(`✅ Status: ${status}`);
|
|
105
|
+
});
|
|
106
|
+
/**
|
|
107
|
+
* Makes a POST request with a JSON body provided via DocString.
|
|
108
|
+
* * @example
|
|
109
|
+
* ```gherkin
|
|
110
|
+
* When I make a POST request to "/api/login" with JSON body:
|
|
111
|
+
* """
|
|
112
|
+
* { "username": "admin", "password": "password123" }
|
|
113
|
+
* """
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
exports.ApiPostRequest = (0, registry_1.Step)(/^I make a POST request to "([^"]+)" with JSON body:?$/, async (page, url, docString) => {
|
|
117
|
+
const payload = safeJsonParse(docString, `POST to "${url}"`);
|
|
118
|
+
console.log(`⚡ POST request to: ${url}`);
|
|
119
|
+
const response = await page.request.post(url, { data: payload });
|
|
120
|
+
const status = response.status();
|
|
121
|
+
const body = await response.text();
|
|
122
|
+
let jsonBody;
|
|
123
|
+
try {
|
|
124
|
+
jsonBody = JSON.parse(body);
|
|
125
|
+
}
|
|
126
|
+
catch { }
|
|
127
|
+
(0, state_1.setVariable)(page, "lastResponse", { status, body, json: jsonBody });
|
|
128
|
+
(0, state_1.setVariable)(page, "lastStatusCode", status);
|
|
129
|
+
console.log(`✅ Status: ${status}`);
|
|
130
|
+
});
|
|
131
|
+
/**
|
|
132
|
+
* Makes a generic HTTP request using the browser's `fetch` API.
|
|
133
|
+
* Supports a data table for headers and an optional body.
|
|
134
|
+
* * @example
|
|
135
|
+
* ```gherkin
|
|
136
|
+
* When I make a "PUT" request to "/api/settings"
|
|
137
|
+
* | Authorization | Bearer my-token |
|
|
138
|
+
* | body | {"theme": "dark"} |
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
exports.BrowserFetchRequest = (0, registry_1.Step)('I make a "{word}" request to {string}', async (page, method, url, table) => {
|
|
142
|
+
const options = { method: method.toUpperCase() };
|
|
143
|
+
const rows = table && typeof table.rows === "function" ? table.rows() : table || [];
|
|
144
|
+
if (Array.isArray(rows)) {
|
|
145
|
+
rows.forEach((row) => {
|
|
146
|
+
const key = Array.isArray(row) ? row[0] : row.header || row.key;
|
|
147
|
+
const val = Array.isArray(row) ? row[1] : row.value;
|
|
148
|
+
if (!key)
|
|
149
|
+
return;
|
|
150
|
+
if (key.toLowerCase() === "body") {
|
|
151
|
+
options.body = val;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
if (!options.headers)
|
|
155
|
+
options.headers = {};
|
|
156
|
+
options.headers[key] = val;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
console.log(`⚡ Browser Fetch: ${method} ${url}`);
|
|
161
|
+
const res = await page.evaluate(async ({ url, options }) => {
|
|
162
|
+
const response = await fetch(url, options);
|
|
163
|
+
return {
|
|
164
|
+
status: response.status,
|
|
165
|
+
body: await response.text(),
|
|
166
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
167
|
+
};
|
|
168
|
+
}, { url, options });
|
|
169
|
+
let jsonBody;
|
|
170
|
+
try {
|
|
171
|
+
jsonBody = JSON.parse(res.body);
|
|
172
|
+
}
|
|
173
|
+
catch { }
|
|
174
|
+
(0, state_1.setVariable)(page, "lastResponse", { ...res, json: jsonBody });
|
|
175
|
+
(0, state_1.setVariable)(page, "lastStatusCode", res.status);
|
|
176
|
+
console.log(`✅ Status: ${res.status}`);
|
|
177
|
+
});
|
|
@@ -1,2 +1,44 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module ApiActions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Performs a standard HTTP GET request and stores the response in the global API state.
|
|
6
|
+
* * @example
|
|
7
|
+
* ```gherkin
|
|
8
|
+
* When I make a GET request to "[https://api.example.com/users](https://api.example.com/users)"
|
|
9
|
+
* ```
|
|
10
|
+
* * @param url - The full URL or endpoint path.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MakeGetRequest: void;
|
|
13
|
+
/**
|
|
14
|
+
* Performs a standard HTTP DELETE request and stores the response in the global API state.
|
|
15
|
+
* * @example
|
|
16
|
+
* ```gherkin
|
|
17
|
+
* When I make a DELETE request to "/api/users/1"
|
|
18
|
+
* ```
|
|
19
|
+
* * @param url - The endpoint path to delete.
|
|
20
|
+
*/
|
|
21
|
+
export declare const MakeDeleteRequest: void;
|
|
22
|
+
/**
|
|
23
|
+
* Performs an HTTP POST request using a Gherkin Data Table as the JSON payload.
|
|
24
|
+
* * @example
|
|
25
|
+
* ```gherkin
|
|
26
|
+
* When I make a POST request to "/api/users" with data
|
|
27
|
+
* | name | John |
|
|
28
|
+
* | job | Dev |
|
|
29
|
+
* ```
|
|
30
|
+
* * @param url - The target endpoint.
|
|
31
|
+
* @param tableData - The Gherkin Data Table (automatically converted to a JSON object).
|
|
32
|
+
*/
|
|
33
|
+
export declare const MakePostRequestWithTable: void;
|
|
34
|
+
/**
|
|
35
|
+
* Performs an HTTP POST request using the contents of a local JSON file as the payload.
|
|
36
|
+
* * @example
|
|
37
|
+
* ```gherkin
|
|
38
|
+
* When I make a POST request to "/api/users" with payload from "data/user.json"
|
|
39
|
+
* ```
|
|
40
|
+
* * @param url - The target endpoint.
|
|
41
|
+
* @param filePath - Path to the JSON file relative to the project root.
|
|
42
|
+
*/
|
|
43
|
+
export declare const MakePostRequestWithFile: void;
|
|
2
44
|
//# sourceMappingURL=requests.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../../src/backend/api/requests.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../../src/backend/api/requests.ts"],"names":[],"mappings":"AAKA;;GAEG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,MAIzB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,MAI5B,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,MAmBpC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,MAoBnC,CAAC"}
|