playwright-cucumber-ts-steps 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/actions/formTable.js +7 -16
- package/dist/backend/actions/interactions.js +15 -24
- package/dist/backend/actions/navigation.js +12 -21
- package/dist/backend/api/assertions.js +8 -17
- package/dist/backend/api/mock.js +15 -24
- package/dist/backend/api/requests.js +12 -21
- package/dist/backend/assertions/expectVisible.js +4 -15
- package/dist/backend/assertions/pageState.js +15 -24
- package/dist/backend/assertions/text.js +12 -21
- package/dist/backend/assertions/visibility.js +12 -21
- package/dist/backend/auth/index.js +6 -15
- package/dist/backend/db/state.js +3 -12
- package/dist/backend/db/steps.js +7 -16
- package/dist/backend/elements/alerts.js +15 -24
- package/dist/backend/elements/forms.js +12 -21
- package/dist/backend/elements/frames.js +11 -20
- package/dist/core/runner.js +7 -16
- package/package.json +1 -1
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const registry_1 = require("../../core/registry");
|
|
13
4
|
const test_1 = require("@playwright/test");
|
|
14
5
|
// CHANGE: Removed the ':' at the end of the string below
|
|
15
|
-
(0, registry_1.Step)("I fill the following {string} form data", (page, formName, tableData) =>
|
|
6
|
+
(0, registry_1.Step)("I fill the following {string} form data", async (page, formName, tableData) => {
|
|
16
7
|
console.log(`📝 Processing Form: ${formName}`);
|
|
17
8
|
// The runner passes the table data as the last argument
|
|
18
9
|
// tableData = [ ['#username', 'tomsmith'], ['#password', '...'] ]
|
|
@@ -24,20 +15,20 @@ const test_1 = require("@playwright/test");
|
|
|
24
15
|
const selector = row[0];
|
|
25
16
|
const value = row[1];
|
|
26
17
|
if (value === "click") {
|
|
27
|
-
|
|
18
|
+
await page.click(selector);
|
|
28
19
|
}
|
|
29
20
|
else if (value === "check") {
|
|
30
|
-
|
|
21
|
+
await page.check(selector);
|
|
31
22
|
}
|
|
32
23
|
else if (value === "assert:visible") {
|
|
33
|
-
|
|
24
|
+
await (0, test_1.expect)(page.locator(selector)).toBeVisible();
|
|
34
25
|
}
|
|
35
26
|
else if (value.startsWith("assert:text:")) {
|
|
36
27
|
const text = value.replace("assert:text:", "");
|
|
37
|
-
|
|
28
|
+
await (0, test_1.expect)(page.locator(selector)).toHaveText(text);
|
|
38
29
|
}
|
|
39
30
|
else {
|
|
40
|
-
|
|
31
|
+
await page.fill(selector, value);
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
|
-
})
|
|
34
|
+
});
|
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const registry_1 = require("../../core/registry");
|
|
13
4
|
// Click
|
|
14
|
-
(0, registry_1.Step)("I click {string}", (page, selector) =>
|
|
15
|
-
|
|
16
|
-
})
|
|
5
|
+
(0, registry_1.Step)("I click {string}", async (page, selector) => {
|
|
6
|
+
await page.click(selector);
|
|
7
|
+
});
|
|
17
8
|
// Force Click (sometimes needed for stubborn elements)
|
|
18
|
-
(0, registry_1.Step)("I force click {string}", (page, selector) =>
|
|
19
|
-
|
|
20
|
-
})
|
|
9
|
+
(0, registry_1.Step)("I force click {string}", async (page, selector) => {
|
|
10
|
+
await page.click(selector, { force: true });
|
|
11
|
+
});
|
|
21
12
|
// Type/Fill
|
|
22
|
-
(0, registry_1.Step)("I fill {string} with {string}", (page, selector, value) =>
|
|
23
|
-
|
|
24
|
-
})
|
|
13
|
+
(0, registry_1.Step)("I fill {string} with {string}", async (page, selector, value) => {
|
|
14
|
+
await page.fill(selector, value);
|
|
15
|
+
});
|
|
25
16
|
// Press Key (e.g., "Enter")
|
|
26
|
-
(0, registry_1.Step)("I press {string}", (page, key) =>
|
|
27
|
-
|
|
28
|
-
})
|
|
17
|
+
(0, registry_1.Step)("I press {string}", async (page, key) => {
|
|
18
|
+
await page.keyboard.press(key);
|
|
19
|
+
});
|
|
29
20
|
// Wait (Hard wait - use sparingly!)
|
|
30
|
-
(0, registry_1.Step)("I wait for {int} milliseconds", (page, ms) =>
|
|
31
|
-
|
|
32
|
-
})
|
|
21
|
+
(0, registry_1.Step)("I wait for {int} milliseconds", async (page, ms) => {
|
|
22
|
+
await page.waitForTimeout(ms);
|
|
23
|
+
});
|
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const registry_1 = require("../../core/registry");
|
|
13
4
|
// Basic visit
|
|
14
|
-
(0, registry_1.Step)("I visit {string}", (page, url) =>
|
|
15
|
-
|
|
16
|
-
})
|
|
5
|
+
(0, registry_1.Step)("I visit {string}", async (page, url) => {
|
|
6
|
+
await page.goto(url);
|
|
7
|
+
});
|
|
17
8
|
// Visit and wait for network (useful for slow apps)
|
|
18
|
-
(0, registry_1.Step)("I visit {string} and wait for network idle", (page, url) =>
|
|
19
|
-
|
|
20
|
-
})
|
|
9
|
+
(0, registry_1.Step)("I visit {string} and wait for network idle", async (page, url) => {
|
|
10
|
+
await page.goto(url, { waitUntil: "networkidle" });
|
|
11
|
+
});
|
|
21
12
|
// Reload page
|
|
22
|
-
(0, registry_1.Step)("I reload the page", (page) =>
|
|
23
|
-
|
|
24
|
-
})
|
|
13
|
+
(0, registry_1.Step)("I reload the page", async (page) => {
|
|
14
|
+
await page.reload();
|
|
15
|
+
});
|
|
25
16
|
// Go back
|
|
26
|
-
(0, registry_1.Step)("I go back", (page) =>
|
|
27
|
-
|
|
28
|
-
})
|
|
17
|
+
(0, registry_1.Step)("I go back", async (page) => {
|
|
18
|
+
await page.goBack();
|
|
19
|
+
});
|
|
@@ -1,35 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const test_1 = require("@playwright/test");
|
|
13
4
|
const registry_1 = require("../../core/registry");
|
|
14
5
|
const state_1 = require("./state");
|
|
15
6
|
// Check Status Code
|
|
16
|
-
(0, registry_1.Step)("I expect the response status to be {int}", (page, statusCode) =>
|
|
7
|
+
(0, registry_1.Step)("I expect the response status to be {int}", async (page, statusCode) => {
|
|
17
8
|
const response = state_1.apiState.getResponse();
|
|
18
9
|
(0, test_1.expect)(response.status()).toBe(statusCode);
|
|
19
|
-
})
|
|
10
|
+
});
|
|
20
11
|
// Check entire Body Text
|
|
21
|
-
(0, registry_1.Step)("I expect the response body to contain {string}", (page, text) =>
|
|
12
|
+
(0, registry_1.Step)("I expect the response body to contain {string}", async (page, text) => {
|
|
22
13
|
const response = state_1.apiState.getResponse();
|
|
23
|
-
const body =
|
|
14
|
+
const body = await response.text();
|
|
24
15
|
(0, test_1.expect)(body).toContain(text);
|
|
25
|
-
})
|
|
16
|
+
});
|
|
26
17
|
// Check JSON Property
|
|
27
|
-
(0, registry_1.Step)("I expect the response property {string} to be {string}", (page, jsonPath, value) =>
|
|
18
|
+
(0, registry_1.Step)("I expect the response property {string} to be {string}", async (page, jsonPath, value) => {
|
|
28
19
|
const response = state_1.apiState.getResponse();
|
|
29
|
-
const json =
|
|
20
|
+
const json = await response.json();
|
|
30
21
|
// FIX: Added ': string' to the 'i' parameter
|
|
31
22
|
const actualValue = jsonPath
|
|
32
23
|
.split(".")
|
|
33
24
|
.reduce((o, i) => o[i], json);
|
|
34
25
|
(0, test_1.expect)(String(actualValue)).toBe(value);
|
|
35
|
-
})
|
|
26
|
+
});
|
package/dist/backend/api/mock.js
CHANGED
|
@@ -32,53 +32,44 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
36
|
const registry_1 = require("../../core/registry");
|
|
46
37
|
const fs = __importStar(require("fs"));
|
|
47
38
|
const path = __importStar(require("path"));
|
|
48
39
|
// 1. Mock with Inline JSON
|
|
49
40
|
// Usage: Given I mock the API endpoint "/api/users" with body '{"id": 1, "name": "Fake"}'
|
|
50
|
-
(0, registry_1.Step)("I mock the API endpoint {string} with body {string}", (page, urlPattern, jsonBody) =>
|
|
51
|
-
|
|
41
|
+
(0, registry_1.Step)("I mock the API endpoint {string} with body {string}", async (page, urlPattern, jsonBody) => {
|
|
42
|
+
await page.route(urlPattern, async (route) => {
|
|
52
43
|
const json = JSON.parse(jsonBody);
|
|
53
|
-
|
|
44
|
+
await route.fulfill({
|
|
54
45
|
status: 200,
|
|
55
46
|
contentType: "application/json",
|
|
56
47
|
body: JSON.stringify(json),
|
|
57
48
|
});
|
|
58
|
-
})
|
|
49
|
+
});
|
|
59
50
|
console.log(`🎭 Mocked ${urlPattern} with inline JSON`);
|
|
60
|
-
})
|
|
51
|
+
});
|
|
61
52
|
// 2. Mock with File
|
|
62
53
|
// Usage: Given I mock the API endpoint "/api/users" with response from "mocks/users.json"
|
|
63
|
-
(0, registry_1.Step)("I mock the API endpoint {string} with response from {string}", (page, urlPattern, filePath) =>
|
|
54
|
+
(0, registry_1.Step)("I mock the API endpoint {string} with response from {string}", async (page, urlPattern, filePath) => {
|
|
64
55
|
const fullPath = path.resolve(process.cwd(), filePath);
|
|
65
56
|
if (!fs.existsSync(fullPath)) {
|
|
66
57
|
throw new Error(`❌ Mock file not found at: ${fullPath}`);
|
|
67
58
|
}
|
|
68
59
|
const bodyContent = fs.readFileSync(fullPath, "utf8");
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
await page.route(urlPattern, async (route) => {
|
|
61
|
+
await route.fulfill({
|
|
71
62
|
status: 200,
|
|
72
63
|
contentType: "application/json",
|
|
73
64
|
body: bodyContent,
|
|
74
65
|
});
|
|
75
|
-
})
|
|
66
|
+
});
|
|
76
67
|
console.log(`🎭 Mocked ${urlPattern} with file: ${filePath}`);
|
|
77
|
-
})
|
|
68
|
+
});
|
|
78
69
|
// 3. Mock Status Code Only (Simulate Errors)
|
|
79
70
|
// Usage: Given I mock the API endpoint "/api/broken" with status 500
|
|
80
|
-
(0, registry_1.Step)("I mock the API endpoint {string} with status {int}", (page, urlPattern, statusCode) =>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
})
|
|
84
|
-
})
|
|
71
|
+
(0, registry_1.Step)("I mock the API endpoint {string} with status {int}", async (page, urlPattern, statusCode) => {
|
|
72
|
+
await page.route(urlPattern, async (route) => {
|
|
73
|
+
await route.fulfill({ status: statusCode });
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -32,37 +32,28 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
36
|
const registry_1 = require("../../core/registry");
|
|
46
37
|
const state_1 = require("./state");
|
|
47
38
|
const fs = __importStar(require("fs"));
|
|
48
39
|
const path = __importStar(require("path"));
|
|
49
40
|
// GET Request
|
|
50
|
-
(0, registry_1.Step)("I make a GET request to {string}", (page, url) =>
|
|
51
|
-
const response =
|
|
41
|
+
(0, registry_1.Step)("I make a GET request to {string}", async (page, url) => {
|
|
42
|
+
const response = await page.request.get(url);
|
|
52
43
|
state_1.apiState.setResponse(response);
|
|
53
44
|
console.log(`GET ${url} - Status: ${response.status()}`);
|
|
54
|
-
})
|
|
45
|
+
});
|
|
55
46
|
// DELETE Request
|
|
56
|
-
(0, registry_1.Step)("I make a DELETE request to {string}", (page, url) =>
|
|
57
|
-
const response =
|
|
47
|
+
(0, registry_1.Step)("I make a DELETE request to {string}", async (page, url) => {
|
|
48
|
+
const response = await page.request.delete(url);
|
|
58
49
|
state_1.apiState.setResponse(response);
|
|
59
|
-
})
|
|
50
|
+
});
|
|
60
51
|
// 1. POST with Data Table
|
|
61
52
|
// Usage:
|
|
62
53
|
// When I make a POST request to "/api/users" with data:
|
|
63
54
|
// | name | John |
|
|
64
55
|
// | job | Dev |
|
|
65
|
-
(0, registry_1.Step)("I make a POST request to {string} with data", (page, url, tableData) =>
|
|
56
|
+
(0, registry_1.Step)("I make a POST request to {string} with data", async (page, url, tableData) => {
|
|
66
57
|
if (!tableData)
|
|
67
58
|
throw new Error("This step requires a Data Table.");
|
|
68
59
|
// Convert Table [ ["key", "val"], ["k2", "v2"] ] -> Object { key: "val", k2: "v2" }
|
|
@@ -70,15 +61,15 @@ const path = __importStar(require("path"));
|
|
|
70
61
|
acc[row[0]] = row[1];
|
|
71
62
|
return acc;
|
|
72
63
|
}, {});
|
|
73
|
-
const response =
|
|
64
|
+
const response = await page.request.post(url, {
|
|
74
65
|
data: payload,
|
|
75
66
|
headers: { "Content-Type": "application/json" },
|
|
76
67
|
});
|
|
77
68
|
state_1.apiState.setResponse(response);
|
|
78
|
-
})
|
|
69
|
+
});
|
|
79
70
|
// 2. POST with File Payload
|
|
80
71
|
// Usage: When I make a POST request to "/api/users" with payload from "data/user.json"
|
|
81
|
-
(0, registry_1.Step)("I make a POST request to {string} with payload from {string}", (page, url, filePath) =>
|
|
72
|
+
(0, registry_1.Step)("I make a POST request to {string} with payload from {string}", async (page, url, filePath) => {
|
|
82
73
|
// Resolve file path (relative to root)
|
|
83
74
|
const fullPath = path.resolve(process.cwd(), filePath);
|
|
84
75
|
if (!fs.existsSync(fullPath)) {
|
|
@@ -87,9 +78,9 @@ const path = __importStar(require("path"));
|
|
|
87
78
|
// Read and parse JSON
|
|
88
79
|
const fileContent = fs.readFileSync(fullPath, "utf8");
|
|
89
80
|
const payload = JSON.parse(fileContent);
|
|
90
|
-
const response =
|
|
81
|
+
const response = await page.request.post(url, {
|
|
91
82
|
data: payload,
|
|
92
83
|
headers: { "Content-Type": "application/json" },
|
|
93
84
|
});
|
|
94
85
|
state_1.apiState.setResponse(response);
|
|
95
|
-
})
|
|
86
|
+
});
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.expectVisible = expectVisible;
|
|
13
|
-
function expectVisible(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
throw new Error(`Element ${selector} not visible`);
|
|
18
|
-
});
|
|
4
|
+
async function expectVisible(page, selector, timeout = 2000) {
|
|
5
|
+
const el = await page.waitForSelector(selector, { state: 'visible', timeout });
|
|
6
|
+
if (!el)
|
|
7
|
+
throw new Error(`Element ${selector} not visible`);
|
|
19
8
|
}
|
|
@@ -1,34 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const test_1 = require("@playwright/test");
|
|
13
4
|
const registry_1 = require("../../core/registry");
|
|
14
5
|
// URL Check
|
|
15
|
-
(0, registry_1.Step)("I expect the url to be {string}", (page, url) =>
|
|
16
|
-
|
|
17
|
-
})
|
|
6
|
+
(0, registry_1.Step)("I expect the url to be {string}", async (page, url) => {
|
|
7
|
+
await (0, test_1.expect)(page).toHaveURL(url);
|
|
8
|
+
});
|
|
18
9
|
// Partial URL Check
|
|
19
|
-
(0, registry_1.Step)("I expect the url to contain {string}", (page, part) =>
|
|
10
|
+
(0, registry_1.Step)("I expect the url to contain {string}", async (page, part) => {
|
|
20
11
|
// We use a RegExp to allow partial matching safely
|
|
21
|
-
|
|
22
|
-
})
|
|
12
|
+
await (0, test_1.expect)(page).toHaveURL(new RegExp(part));
|
|
13
|
+
});
|
|
23
14
|
// Title Check
|
|
24
|
-
(0, registry_1.Step)("I expect the title to be {string}", (page, title) =>
|
|
25
|
-
|
|
26
|
-
})
|
|
15
|
+
(0, registry_1.Step)("I expect the title to be {string}", async (page, title) => {
|
|
16
|
+
await (0, test_1.expect)(page).toHaveTitle(title);
|
|
17
|
+
});
|
|
27
18
|
// Partial Title Check
|
|
28
|
-
(0, registry_1.Step)("I expect the title to contain {string}", (page, titlePart) =>
|
|
29
|
-
|
|
30
|
-
})
|
|
19
|
+
(0, registry_1.Step)("I expect the title to contain {string}", async (page, titlePart) => {
|
|
20
|
+
await (0, test_1.expect)(page).toHaveTitle(new RegExp(titlePart));
|
|
21
|
+
});
|
|
31
22
|
// Screenshot Match (Visual Regression)
|
|
32
|
-
(0, registry_1.Step)("I expect the page screenshot to match {string}", (page, filename) =>
|
|
33
|
-
|
|
34
|
-
})
|
|
23
|
+
(0, registry_1.Step)("I expect the page screenshot to match {string}", async (page, filename) => {
|
|
24
|
+
await (0, test_1.expect)(page).toHaveScreenshot(filename);
|
|
25
|
+
});
|
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const test_1 = require("@playwright/test");
|
|
13
4
|
const registry_1 = require("../../core/registry");
|
|
14
5
|
// Exact text match
|
|
15
|
-
(0, registry_1.Step)("I expect {string} to have text {string}", (page, selector, text) =>
|
|
16
|
-
|
|
17
|
-
})
|
|
6
|
+
(0, registry_1.Step)("I expect {string} to have text {string}", async (page, selector, text) => {
|
|
7
|
+
await (0, test_1.expect)(page.locator(selector)).toHaveText(text);
|
|
8
|
+
});
|
|
18
9
|
// Partial text match (contains)
|
|
19
|
-
(0, registry_1.Step)("I expect {string} to contain text {string}", (page, selector, text) =>
|
|
20
|
-
|
|
21
|
-
})
|
|
10
|
+
(0, registry_1.Step)("I expect {string} to contain text {string}", async (page, selector, text) => {
|
|
11
|
+
await (0, test_1.expect)(page.locator(selector)).toContainText(text);
|
|
12
|
+
});
|
|
22
13
|
// Check input value (for form fields)
|
|
23
|
-
(0, registry_1.Step)("I expect {string} to have value {string}", (page, selector, value) =>
|
|
24
|
-
|
|
25
|
-
})
|
|
14
|
+
(0, registry_1.Step)("I expect {string} to have value {string}", async (page, selector, value) => {
|
|
15
|
+
await (0, test_1.expect)(page.locator(selector)).toHaveValue(value);
|
|
16
|
+
});
|
|
26
17
|
// Check an attribute (e.g., class, href, src)
|
|
27
|
-
(0, registry_1.Step)("I expect {string} to have attribute {string} with value {string}", (page, selector, attr, value) =>
|
|
28
|
-
|
|
29
|
-
})
|
|
18
|
+
(0, registry_1.Step)("I expect {string} to have attribute {string} with value {string}", async (page, selector, attr, value) => {
|
|
19
|
+
await (0, test_1.expect)(page.locator(selector)).toHaveAttribute(attr, value);
|
|
20
|
+
});
|
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const test_1 = require("@playwright/test");
|
|
13
4
|
const registry_1 = require("../../core/registry");
|
|
14
5
|
// Check if element exists and is visible
|
|
15
|
-
(0, registry_1.Step)("I expect {string} to be visible", (page, selector) =>
|
|
16
|
-
|
|
17
|
-
})
|
|
6
|
+
(0, registry_1.Step)("I expect {string} to be visible", async (page, selector) => {
|
|
7
|
+
await (0, test_1.expect)(page.locator(selector)).toBeVisible();
|
|
8
|
+
});
|
|
18
9
|
// Check if element is hidden (or doesn't exist)
|
|
19
|
-
(0, registry_1.Step)("I expect {string} to be hidden", (page, selector) =>
|
|
20
|
-
|
|
21
|
-
})
|
|
10
|
+
(0, registry_1.Step)("I expect {string} to be hidden", async (page, selector) => {
|
|
11
|
+
await (0, test_1.expect)(page.locator(selector)).toBeHidden();
|
|
12
|
+
});
|
|
22
13
|
// Check if element is enabled (clickable)
|
|
23
|
-
(0, registry_1.Step)("I expect {string} to be enabled", (page, selector) =>
|
|
24
|
-
|
|
25
|
-
})
|
|
14
|
+
(0, registry_1.Step)("I expect {string} to be enabled", async (page, selector) => {
|
|
15
|
+
await (0, test_1.expect)(page.locator(selector)).toBeEnabled();
|
|
16
|
+
});
|
|
26
17
|
// Check if element is disabled
|
|
27
|
-
(0, registry_1.Step)("I expect {string} to be disabled", (page, selector) =>
|
|
28
|
-
|
|
29
|
-
})
|
|
18
|
+
(0, registry_1.Step)("I expect {string} to be disabled", async (page, selector) => {
|
|
19
|
+
await (0, test_1.expect)(page.locator(selector)).toBeDisabled();
|
|
20
|
+
});
|
|
@@ -32,34 +32,25 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
36
|
const registry_1 = require("../../core/registry");
|
|
46
37
|
const path = __importStar(require("path"));
|
|
47
38
|
const fs = __importStar(require("fs"));
|
|
48
39
|
// 1. SAVE STATE (Use this after a successful login)
|
|
49
40
|
// Example: And I save the browser state to "admin.json"
|
|
50
|
-
(0, registry_1.Step)("I save the browser state to {string}", (page, filename) =>
|
|
41
|
+
(0, registry_1.Step)("I save the browser state to {string}", async (page, filename) => {
|
|
51
42
|
// Ensure the directory exists
|
|
52
43
|
const authDir = path.resolve(process.cwd(), "auth");
|
|
53
44
|
if (!fs.existsSync(authDir)) {
|
|
54
45
|
fs.mkdirSync(authDir);
|
|
55
46
|
}
|
|
56
47
|
const filePath = path.resolve(authDir, filename);
|
|
57
|
-
|
|
48
|
+
await page.context().storageState({ path: filePath });
|
|
58
49
|
console.log(`✅ State saved to: ${filePath}`);
|
|
59
|
-
})
|
|
50
|
+
});
|
|
60
51
|
// 2. LOAD STATE (Use this at the start of other scenarios)
|
|
61
52
|
// Example: Given I load the browser state from "admin.json"
|
|
62
|
-
(0, registry_1.Step)("I load the browser state from {string}", (page, filename) =>
|
|
53
|
+
(0, registry_1.Step)("I load the browser state from {string}", async (page, filename) => {
|
|
63
54
|
const filePath = path.resolve(process.cwd(), "auth", filename);
|
|
64
55
|
if (!fs.existsSync(filePath)) {
|
|
65
56
|
throw new Error(`❌ Auth file not found at: ${filePath}. Did you run the login scenario first?`);
|
|
@@ -68,7 +59,7 @@ const fs = __importStar(require("fs"));
|
|
|
68
59
|
// To load it dynamically mid-test, we need to add cookies/origins to the current context.
|
|
69
60
|
const state = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
70
61
|
if (state.cookies) {
|
|
71
|
-
|
|
62
|
+
await page.context().addCookies(state.cookies);
|
|
72
63
|
}
|
|
73
64
|
if (state.origins) {
|
|
74
65
|
// LocalStorage requires a bit more work, usually handled by context creation,
|
|
@@ -77,4 +68,4 @@ const fs = __importStar(require("fs"));
|
|
|
77
68
|
// but this step is a great dynamic helper.
|
|
78
69
|
}
|
|
79
70
|
console.log(`✅ Loaded session for: ${filename}`);
|
|
80
|
-
})
|
|
71
|
+
});
|
package/dist/backend/db/state.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.dbState = void 0;
|
|
13
4
|
// Holds the user's custom DB function
|
|
@@ -19,15 +10,15 @@ exports.dbState = {
|
|
|
19
10
|
dbAdapter = fn;
|
|
20
11
|
},
|
|
21
12
|
// Step calls this to run a query
|
|
22
|
-
executeQuery: (query) =>
|
|
13
|
+
executeQuery: async (query) => {
|
|
23
14
|
if (!dbAdapter) {
|
|
24
15
|
throw new Error("❌ No Database Adapter found. Pass a 'dbQuery' function to runTests().");
|
|
25
16
|
}
|
|
26
|
-
const result =
|
|
17
|
+
const result = await dbAdapter(query);
|
|
27
18
|
lastResult = result;
|
|
28
19
|
console.log(`🗄️ DB Result:`, JSON.stringify(lastResult));
|
|
29
20
|
return result;
|
|
30
|
-
}
|
|
21
|
+
},
|
|
31
22
|
// Assertions use this to check results
|
|
32
23
|
getLastResult: () => lastResult,
|
|
33
24
|
};
|
package/dist/backend/db/steps.js
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const registry_1 = require("../../core/registry");
|
|
13
4
|
const state_1 = require("./state");
|
|
14
5
|
const test_1 = require("@playwright/test");
|
|
15
6
|
// 1. Run Query
|
|
16
|
-
(0, registry_1.Step)("I run the database query {string}", (page, query) =>
|
|
17
|
-
|
|
18
|
-
})
|
|
7
|
+
(0, registry_1.Step)("I run the database query {string}", async (page, query) => {
|
|
8
|
+
await state_1.dbState.executeQuery(query);
|
|
9
|
+
});
|
|
19
10
|
// 2. Count Check
|
|
20
|
-
(0, registry_1.Step)("I expect the database to return {int} record(s)", (page, count) =>
|
|
11
|
+
(0, registry_1.Step)("I expect the database to return {int} record(s)", async (page, count) => {
|
|
21
12
|
const result = state_1.dbState.getLastResult();
|
|
22
13
|
if (Array.isArray(result)) {
|
|
23
14
|
(0, test_1.expect)(result.length).toBe(count);
|
|
@@ -25,10 +16,10 @@ const test_1 = require("@playwright/test");
|
|
|
25
16
|
else {
|
|
26
17
|
throw new Error(`Expected array result but got: ${typeof result}`);
|
|
27
18
|
}
|
|
28
|
-
})
|
|
19
|
+
});
|
|
29
20
|
// 3. JSON/Table Check
|
|
30
21
|
// CHANGE: Removed the colon ':' at the end of the string below
|
|
31
|
-
(0, registry_1.Step)("I expect the first database record to contain", (page, tableData) =>
|
|
22
|
+
(0, registry_1.Step)("I expect the first database record to contain", async (page, tableData) => {
|
|
32
23
|
const result = state_1.dbState.getLastResult();
|
|
33
24
|
// Guard Clauses
|
|
34
25
|
if (!Array.isArray(result) || result.length === 0) {
|
|
@@ -49,4 +40,4 @@ const test_1 = require("@playwright/test");
|
|
|
49
40
|
// Loose equality check (DB might return int, Gherkin sends string)
|
|
50
41
|
(0, test_1.expect)(String(firstRow[key])).toBe(expectedValue);
|
|
51
42
|
}
|
|
52
|
-
})
|
|
43
|
+
});
|
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const registry_1 = require("../../core/registry");
|
|
13
4
|
// Accept the next popup (Alert/Confirm/Prompt)
|
|
14
|
-
(0, registry_1.Step)("I accept the next dialog", (page) =>
|
|
15
|
-
page.once("dialog", (dialog) =>
|
|
16
|
-
|
|
17
|
-
})
|
|
18
|
-
})
|
|
5
|
+
(0, registry_1.Step)("I accept the next dialog", async (page) => {
|
|
6
|
+
page.once("dialog", async (dialog) => {
|
|
7
|
+
await dialog.accept();
|
|
8
|
+
});
|
|
9
|
+
});
|
|
19
10
|
// Dismiss (Cancel) the next popup
|
|
20
|
-
(0, registry_1.Step)("I dismiss the next dialog", (page) =>
|
|
21
|
-
page.once("dialog", (dialog) =>
|
|
22
|
-
|
|
23
|
-
})
|
|
24
|
-
})
|
|
11
|
+
(0, registry_1.Step)("I dismiss the next dialog", async (page) => {
|
|
12
|
+
page.once("dialog", async (dialog) => {
|
|
13
|
+
await dialog.dismiss();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
25
16
|
// Type text into a prompt and accept
|
|
26
|
-
(0, registry_1.Step)("I type {string} into the next prompt and accept", (page, text) =>
|
|
27
|
-
page.once("dialog", (dialog) =>
|
|
28
|
-
|
|
29
|
-
})
|
|
30
|
-
})
|
|
17
|
+
(0, registry_1.Step)("I type {string} into the next prompt and accept", async (page, text) => {
|
|
18
|
+
page.once("dialog", async (dialog) => {
|
|
19
|
+
await dialog.accept(text);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -32,37 +32,28 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
36
|
const registry_1 = require("../../core/registry");
|
|
46
37
|
const path = __importStar(require("path"));
|
|
47
38
|
// Dropdown: Select by value or label
|
|
48
|
-
(0, registry_1.Step)("I select option {string} from {string}", (page, option, selector) =>
|
|
49
|
-
|
|
39
|
+
(0, registry_1.Step)("I select option {string} from {string}", async (page, option, selector) => {
|
|
40
|
+
await page.selectOption(selector, { label: option }).catch(() => {
|
|
50
41
|
// Fallback: try selecting by value if label fails
|
|
51
42
|
return page.selectOption(selector, { value: option });
|
|
52
43
|
});
|
|
53
|
-
})
|
|
44
|
+
});
|
|
54
45
|
// Checkboxes & Radio Buttons
|
|
55
|
-
(0, registry_1.Step)("I check {string}", (page, selector) =>
|
|
56
|
-
|
|
57
|
-
})
|
|
58
|
-
(0, registry_1.Step)("I uncheck {string}", (page, selector) =>
|
|
59
|
-
|
|
60
|
-
})
|
|
46
|
+
(0, registry_1.Step)("I check {string}", async (page, selector) => {
|
|
47
|
+
await page.check(selector);
|
|
48
|
+
});
|
|
49
|
+
(0, registry_1.Step)("I uncheck {string}", async (page, selector) => {
|
|
50
|
+
await page.uncheck(selector);
|
|
51
|
+
});
|
|
61
52
|
// File Upload
|
|
62
53
|
// Usage: When I upload file "data.csv" to "#upload-input"
|
|
63
|
-
(0, registry_1.Step)("I upload file {string} to {string}", (page, fileName, selector) =>
|
|
54
|
+
(0, registry_1.Step)("I upload file {string} to {string}", async (page, fileName, selector) => {
|
|
64
55
|
// We assume the user puts files in a 'fixtures' or root folder.
|
|
65
56
|
// You might want to customize this path resolution.
|
|
66
57
|
const filePath = path.resolve(process.cwd(), fileName);
|
|
67
|
-
|
|
68
|
-
})
|
|
58
|
+
await page.setInputFiles(selector, filePath);
|
|
59
|
+
});
|
|
@@ -1,34 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
const registry_1 = require("../../core/registry");
|
|
13
4
|
// Click inside a specific frame
|
|
14
|
-
(0, registry_1.Step)("I click {string} inside frame {string}", (page, elementSelector, frameSelector) =>
|
|
5
|
+
(0, registry_1.Step)("I click {string} inside frame {string}", async (page, elementSelector, frameSelector) => {
|
|
15
6
|
const frame = page.frameLocator(frameSelector);
|
|
16
|
-
|
|
17
|
-
})
|
|
7
|
+
await frame.locator(elementSelector).click();
|
|
8
|
+
});
|
|
18
9
|
// Fill input inside a specific frame
|
|
19
|
-
(0, registry_1.Step)("I fill {string} inside frame {string} with {string}", (page, elementSelector, frameSelector, value) =>
|
|
10
|
+
(0, registry_1.Step)("I fill {string} inside frame {string} with {string}", async (page, elementSelector, frameSelector, value) => {
|
|
20
11
|
const frame = page.frameLocator(frameSelector);
|
|
21
|
-
|
|
22
|
-
})
|
|
12
|
+
await frame.locator(elementSelector).fill(value);
|
|
13
|
+
});
|
|
23
14
|
// Assert text inside a specific frame
|
|
24
|
-
(0, registry_1.Step)("I expect {string} inside frame {string} to have text {string}", (page, elementSelector, frameSelector, text) =>
|
|
15
|
+
(0, registry_1.Step)("I expect {string} inside frame {string} to have text {string}", async (page, elementSelector, frameSelector, text) => {
|
|
25
16
|
const frame = page.frameLocator(frameSelector);
|
|
26
17
|
const locator = frame.locator(elementSelector);
|
|
27
18
|
// We need to import expect for this assertion, or use a custom check
|
|
28
19
|
// Since we are inside 'elements', let's just do a basic wait/check or re-export expect
|
|
29
|
-
|
|
30
|
-
const actualText =
|
|
31
|
-
if (!
|
|
20
|
+
await locator.waitFor();
|
|
21
|
+
const actualText = await locator.textContent();
|
|
22
|
+
if (!actualText?.includes(text)) {
|
|
32
23
|
throw new Error(`Expected text "${text}" but found "${actualText}" in frame`);
|
|
33
24
|
}
|
|
34
|
-
})
|
|
25
|
+
});
|
package/dist/core/runner.js
CHANGED
|
@@ -32,15 +32,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
36
|
exports.runTests = runTests;
|
|
46
37
|
// src/core/runner.ts
|
|
@@ -62,7 +53,7 @@ require("../backend/db/index"); // Register DB steps
|
|
|
62
53
|
*/
|
|
63
54
|
function runTests(featureGlob, options) {
|
|
64
55
|
// 1. Register DB Adapter if provided
|
|
65
|
-
if (options
|
|
56
|
+
if (options?.dbQuery) {
|
|
66
57
|
state_1.dbState.setAdapter(options.dbQuery);
|
|
67
58
|
}
|
|
68
59
|
const files = (0, glob_1.globSync)(featureGlob);
|
|
@@ -83,10 +74,10 @@ function runTests(featureGlob, options) {
|
|
|
83
74
|
const nextMatchIndex = content.slice(startIndex).search(/Scenario:/);
|
|
84
75
|
const blockEnd = nextMatchIndex === -1 ? content.length : startIndex + nextMatchIndex;
|
|
85
76
|
const scenarioBlock = content.slice(startIndex, blockEnd);
|
|
86
|
-
if (
|
|
77
|
+
if (options?.tags && !foundTags.includes(options.tags)) {
|
|
87
78
|
continue;
|
|
88
79
|
}
|
|
89
|
-
(0, test_1.test)(scenarioName,
|
|
80
|
+
(0, test_1.test)(scenarioName, async ({ page }, testInfo) => {
|
|
90
81
|
const lines = scenarioBlock
|
|
91
82
|
.trim()
|
|
92
83
|
.split("\n")
|
|
@@ -128,23 +119,23 @@ function runTests(featureGlob, options) {
|
|
|
128
119
|
args.push(tableData);
|
|
129
120
|
}
|
|
130
121
|
// Pass 'page' + args to the step function
|
|
131
|
-
|
|
122
|
+
await stepDef.fn(page, ...args);
|
|
132
123
|
}
|
|
133
124
|
catch (error) {
|
|
134
125
|
console.error(`❌ Failed at step: "${stepText}"`);
|
|
135
126
|
// Take a screenshot immediately
|
|
136
|
-
const screenshot =
|
|
127
|
+
const screenshot = await page.screenshot({
|
|
137
128
|
fullPage: true,
|
|
138
129
|
type: "png",
|
|
139
130
|
});
|
|
140
|
-
|
|
131
|
+
await testInfo.attach("failure-screenshot", {
|
|
141
132
|
body: screenshot,
|
|
142
133
|
contentType: "image/png",
|
|
143
134
|
});
|
|
144
135
|
throw error;
|
|
145
136
|
}
|
|
146
137
|
}
|
|
147
|
-
})
|
|
138
|
+
});
|
|
148
139
|
}
|
|
149
140
|
});
|
|
150
141
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playwright-cucumber-ts-steps",
|
|
3
3
|
"description": "A collection of reusable Playwright step definitions for Cucumber in TypeScript, designed to streamline end-to-end testing across web, API, and mobile applications.",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|