pomwright 1.5.1 → 2.0.0
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/CHANGELOG.md +22 -0
- package/README.md +5 -5
- package/dist/index.d.mts +75 -970
- package/dist/index.d.ts +75 -970
- package/dist/index.js +585 -1872
- package/dist/index.mjs +598 -1880
- package/package.json +9 -11
- package/AGENTS.md +0 -37
- package/docs/v1/BaseApi-explanation.md +0 -63
- package/docs/v1/BasePage-explanation.md +0 -96
- package/docs/v1/LocatorSchema-explanation.md +0 -271
- package/docs/v1/LocatorSchemaPath-explanation.md +0 -165
- package/docs/v1/PlaywrightReportLogger-explanation.md +0 -56
- package/docs/v1/get-locator-methods-explanation.md +0 -250
- package/docs/v1/intro-to-using-pomwright.md +0 -899
- package/docs/v1/sessionStorage-methods-explanation.md +0 -38
- package/docs/v1/tips-folder-structure.md +0 -38
- package/docs/v1-to-v2-migration/bridge-migration-guide.md +0 -159
- package/docs/v1-to-v2-migration/direct-migration-guide.md +0 -238
- package/docs/v1-to-v2-migration/v1-to-v2-comparison.md +0 -547
- package/docs/v2/PageObject.md +0 -293
- package/docs/v2/composing-locator-modules.md +0 -93
- package/docs/v2/locator-registry.md +0 -695
- package/docs/v2/logging.md +0 -168
- package/docs/v2/overview.md +0 -515
- package/docs/v2/session-storage.md +0 -160
- package/index.ts +0 -75
- package/intTestV2/.env +0 -0
- package/intTestV2/fixtures/testApp.fixtures.ts +0 -43
- package/intTestV2/package.json +0 -22
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.locatorSchema.ts +0 -24
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.page.ts +0 -17
- package/intTestV2/page-object-models/testApp/pages/testPage.locatorSchema.ts +0 -32
- package/intTestV2/page-object-models/testApp/pages/testPage.page.ts +0 -119
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.locatorSchema.ts +0 -29
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.page.ts +0 -48
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.locatorSchema.ts +0 -9
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.locatorSchema.ts +0 -114
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/testApp.base.ts +0 -20
- package/intTestV2/playwright.config.ts +0 -54
- package/intTestV2/server.js +0 -216
- package/intTestV2/test-data/staticPage/index.html +0 -280
- package/intTestV2/test-data/staticPage/w3images/avatar2.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar3.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar5.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar6.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/forest.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/lights.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/mountains.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/nature.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/snow.jpg +0 -0
- package/intTestV2/tests/locatorRegistry/add/add.describe.spec.ts +0 -54
- package/intTestV2/tests/locatorRegistry/add/add.filter.spec.ts +0 -143
- package/intTestV2/tests/locatorRegistry/add/add.frameLocator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.get.clone.spec.ts +0 -76
- package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
- package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -107
- package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
- package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
- package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
- package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
- package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
- package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
- package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
- package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.typecheck.ts +0 -86
- package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
- package/intTestV2/tests/step/step.spec.ts +0 -49
- package/intTestV2/tests/testApp/color.spec.ts +0 -15
- package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
- package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
- package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
- package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
- package/pack-build.sh +0 -11
- package/pack-test-v2.sh +0 -36
- package/playwright.base.ts +0 -42
- package/skills/README.md +0 -56
- package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
- package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
- package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
- package/skills/pomwright-v2-migration/SKILL.md +0 -63
- package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
- package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
- package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
- package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
- package/srcV2/fixture/base.fixtures.ts +0 -23
- package/srcV2/helpers/navigation.ts +0 -153
- package/srcV2/helpers/playwrightReportLogger.ts +0 -196
- package/srcV2/helpers/sessionStorage.ts +0 -251
- package/srcV2/helpers/stepDecorator.ts +0 -106
- package/srcV2/locators/index.ts +0 -15
- package/srcV2/locators/locatorQueryBuilder.ts +0 -427
- package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
- package/srcV2/locators/locatorRegistry.ts +0 -583
- package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
- package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
- package/srcV2/locators/types.ts +0 -256
- package/srcV2/locators/utils.ts +0 -309
- package/srcV2/locators/v1SchemaTranslator.ts +0 -178
- package/srcV2/pageObject.ts +0 -105
package/dist/index.js
CHANGED
|
@@ -20,1436 +20,626 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
BaseApi: () => BaseApi,
|
|
24
|
-
BasePage: () => BasePage,
|
|
25
|
-
BasePageV1toV2: () => BasePageV1toV2,
|
|
26
|
-
GetByMethod: () => GetByMethod,
|
|
27
|
-
GetLocatorBase: () => GetLocatorBase,
|
|
28
23
|
PageObject: () => PageObject,
|
|
29
24
|
PlaywrightReportLogger: () => PlaywrightReportLogger,
|
|
30
|
-
SessionStorage: () =>
|
|
25
|
+
SessionStorage: () => SessionStorage,
|
|
31
26
|
createRegistryWithAccessors: () => createRegistryWithAccessors,
|
|
32
27
|
step: () => step,
|
|
33
|
-
test: () =>
|
|
28
|
+
test: () => test
|
|
34
29
|
});
|
|
35
30
|
module.exports = __toCommonJS(index_exports);
|
|
36
31
|
|
|
37
|
-
// src/
|
|
38
|
-
var
|
|
39
|
-
GetByMethod2["role"] = "role";
|
|
40
|
-
GetByMethod2["text"] = "text";
|
|
41
|
-
GetByMethod2["label"] = "label";
|
|
42
|
-
GetByMethod2["placeholder"] = "placeholder";
|
|
43
|
-
GetByMethod2["altText"] = "altText";
|
|
44
|
-
GetByMethod2["title"] = "title";
|
|
45
|
-
GetByMethod2["locator"] = "locator";
|
|
46
|
-
GetByMethod2["frameLocator"] = "frameLocator";
|
|
47
|
-
GetByMethod2["testId"] = "testId";
|
|
48
|
-
GetByMethod2["dataCy"] = "dataCy";
|
|
49
|
-
GetByMethod2["id"] = "id";
|
|
50
|
-
return GetByMethod2;
|
|
51
|
-
})(GetByMethod || {});
|
|
52
|
-
var locatorSchemaDummy = {
|
|
53
|
-
role: void 0,
|
|
54
|
-
roleOptions: {
|
|
55
|
-
checked: void 0,
|
|
56
|
-
disabled: void 0,
|
|
57
|
-
exact: void 0,
|
|
58
|
-
expanded: void 0,
|
|
59
|
-
includeHidden: void 0,
|
|
60
|
-
level: void 0,
|
|
61
|
-
name: void 0,
|
|
62
|
-
pressed: void 0,
|
|
63
|
-
selected: void 0
|
|
64
|
-
},
|
|
65
|
-
text: void 0,
|
|
66
|
-
textOptions: {
|
|
67
|
-
exact: void 0
|
|
68
|
-
},
|
|
69
|
-
label: void 0,
|
|
70
|
-
labelOptions: {
|
|
71
|
-
exact: void 0
|
|
72
|
-
},
|
|
73
|
-
placeholder: void 0,
|
|
74
|
-
placeholderOptions: {
|
|
75
|
-
exact: void 0
|
|
76
|
-
},
|
|
77
|
-
altText: void 0,
|
|
78
|
-
altTextOptions: {
|
|
79
|
-
exact: void 0
|
|
80
|
-
},
|
|
81
|
-
title: void 0,
|
|
82
|
-
titleOptions: {
|
|
83
|
-
exact: void 0
|
|
84
|
-
},
|
|
85
|
-
locator: void 0,
|
|
86
|
-
locatorOptions: {
|
|
87
|
-
has: void 0,
|
|
88
|
-
hasNot: void 0,
|
|
89
|
-
hasNotText: void 0,
|
|
90
|
-
hasText: void 0
|
|
91
|
-
},
|
|
92
|
-
frameLocator: void 0,
|
|
93
|
-
testId: void 0,
|
|
94
|
-
dataCy: void 0,
|
|
95
|
-
id: void 0,
|
|
96
|
-
filter: {
|
|
97
|
-
has: void 0,
|
|
98
|
-
hasNot: void 0,
|
|
99
|
-
hasNotText: void 0,
|
|
100
|
-
hasText: void 0
|
|
101
|
-
},
|
|
102
|
-
locatorMethod: void 0,
|
|
103
|
-
locatorSchemaPath: void 0
|
|
104
|
-
};
|
|
105
|
-
function getLocatorSchemaDummy() {
|
|
106
|
-
return locatorSchemaDummy;
|
|
107
|
-
}
|
|
32
|
+
// src/fixture/base.fixtures.ts
|
|
33
|
+
var import_test = require("@playwright/test");
|
|
108
34
|
|
|
109
|
-
// src/helpers/
|
|
110
|
-
var
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (Array.isArray(maybeSharedLogEntries)) {
|
|
117
|
-
return maybeSharedLogEntries;
|
|
35
|
+
// src/helpers/playwrightReportLogger.ts
|
|
36
|
+
var PlaywrightReportLogger = class _PlaywrightReportLogger {
|
|
37
|
+
// Initializes the logger with shared log level, log entries, and a context name.
|
|
38
|
+
constructor(sharedLogLevel, sharedLogEntry, contextName) {
|
|
39
|
+
this.sharedLogLevel = sharedLogLevel;
|
|
40
|
+
this.sharedLogEntry = sharedLogEntry;
|
|
41
|
+
this.contextName = contextName;
|
|
118
42
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
logger?.warn(message);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// src/api/baseApi.ts
|
|
133
|
-
var BaseApi = class {
|
|
134
|
-
baseUrl;
|
|
135
|
-
apiName;
|
|
136
|
-
log;
|
|
137
|
-
request;
|
|
138
|
-
constructor(baseUrl, apiName, context, pwrl) {
|
|
139
|
-
this.baseUrl = baseUrl;
|
|
140
|
-
this.apiName = apiName;
|
|
141
|
-
this.log = pwrl.getNewChildLogger(apiName);
|
|
142
|
-
this.request = context;
|
|
143
|
-
const classDeprecationMessage = "[POMWright] BaseApi is depricated and will be removed in 2.0.0 with no replacement. If you need a base API class, you can use the v1 pomwright/src/api/baseApi.ts implementation for reference to implement your own.";
|
|
144
|
-
warnDeprecationOncePerTest(`${this.constructor.name}-class-deprecation`, classDeprecationMessage, this.log);
|
|
43
|
+
contextName;
|
|
44
|
+
logLevels = ["debug", "info", "warn", "error"];
|
|
45
|
+
/**
|
|
46
|
+
* Creates a child logger with a new contextual name, sharing the same log level and log entries with the parent logger.
|
|
47
|
+
*
|
|
48
|
+
* The root loggers log "level" is referenced by all child loggers and their child loggers and so on...
|
|
49
|
+
* Changing the log "level" of one, will change it for all.
|
|
50
|
+
*/
|
|
51
|
+
getNewChildLogger(prefix) {
|
|
52
|
+
return new _PlaywrightReportLogger(this.sharedLogLevel, this.sharedLogEntry, `${this.contextName} -> ${prefix}`);
|
|
145
53
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Logs a message with the specified log level, prefix, and additional arguments if the current log level permits.
|
|
56
|
+
*/
|
|
57
|
+
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
58
|
+
log(level, message, ...args) {
|
|
59
|
+
const logLevelIndex = this.logLevels.indexOf(level);
|
|
60
|
+
if (logLevelIndex < this.getCurrentLogLevelIndex()) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
this.sharedLogEntry.push({
|
|
64
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
65
|
+
logLevel: level,
|
|
66
|
+
prefix: this.contextName,
|
|
67
|
+
message: `${message}
|
|
153
68
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const json = JSON.stringify(path);
|
|
157
|
-
return json.slice(1, -1);
|
|
158
|
-
};
|
|
159
|
-
var RUNTIME_WHITESPACE_REGEX = /[\s\u0085]/u;
|
|
160
|
-
var validateLocatorSchemaPath = (path) => {
|
|
161
|
-
if (!path) {
|
|
162
|
-
throw new Error("LocatorSchemaPath string cannot be empty");
|
|
69
|
+
${args.join("\n\n")}`
|
|
70
|
+
});
|
|
163
71
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Logs a debug-level message with the specified message and arguments.
|
|
74
|
+
*/
|
|
75
|
+
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
76
|
+
debug(message, ...args) {
|
|
77
|
+
this.log("debug", message, ...args);
|
|
167
78
|
}
|
|
168
|
-
|
|
169
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Logs a info-level message with the specified message and arguments.
|
|
81
|
+
*/
|
|
82
|
+
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
83
|
+
info(message, ...args) {
|
|
84
|
+
this.log("info", message, ...args);
|
|
170
85
|
}
|
|
171
|
-
|
|
172
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Logs a warn-level message with the specified message and arguments.
|
|
88
|
+
*/
|
|
89
|
+
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
90
|
+
warn(message, ...args) {
|
|
91
|
+
this.log("warn", message, ...args);
|
|
173
92
|
}
|
|
174
|
-
|
|
175
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Logs a error-level message with the specified message and arguments.
|
|
95
|
+
*/
|
|
96
|
+
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
97
|
+
error(message, ...args) {
|
|
98
|
+
this.log("error", message, ...args);
|
|
176
99
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
};
|
|
183
|
-
var cssEscape = (value) => {
|
|
184
|
-
return value.replace(/([\\"'#.:;,?*+<>{}[\\]()])/g, "\\$1");
|
|
185
|
-
};
|
|
186
|
-
var normalizeSteps = (steps) => steps ? steps.map((step2) => ({ ...step2 })) : [];
|
|
187
|
-
function normalizeIdValue(id) {
|
|
188
|
-
if (typeof id !== "string") {
|
|
189
|
-
return id;
|
|
100
|
+
/**
|
|
101
|
+
* Sets the current log level to the specified level during runTime.
|
|
102
|
+
*/
|
|
103
|
+
setLogLevel(level) {
|
|
104
|
+
this.sharedLogLevel.current = level;
|
|
190
105
|
}
|
|
191
|
-
|
|
192
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Retrieves the current log level during runtime.
|
|
108
|
+
*/
|
|
109
|
+
getCurrentLogLevel() {
|
|
110
|
+
return this.sharedLogLevel.current;
|
|
193
111
|
}
|
|
194
|
-
|
|
195
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Retrieves the index of the current log level in the logLevels array during runtime.
|
|
114
|
+
*/
|
|
115
|
+
getCurrentLogLevelIndex() {
|
|
116
|
+
return this.logLevels.indexOf(this.sharedLogLevel.current);
|
|
196
117
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
value,
|
|
203
|
-
(_key, current) => {
|
|
204
|
-
if (typeof current === "object" && current !== null) {
|
|
205
|
-
if (seen.has(current)) {
|
|
206
|
-
return "[Circular]";
|
|
207
|
-
}
|
|
208
|
-
seen.add(current);
|
|
209
|
-
}
|
|
210
|
-
if (current instanceof RegExp) {
|
|
211
|
-
return { type: "RegExp", source: current.source, flags: current.flags };
|
|
212
|
-
}
|
|
213
|
-
return current;
|
|
214
|
-
},
|
|
215
|
-
2
|
|
216
|
-
);
|
|
217
|
-
};
|
|
218
|
-
var applyIndexSelector = (locator, selector) => {
|
|
219
|
-
if (selector === void 0 || selector === null) {
|
|
220
|
-
return locator;
|
|
118
|
+
/**
|
|
119
|
+
* Resets the current log level to the initial level during runtime.
|
|
120
|
+
*/
|
|
121
|
+
resetLogLevel() {
|
|
122
|
+
this.sharedLogLevel.current = this.sharedLogLevel.initial;
|
|
221
123
|
}
|
|
222
|
-
|
|
223
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Checks if the input log level is equal to the current log level of the PlaywrightReportLogger instance.
|
|
126
|
+
*/
|
|
127
|
+
isCurrentLogLevel(level) {
|
|
128
|
+
return this.sharedLogLevel.current === level;
|
|
224
129
|
}
|
|
225
|
-
|
|
226
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Returns 'true' if the "level" parameter provided has an equal or greater index than the current logLevel.
|
|
132
|
+
*/
|
|
133
|
+
isLogLevelEnabled(level) {
|
|
134
|
+
const logLevelIndex = this.logLevels.indexOf(level);
|
|
135
|
+
if (logLevelIndex < this.getCurrentLogLevelIndex()) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
227
139
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Attaches the recorded log entries to the Playwright HTML report in a sorted and formatted manner.
|
|
142
|
+
*/
|
|
143
|
+
attachLogsToTest(testInfo) {
|
|
144
|
+
this.sharedLogEntry.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
145
|
+
for (const log of this.sharedLogEntry) {
|
|
146
|
+
const printTime = log.timestamp.toLocaleTimeString("nb-NO", {
|
|
147
|
+
hour: "2-digit",
|
|
148
|
+
minute: "2-digit",
|
|
149
|
+
second: "2-digit"
|
|
150
|
+
});
|
|
151
|
+
const printDate = log.timestamp.toLocaleDateString("nb-NO", {
|
|
152
|
+
day: "2-digit",
|
|
153
|
+
month: "2-digit",
|
|
154
|
+
year: "numeric"
|
|
155
|
+
});
|
|
156
|
+
const printLogLevel = `${log.logLevel.toUpperCase()}`;
|
|
157
|
+
const printPrefix = log.prefix ? `: [${log.prefix}]` : "";
|
|
158
|
+
let messageBody = "";
|
|
159
|
+
let messageContentType = "";
|
|
160
|
+
try {
|
|
161
|
+
const parsedMessage = JSON.parse(log.message);
|
|
162
|
+
messageContentType = "application/json";
|
|
163
|
+
messageBody = JSON.stringify(parsedMessage, null, 2);
|
|
164
|
+
} catch (_error) {
|
|
165
|
+
messageContentType = "text/plain";
|
|
166
|
+
messageBody = log.message;
|
|
254
167
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
default: {
|
|
260
|
-
const exhaustive = definition;
|
|
261
|
-
return exhaustive;
|
|
168
|
+
testInfo.attach(`${printTime} ${printDate} - ${printLogLevel} ${printPrefix}`, {
|
|
169
|
+
contentType: messageContentType,
|
|
170
|
+
body: Buffer.from(messageBody)
|
|
171
|
+
});
|
|
262
172
|
}
|
|
263
173
|
}
|
|
264
174
|
};
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
text: definition.text,
|
|
277
|
-
...definition.options ? { options: { ...definition.options } } : {}
|
|
278
|
-
};
|
|
279
|
-
case "label":
|
|
280
|
-
return {
|
|
281
|
-
type: "label",
|
|
282
|
-
text: definition.text,
|
|
283
|
-
...definition.options ? { options: { ...definition.options } } : {}
|
|
284
|
-
};
|
|
285
|
-
case "placeholder":
|
|
286
|
-
return {
|
|
287
|
-
type: "placeholder",
|
|
288
|
-
text: definition.text,
|
|
289
|
-
...definition.options ? { options: { ...definition.options } } : {}
|
|
290
|
-
};
|
|
291
|
-
case "altText":
|
|
292
|
-
return {
|
|
293
|
-
type: "altText",
|
|
294
|
-
text: definition.text,
|
|
295
|
-
...definition.options ? { options: { ...definition.options } } : {}
|
|
296
|
-
};
|
|
297
|
-
case "title":
|
|
298
|
-
return {
|
|
299
|
-
type: "title",
|
|
300
|
-
text: definition.text,
|
|
301
|
-
...definition.options ? { options: { ...definition.options } } : {}
|
|
302
|
-
};
|
|
303
|
-
case "locator":
|
|
304
|
-
return {
|
|
305
|
-
type: "locator",
|
|
306
|
-
selector: definition.selector,
|
|
307
|
-
...definition.options ? { options: { ...definition.options } } : {}
|
|
308
|
-
};
|
|
309
|
-
case "frameLocator":
|
|
310
|
-
return { type: "frameLocator", selector: definition.selector };
|
|
311
|
-
case "testId":
|
|
312
|
-
return { type: "testId", testId: definition.testId };
|
|
313
|
-
case "id":
|
|
314
|
-
return { type: "id", id: definition.id };
|
|
315
|
-
default: {
|
|
316
|
-
const exhaustive = definition;
|
|
317
|
-
return exhaustive;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
var applyDefinitionPatch = (seed, patch) => {
|
|
322
|
-
const base2 = cloneLocatorStrategyDefinition(seed);
|
|
323
|
-
switch (patch.type) {
|
|
324
|
-
case "locator": {
|
|
325
|
-
const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
|
|
326
|
-
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
327
|
-
return { type: "locator", selector, ...options ? { options } : {} };
|
|
328
|
-
}
|
|
329
|
-
case "role": {
|
|
330
|
-
const role = patch.role ?? base2.role;
|
|
331
|
-
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
332
|
-
return { type: "role", role, ...options ? { options } : {} };
|
|
333
|
-
}
|
|
334
|
-
case "text": {
|
|
335
|
-
const text = patch.text ?? base2.text;
|
|
336
|
-
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
337
|
-
return { type: "text", text, ...options ? { options } : {} };
|
|
338
|
-
}
|
|
339
|
-
case "label": {
|
|
340
|
-
const text = patch.text ?? base2.text;
|
|
341
|
-
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
342
|
-
return { type: "label", text, ...options ? { options } : {} };
|
|
343
|
-
}
|
|
344
|
-
case "placeholder": {
|
|
345
|
-
const text = patch.text ?? base2.text;
|
|
346
|
-
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
347
|
-
return { type: "placeholder", text, ...options ? { options } : {} };
|
|
348
|
-
}
|
|
349
|
-
case "altText": {
|
|
350
|
-
const text = patch.text ?? base2.text;
|
|
351
|
-
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
352
|
-
return { type: "altText", text, ...options ? { options } : {} };
|
|
353
|
-
}
|
|
354
|
-
case "title": {
|
|
355
|
-
const text = patch.text ?? base2.text;
|
|
356
|
-
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
357
|
-
return { type: "title", text, ...options ? { options } : {} };
|
|
358
|
-
}
|
|
359
|
-
case "frameLocator": {
|
|
360
|
-
const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
|
|
361
|
-
return { type: "frameLocator", selector };
|
|
362
|
-
}
|
|
363
|
-
case "testId": {
|
|
364
|
-
const testId = patch.testId !== void 0 ? patch.testId : base2.testId;
|
|
365
|
-
return { type: "testId", testId };
|
|
366
|
-
}
|
|
367
|
-
case "id": {
|
|
368
|
-
const id = patch.id !== void 0 ? normalizeIdValue(patch.id) ?? base2.id : base2.id;
|
|
369
|
-
return { type: "id", id };
|
|
370
|
-
}
|
|
371
|
-
default: {
|
|
372
|
-
const exhaustive = patch;
|
|
373
|
-
return exhaustive;
|
|
374
|
-
}
|
|
175
|
+
|
|
176
|
+
// src/fixture/base.fixtures.ts
|
|
177
|
+
var test = import_test.test.extend({
|
|
178
|
+
// biome-ignore lint/correctness/noEmptyPattern: Playwright does not support the use of _
|
|
179
|
+
log: async ({}, use, testInfo) => {
|
|
180
|
+
const contextName = "TestCase";
|
|
181
|
+
const sharedLogEntry = [];
|
|
182
|
+
const sharedLogLevel = testInfo.retry === 0 ? { current: "warn", initial: "warn" } : { current: "debug", initial: "debug" };
|
|
183
|
+
const log = new PlaywrightReportLogger(sharedLogLevel, sharedLogEntry, contextName);
|
|
184
|
+
await use(log);
|
|
185
|
+
log.attachLogsToTest(testInfo);
|
|
375
186
|
}
|
|
376
|
-
};
|
|
377
|
-
var isFrameLocatorDefinition = (definition) => definition.type === "frameLocator";
|
|
378
|
-
var isLocatorInstance = (value) => {
|
|
379
|
-
return !!value && typeof value === "object" && typeof value.filter === "function";
|
|
380
|
-
};
|
|
187
|
+
});
|
|
381
188
|
|
|
382
|
-
//
|
|
383
|
-
var
|
|
384
|
-
var
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
var logLocatorInstanceWarning = (path) => {
|
|
390
|
-
console.warn(
|
|
391
|
-
`[POMWright] Skipping v2 translation for "${path}" because v1 LocatorSchema.locator is a Locator instance. Rewrite this path in defineLocators() to avoid runtime gaps during migration.`
|
|
392
|
-
);
|
|
393
|
-
};
|
|
394
|
-
var addV1SchemaToV2Registry = (registry, locatorSchema) => {
|
|
395
|
-
const path = locatorSchema.locatorSchemaPath;
|
|
396
|
-
validateLocatorSchemaPath(path);
|
|
397
|
-
const registryWithLookup = getRegistryLookup(registry);
|
|
398
|
-
const existing = registryWithLookup.getIfExists?.(path);
|
|
399
|
-
if (existing) {
|
|
400
|
-
return;
|
|
189
|
+
// src/helpers/sessionStorage.ts
|
|
190
|
+
var import_test2 = require("@playwright/test");
|
|
191
|
+
var SessionStorage = class {
|
|
192
|
+
// Initializes the class with a Playwright Page object and an optional label for step titles.
|
|
193
|
+
constructor(page, options = {}) {
|
|
194
|
+
this.page = page;
|
|
195
|
+
this.options = options;
|
|
401
196
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
case "text" /* text */: {
|
|
420
|
-
if (!locatorSchema.text) {
|
|
421
|
-
logMissingDefinition(path, "text");
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
postDefinition = registration.getByText(locatorSchema.text, locatorSchema.textOptions);
|
|
425
|
-
break;
|
|
426
|
-
}
|
|
427
|
-
case "label" /* label */: {
|
|
428
|
-
if (!locatorSchema.label) {
|
|
429
|
-
logMissingDefinition(path, "label");
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
postDefinition = registration.getByLabel(locatorSchema.label, locatorSchema.labelOptions);
|
|
433
|
-
break;
|
|
434
|
-
}
|
|
435
|
-
case "placeholder" /* placeholder */: {
|
|
436
|
-
if (!locatorSchema.placeholder) {
|
|
437
|
-
logMissingDefinition(path, "placeholder");
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
postDefinition = registration.getByPlaceholder(locatorSchema.placeholder, locatorSchema.placeholderOptions);
|
|
441
|
-
break;
|
|
442
|
-
}
|
|
443
|
-
case "altText" /* altText */: {
|
|
444
|
-
if (!locatorSchema.altText) {
|
|
445
|
-
logMissingDefinition(path, "altText");
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
postDefinition = registration.getByAltText(locatorSchema.altText, locatorSchema.altTextOptions);
|
|
449
|
-
break;
|
|
450
|
-
}
|
|
451
|
-
case "title" /* title */: {
|
|
452
|
-
if (!locatorSchema.title) {
|
|
453
|
-
logMissingDefinition(path, "title");
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
postDefinition = registration.getByTitle(locatorSchema.title, locatorSchema.titleOptions);
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
case "locator" /* locator */: {
|
|
460
|
-
if (!locatorSchema.locator) {
|
|
461
|
-
logMissingDefinition(path, "locator");
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
if (isLocatorInstance(locatorSchema.locator)) {
|
|
465
|
-
logLocatorInstanceWarning(path);
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
postDefinition = registration.locator(locatorSchema.locator, locatorSchema.locatorOptions);
|
|
469
|
-
break;
|
|
470
|
-
}
|
|
471
|
-
case "frameLocator" /* frameLocator */: {
|
|
472
|
-
if (!locatorSchema.frameLocator) {
|
|
473
|
-
logMissingDefinition(path, "frameLocator");
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
postDefinition = registration.frameLocator(locatorSchema.frameLocator);
|
|
477
|
-
break;
|
|
478
|
-
}
|
|
479
|
-
case "testId" /* testId */: {
|
|
480
|
-
if (!locatorSchema.testId) {
|
|
481
|
-
logMissingDefinition(path, "testId");
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
postDefinition = registration.getByTestId(locatorSchema.testId);
|
|
485
|
-
break;
|
|
486
|
-
}
|
|
487
|
-
case "dataCy" /* dataCy */: {
|
|
488
|
-
if (!locatorSchema.dataCy) {
|
|
489
|
-
logMissingDefinition(path, "dataCy");
|
|
197
|
+
// Defines an object to hold states to be set in session storage, allowing any value type.
|
|
198
|
+
queuedStates = {};
|
|
199
|
+
// Indicates if the session storage manipulation has been initiated.
|
|
200
|
+
isInitiated = false;
|
|
201
|
+
getStepLabel(methodName) {
|
|
202
|
+
const prefix = this.options.label ? `${this.options.label}.` : "";
|
|
203
|
+
return `${prefix}SessionStorage.${methodName}:`;
|
|
204
|
+
}
|
|
205
|
+
async hasContext() {
|
|
206
|
+
return await this.page.evaluate(() => {
|
|
207
|
+
return typeof window !== "undefined" && window.sessionStorage !== void 0;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async waitForContextAvailability() {
|
|
211
|
+
try {
|
|
212
|
+
const contextExists = await this.hasContext();
|
|
213
|
+
if (contextExists) {
|
|
490
214
|
return;
|
|
491
215
|
}
|
|
492
|
-
|
|
493
|
-
break;
|
|
216
|
+
} catch (_e) {
|
|
494
217
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
218
|
+
await new Promise((resolve) => {
|
|
219
|
+
const handler = async (frame) => {
|
|
220
|
+
if (frame !== this.page.mainFrame()) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const contextExists = await this.hasContext();
|
|
225
|
+
if (!contextExists) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
} catch (_e) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.page.off("framenavigated", handler);
|
|
232
|
+
resolve();
|
|
233
|
+
};
|
|
234
|
+
this.page.on("framenavigated", handler);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
async ensureContext({ waitForContext = false } = {}) {
|
|
238
|
+
try {
|
|
239
|
+
const contextExists = await this.hasContext();
|
|
240
|
+
if (contextExists) {
|
|
498
241
|
return;
|
|
499
242
|
}
|
|
500
|
-
|
|
501
|
-
break;
|
|
243
|
+
} catch (_e) {
|
|
502
244
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
return exhaustive;
|
|
245
|
+
if (!waitForContext) {
|
|
246
|
+
throw new Error("SessionStorage context is not available.");
|
|
506
247
|
}
|
|
248
|
+
await this.waitForContextAvailability();
|
|
507
249
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
250
|
+
/** Writes states to session storage. Accepts an object with key-value pairs representing the states. */
|
|
251
|
+
async writeToSessionStorage(states) {
|
|
252
|
+
await this.page.evaluate((storage) => {
|
|
253
|
+
for (const [key, value] of Object.entries(storage)) {
|
|
254
|
+
window.sessionStorage.setItem(key, JSON.stringify(value));
|
|
255
|
+
}
|
|
256
|
+
}, states);
|
|
514
257
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
["id" /* id */]: this.id
|
|
534
|
-
};
|
|
535
|
-
this.subMethodMap = {
|
|
536
|
-
["role" /* role */]: this.page.getByRole,
|
|
537
|
-
["text" /* text */]: this.page.getByText,
|
|
538
|
-
["label" /* label */]: this.page.getByLabel,
|
|
539
|
-
["placeholder" /* placeholder */]: this.page.getByPlaceholder,
|
|
540
|
-
["altText" /* altText */]: this.page.getByAltText,
|
|
541
|
-
["title" /* title */]: this.page.getByTitle,
|
|
542
|
-
["locator" /* locator */]: this.page.locator
|
|
543
|
-
};
|
|
258
|
+
/** Reads all states from session storage and returns them as an object. */
|
|
259
|
+
async readFromSessionStorage() {
|
|
260
|
+
const storage = await this.page.evaluate(() => {
|
|
261
|
+
const storage2 = {};
|
|
262
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
263
|
+
const key = sessionStorage.key(i);
|
|
264
|
+
if (key !== null) {
|
|
265
|
+
const item = sessionStorage.getItem(key);
|
|
266
|
+
try {
|
|
267
|
+
storage2[key] = item ? JSON.parse(item) : null;
|
|
268
|
+
} catch (_e) {
|
|
269
|
+
storage2[key] = item;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return storage2;
|
|
274
|
+
});
|
|
275
|
+
return storage;
|
|
544
276
|
}
|
|
545
|
-
log;
|
|
546
|
-
methodMap;
|
|
547
|
-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
548
|
-
subMethodMap;
|
|
549
|
-
/**
|
|
550
|
-
* Retrieves a Locator based on the details provided in a LocatorSchema.
|
|
551
|
-
* The method identifies the appropriate locator creation function from methodMap and invokes it.
|
|
552
|
-
* Throws an error if the locator method is unsupported.
|
|
553
|
-
*/
|
|
554
|
-
getLocator = (locatorSchema) => {
|
|
555
|
-
const methodName = locatorSchema.locatorMethod;
|
|
556
|
-
const method = this.methodMap[methodName];
|
|
557
|
-
if (method) {
|
|
558
|
-
return method(locatorSchema);
|
|
559
|
-
}
|
|
560
|
-
throw new Error(`Unsupported locator method: ${methodName}`);
|
|
561
|
-
};
|
|
562
277
|
/**
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
278
|
+
* Sets the specified states in session storage.
|
|
279
|
+
* Optionally waits for the next main-frame navigation to establish a valid context before writing,
|
|
280
|
+
* and reloads the page after setting the data.
|
|
281
|
+
*
|
|
282
|
+
* Parameters:
|
|
283
|
+
* states: Object representing the states to set in session storage.
|
|
284
|
+
* reload: Boolean indicating whether to reload the page after setting the session storage data.
|
|
285
|
+
* waitForContext: Boolean indicating whether to wait for a main-frame navigation and a valid context.
|
|
566
286
|
*/
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
const errorText = `Locator "${locator.locatorSchemaPath}" .${caller} is undefined.`;
|
|
577
|
-
this.log.warn(errorText);
|
|
578
|
-
throw new Error(errorText);
|
|
579
|
-
}
|
|
580
|
-
return initialPWLocator;
|
|
581
|
-
};
|
|
287
|
+
async set(states, options = {}) {
|
|
288
|
+
await import_test2.test.step(this.getStepLabel("set"), async () => {
|
|
289
|
+
await this.ensureContext({ waitForContext: options.waitForContext });
|
|
290
|
+
await this.writeToSessionStorage(states);
|
|
291
|
+
if (options.reload) {
|
|
292
|
+
await this.page.reload();
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
582
296
|
/**
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
297
|
+
* Queues states to be set in the sessionStorage before the next navigation occurs.
|
|
298
|
+
* Handles different scenarios based on multiple calls made before the navigation occurs.
|
|
299
|
+
*
|
|
300
|
+
* 1. No Context, Single Call: Queues and sets states upon the next navigation.
|
|
301
|
+
* 2. No Context, Multiple Calls: Merges states from multiple calls and sets them upon the next navigation.
|
|
302
|
+
* 3. With Context: Still queues until the next navigation.
|
|
303
|
+
*
|
|
304
|
+
* Parameters:
|
|
305
|
+
* states: Object representing the states to queue for setting in session storage.
|
|
586
306
|
*/
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
307
|
+
async setOnNextNavigation(states) {
|
|
308
|
+
this.queuedStates = { ...this.queuedStates, ...states };
|
|
309
|
+
const populateStorage = async () => {
|
|
310
|
+
await import_test2.test.step(this.getStepLabel("setOnNextNavigation"), async () => {
|
|
311
|
+
await this.writeToSessionStorage(this.queuedStates);
|
|
312
|
+
});
|
|
313
|
+
this.queuedStates = {};
|
|
590
314
|
};
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
locator = this.createByMethod("locator" /* locator */);
|
|
603
|
-
/**
|
|
604
|
-
* Returns a FrameLocator using the 'frameLocator' selector from a LocatorSchema.
|
|
605
|
-
* Throws an error if the frameLocator is not defined.
|
|
606
|
-
*/
|
|
607
|
-
frameLocator = (locatorSchema) => {
|
|
608
|
-
const initialFrameLocator = locatorSchema.frameLocator ? this.page.frameLocator(locatorSchema.frameLocator) : null;
|
|
609
|
-
if (!initialFrameLocator) {
|
|
610
|
-
const errorText = `Locator "${locatorSchema.locatorSchemaPath}" .frameLocator is not defined.`;
|
|
611
|
-
this.log.warn(errorText);
|
|
612
|
-
throw new Error(errorText);
|
|
613
|
-
}
|
|
614
|
-
return initialFrameLocator;
|
|
615
|
-
};
|
|
616
|
-
/**
|
|
617
|
-
* Returns a Locator using the 'testId' selector from a LocatorSchema.
|
|
618
|
-
* Throws an error if the testId is not defined.
|
|
619
|
-
*/
|
|
620
|
-
testId = (locator) => {
|
|
621
|
-
const initialPWLocator = locator.testId ? this.page.getByTestId(locator.testId) : null;
|
|
622
|
-
if (!initialPWLocator) {
|
|
623
|
-
const errorText = `Locator "${locator.locatorSchemaPath}" .testId is not defined.`;
|
|
624
|
-
this.log.warn(`Locator "${locator.locatorSchemaPath}" .testId is not defined.`);
|
|
625
|
-
throw new Error(errorText);
|
|
626
|
-
}
|
|
627
|
-
return initialPWLocator;
|
|
628
|
-
};
|
|
629
|
-
/**
|
|
630
|
-
* Returns a Locator using the 'dataCy' selector from a LocatorSchema.
|
|
631
|
-
* Throws an error if the dataCy is undefined.
|
|
632
|
-
*/
|
|
633
|
-
dataCy = (locator) => {
|
|
634
|
-
let initialPWLocator = null;
|
|
635
|
-
if (locator.dataCy) {
|
|
636
|
-
initialPWLocator = locator.dataCy.startsWith("data-cy=") ? this.page.locator(locator.dataCy) : this.page.locator(`data-cy=${locator.dataCy}`);
|
|
637
|
-
} else {
|
|
638
|
-
const errorText = `Locator "${locator.locatorSchemaPath}" .dataCy is undefined.`;
|
|
639
|
-
this.log.warn(errorText);
|
|
640
|
-
throw new Error(errorText);
|
|
315
|
+
if (!this.isInitiated) {
|
|
316
|
+
this.isInitiated = true;
|
|
317
|
+
const handler = async (frame) => {
|
|
318
|
+
if (frame !== this.page.mainFrame()) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
await populateStorage();
|
|
322
|
+
this.page.off("framenavigated", handler);
|
|
323
|
+
this.isInitiated = false;
|
|
324
|
+
};
|
|
325
|
+
this.page.on("framenavigated", handler);
|
|
641
326
|
}
|
|
642
|
-
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
if (typeof locator.id === "string") {
|
|
658
|
-
if (locator.id.startsWith("#")) {
|
|
659
|
-
selector = locator.id;
|
|
660
|
-
} else if (locator.id.startsWith("id=")) {
|
|
661
|
-
selector = `#${locator.id.slice("id=".length)}`;
|
|
327
|
+
}
|
|
328
|
+
async get(keys, options = {}) {
|
|
329
|
+
let result = {};
|
|
330
|
+
await import_test2.test.step(this.getStepLabel("get"), async () => {
|
|
331
|
+
await this.ensureContext(options);
|
|
332
|
+
const allData = await this.readFromSessionStorage();
|
|
333
|
+
if (keys && keys.length > 0) {
|
|
334
|
+
for (const key of keys) {
|
|
335
|
+
if (Object.hasOwn(allData, key)) {
|
|
336
|
+
const value = allData[key];
|
|
337
|
+
if (value !== void 0) {
|
|
338
|
+
result[key] = value;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
662
342
|
} else {
|
|
663
|
-
|
|
343
|
+
result = allData;
|
|
664
344
|
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
initialPWLocator = this.page.locator(selector);
|
|
674
|
-
return initialPWLocator;
|
|
675
|
-
};
|
|
676
|
-
};
|
|
677
|
-
|
|
678
|
-
// src/helpers/getLocatorBase.ts
|
|
679
|
-
var REQUIRED_PROPERTIES_FOR_LOCATOR_SCHEMA_WITH_METHODS = [
|
|
680
|
-
"update",
|
|
681
|
-
"addFilter",
|
|
682
|
-
"getNestedLocator",
|
|
683
|
-
"getLocator",
|
|
684
|
-
"locatorSchemaPath",
|
|
685
|
-
"locatorMethod",
|
|
686
|
-
"schemasMap",
|
|
687
|
-
"filterMap"
|
|
688
|
-
];
|
|
689
|
-
var safeStringifyOfNestedLocatorResults = (obj) => {
|
|
690
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
691
|
-
return JSON.stringify(
|
|
692
|
-
obj,
|
|
693
|
-
(key, value) => {
|
|
694
|
-
if (value instanceof Map) {
|
|
695
|
-
return Array.from(value.entries());
|
|
345
|
+
});
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
async clear(keyOrOptions, options = {}) {
|
|
349
|
+
const { keys, waitForContext } = (() => {
|
|
350
|
+
if (Array.isArray(keyOrOptions)) {
|
|
351
|
+
return { keys: keyOrOptions, waitForContext: options.waitForContext };
|
|
696
352
|
}
|
|
697
|
-
if (
|
|
698
|
-
return {
|
|
353
|
+
if (typeof keyOrOptions === "string") {
|
|
354
|
+
return { keys: [keyOrOptions], waitForContext: options.waitForContext };
|
|
699
355
|
}
|
|
700
|
-
if (
|
|
701
|
-
return {
|
|
356
|
+
if (keyOrOptions) {
|
|
357
|
+
return { keys: void 0, waitForContext: keyOrOptions.waitForContext };
|
|
702
358
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
359
|
+
return { keys: void 0, waitForContext: options.waitForContext };
|
|
360
|
+
})();
|
|
361
|
+
await import_test2.test.step(this.getStepLabel("clear"), async () => {
|
|
362
|
+
await this.ensureContext({ waitForContext });
|
|
363
|
+
if (!keys || keys.length === 0) {
|
|
364
|
+
await this.page.evaluate(() => sessionStorage.clear());
|
|
365
|
+
return;
|
|
706
366
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
367
|
+
await this.page.evaluate((keysToClear) => {
|
|
368
|
+
for (const key of keysToClear) {
|
|
369
|
+
sessionStorage.removeItem(key);
|
|
370
|
+
}
|
|
371
|
+
}, keys);
|
|
372
|
+
});
|
|
373
|
+
}
|
|
711
374
|
};
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
locatorSchemaCopy.schemasMap = schemasMap;
|
|
734
|
-
locatorSchemaCopy.filterMap = /* @__PURE__ */ new Map();
|
|
735
|
-
const wrapper = new WithMethodsClass(
|
|
736
|
-
this.pageObjectClass,
|
|
737
|
-
this.log,
|
|
738
|
-
locatorSchemaPath,
|
|
739
|
-
schemasMap
|
|
740
|
-
);
|
|
741
|
-
return wrapper.init(locatorSchemaPath, locatorSchemaCopy);
|
|
375
|
+
|
|
376
|
+
// src/helpers/stepDecorator.ts
|
|
377
|
+
var import_test3 = require("@playwright/test");
|
|
378
|
+
var isMethodDecoratorArgs = (args) => args.length === 3 && typeof args[0] === "object" && (typeof args[1] === "string" || typeof args[1] === "symbol");
|
|
379
|
+
var isStage3MethodDecoratorArgs = (args) => args.length === 2 && typeof args[0] === "function" && args[1] !== null && typeof args[1] === "object";
|
|
380
|
+
var normalizeStepArguments = (args) => {
|
|
381
|
+
const [titleOrOptions, maybeOptions] = args;
|
|
382
|
+
const title = typeof titleOrOptions === "string" ? titleOrOptions : void 0;
|
|
383
|
+
const options = typeof titleOrOptions === "string" ? maybeOptions : titleOrOptions;
|
|
384
|
+
return { title, options };
|
|
385
|
+
};
|
|
386
|
+
var createWrappedMethod = (original, methodName, title, options) => function(...methodArgs) {
|
|
387
|
+
const rawClassName = this.constructor?.name ?? "";
|
|
388
|
+
const className = rawClassName && rawClassName !== "Object" ? rawClassName : "Anonymous";
|
|
389
|
+
const resolvedTitle = title ?? `${className}.${String(methodName)}`;
|
|
390
|
+
return import_test3.test.step(resolvedTitle, () => original.apply(this, methodArgs), options);
|
|
391
|
+
};
|
|
392
|
+
var createStepDecorator = ({ title, options }) => (valueOrTarget, contextOrKey, descriptor) => {
|
|
393
|
+
if (typeof valueOrTarget === "function" && isStage3MethodDecoratorArgs([valueOrTarget, contextOrKey])) {
|
|
394
|
+
const [original2, context] = [valueOrTarget, contextOrKey];
|
|
395
|
+
return createWrappedMethod(original2, context.name, title, options);
|
|
742
396
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
* Clones and stores all schemas related to the chosen path and its sub-paths.
|
|
746
|
-
* Ensures updates and filters don't affect original schema definitions.
|
|
747
|
-
*/
|
|
748
|
-
collectDeepCopies(locatorSchemaPath, pathIndexPairs) {
|
|
749
|
-
const schemasMap = /* @__PURE__ */ new Map();
|
|
750
|
-
const fullSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
|
|
751
|
-
if (!fullSchemaFunc) {
|
|
752
|
-
const errorMessage = `LocatorSchema not found for path: '${locatorSchemaPath}'`;
|
|
753
|
-
this.log.error(errorMessage);
|
|
754
|
-
throw new Error(`[${this.pageObjectClass.pocName}] ${errorMessage}`);
|
|
755
|
-
}
|
|
756
|
-
schemasMap.set(locatorSchemaPath, structuredClone(fullSchemaFunc()));
|
|
757
|
-
for (const { path } of pathIndexPairs) {
|
|
758
|
-
if (path !== locatorSchemaPath) {
|
|
759
|
-
const schemaFunc = this.safeGetLocatorSchema(path);
|
|
760
|
-
if (schemaFunc) {
|
|
761
|
-
schemasMap.set(path, structuredClone(schemaFunc()));
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
return schemasMap;
|
|
397
|
+
if (!descriptor || typeof descriptor.value !== "function") {
|
|
398
|
+
throw new Error("@step decorator can only be applied to methods.");
|
|
766
399
|
}
|
|
767
|
-
|
|
768
|
-
|
|
400
|
+
const original = descriptor.value;
|
|
401
|
+
descriptor.value = createWrappedMethod(original, contextOrKey, title, options);
|
|
402
|
+
return descriptor;
|
|
403
|
+
};
|
|
404
|
+
function step(...args) {
|
|
405
|
+
if (isStage3MethodDecoratorArgs(args)) {
|
|
406
|
+
return createStepDecorator(normalizeStepArguments([]))(...args);
|
|
769
407
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
* Applies updates to a specific sub-path schema within schemasMap.
|
|
773
|
-
* Similar to applyUpdate, but we locate the sub-path schema directly by its path.
|
|
774
|
-
*/
|
|
775
|
-
applyUpdateToSubPath(schemasMap, subPath, updates) {
|
|
776
|
-
const schema = schemasMap.get(subPath);
|
|
777
|
-
if (!schema) {
|
|
778
|
-
throw new Error(`No schema found for sub-path: '${subPath}'`);
|
|
779
|
-
}
|
|
780
|
-
const updatedSchema = this.deepMerge(schema, updates);
|
|
781
|
-
if (this.isLocatorSchemaWithMethods(schema)) {
|
|
782
|
-
Object.assign(schema, updatedSchema);
|
|
783
|
-
} else {
|
|
784
|
-
schemasMap.set(subPath, updatedSchema);
|
|
785
|
-
}
|
|
408
|
+
if (isMethodDecoratorArgs(args)) {
|
|
409
|
+
return createStepDecorator(normalizeStepArguments([]))(...args);
|
|
786
410
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
411
|
+
return createStepDecorator(normalizeStepArguments(args));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/locators/utils.ts
|
|
415
|
+
var formatLocatorSchemaPathForError = (path) => {
|
|
416
|
+
const json = JSON.stringify(path);
|
|
417
|
+
return json.slice(1, -1);
|
|
418
|
+
};
|
|
419
|
+
var RUNTIME_WHITESPACE_REGEX = /[\s\u0085]/u;
|
|
420
|
+
var validateLocatorSchemaPath = (path) => {
|
|
421
|
+
if (!path) {
|
|
422
|
+
throw new Error("LocatorSchemaPath string cannot be empty");
|
|
794
423
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
* Throws an error if a schema already exists at that path.
|
|
799
|
-
*/
|
|
800
|
-
addSchema(locatorSchemaPath, schemaDetails) {
|
|
801
|
-
if (locatorSchemaPath.length === 0 || locatorSchemaPath.startsWith(".") || locatorSchemaPath.endsWith(".") || locatorSchemaPath.includes("..")) {
|
|
802
|
-
throw new Error(
|
|
803
|
-
`[${this.pageObjectClass.pocName}] Invalid LocatorSchemaPath '${locatorSchemaPath}'. LocatorSchemaPath must not be empty, start or end with a '.', or contain consecutive '.'.`
|
|
804
|
-
);
|
|
805
|
-
}
|
|
806
|
-
const newLocatorSchema = this.createLocatorSchema(schemaDetails, locatorSchemaPath);
|
|
807
|
-
const existingSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
|
|
808
|
-
if (existingSchemaFunc) {
|
|
809
|
-
const existingLocatorSchema = existingSchemaFunc();
|
|
810
|
-
throw new Error(
|
|
811
|
-
`[${this.pageObjectClass.pocName}] A LocatorSchema with the path '${locatorSchemaPath}' already exists.
|
|
812
|
-
Existing Schema: ${JSON.stringify(existingLocatorSchema, null, 2)}
|
|
813
|
-
Attempted to Add Schema: ${JSON.stringify(newLocatorSchema, null, 2)}`
|
|
814
|
-
);
|
|
815
|
-
}
|
|
816
|
-
this.locatorSchemas.set(locatorSchemaPath, () => newLocatorSchema);
|
|
817
|
-
const v2Registry = this.pageObjectClass.locatorRegistry;
|
|
818
|
-
if (v2Registry) {
|
|
819
|
-
addV1SchemaToV2Registry(v2Registry, newLocatorSchema);
|
|
820
|
-
}
|
|
424
|
+
if (RUNTIME_WHITESPACE_REGEX.test(path)) {
|
|
425
|
+
const escaped = formatLocatorSchemaPathForError(path);
|
|
426
|
+
throw new Error(`LocatorSchemaPath string cannot contain whitespace chars: ${escaped}`);
|
|
821
427
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
* Safely retrieves a schema function if available for the given path.
|
|
825
|
-
*/
|
|
826
|
-
safeGetLocatorSchema(path) {
|
|
827
|
-
return this.locatorSchemas.get(path);
|
|
428
|
+
if (path.startsWith(".")) {
|
|
429
|
+
throw new Error(`LocatorSchemaPath string cannot start with a dot: ${path}`);
|
|
828
430
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
* Splits a path into incremental sub-paths and associates them with optional indices.
|
|
832
|
-
* Used by getNestedLocator methods.
|
|
833
|
-
*/
|
|
834
|
-
extractPathsFromSchema = (paths, indices = {}) => {
|
|
835
|
-
const schemaParts = paths.split(".");
|
|
836
|
-
let cumulativePath = "";
|
|
837
|
-
return schemaParts.map((part, index) => {
|
|
838
|
-
cumulativePath = cumulativePath ? `${cumulativePath}.${part}` : part;
|
|
839
|
-
return {
|
|
840
|
-
path: cumulativePath,
|
|
841
|
-
index: indices[index] ?? void 0
|
|
842
|
-
};
|
|
843
|
-
});
|
|
844
|
-
};
|
|
845
|
-
/**
|
|
846
|
-
* logError:
|
|
847
|
-
* Logs detailed error information and re-throws the error to ensure tests fail as expected.
|
|
848
|
-
*/
|
|
849
|
-
logError = (error, locatorSchemaPath, currentLocator, currentPath, pathIndexPairs, nestedLocatorResults) => {
|
|
850
|
-
const errorDetails = {
|
|
851
|
-
error: error.message,
|
|
852
|
-
locatorSchemaPath,
|
|
853
|
-
currentPath,
|
|
854
|
-
pathIndexPairs: JSON.stringify(pathIndexPairs, null, 2),
|
|
855
|
-
currentLocatorDetails: currentLocator ? {
|
|
856
|
-
locatorString: currentLocator,
|
|
857
|
-
isNotNull: true
|
|
858
|
-
} : { isNotNull: false },
|
|
859
|
-
nestedLocatorResults: safeStringifyOfNestedLocatorResults(nestedLocatorResults)
|
|
860
|
-
};
|
|
861
|
-
this.log.error(
|
|
862
|
-
"An error occurred during nested locator construction.\n",
|
|
863
|
-
"Error details:\n",
|
|
864
|
-
JSON.stringify(errorDetails, null, 2)
|
|
865
|
-
);
|
|
866
|
-
throw error;
|
|
867
|
-
};
|
|
868
|
-
/**
|
|
869
|
-
* deepMerge:
|
|
870
|
-
* Recursively merges source properties into target, validating them against LocatorSchema to ensure no invalid keys.
|
|
871
|
-
* Ensures immutability by creating a new object rather than modifying in place.
|
|
872
|
-
*/
|
|
873
|
-
deepMerge(target, source, schema = getLocatorSchemaDummy()) {
|
|
874
|
-
const merged = { ...target };
|
|
875
|
-
for (const key of Object.keys(source)) {
|
|
876
|
-
if (key === "locatorSchemaPath") {
|
|
877
|
-
throw new Error(
|
|
878
|
-
`[${this.pageObjectClass.pocName}] Invalid property: 'locatorSchemaPath' cannot be updated. Attempted to update LocatorSchemaPath from '${target[key]}' to '${source[key]}'.`
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
if (!(key in schema)) {
|
|
882
|
-
throw new Error(`Invalid property: '${key}' is not a valid property of LocatorSchema`);
|
|
883
|
-
}
|
|
884
|
-
const sourceValue = source[key];
|
|
885
|
-
const targetValue = target[key];
|
|
886
|
-
if (typeof sourceValue === "object" && sourceValue !== null && schema[key] && typeof schema[key] === "object") {
|
|
887
|
-
if (targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
888
|
-
merged[key] = this.deepMerge(
|
|
889
|
-
targetValue,
|
|
890
|
-
// Updated type here
|
|
891
|
-
sourceValue,
|
|
892
|
-
schema[key]
|
|
893
|
-
);
|
|
894
|
-
} else {
|
|
895
|
-
merged[key] = this.deepMerge(
|
|
896
|
-
{},
|
|
897
|
-
sourceValue,
|
|
898
|
-
schema[key]
|
|
899
|
-
);
|
|
900
|
-
}
|
|
901
|
-
} else {
|
|
902
|
-
if (Array.isArray(sourceValue)) {
|
|
903
|
-
merged[key] = Array.isArray(targetValue) ? targetValue.concat(sourceValue) : [...sourceValue];
|
|
904
|
-
} else if (typeof sourceValue === "object" && sourceValue !== null && Object.prototype.toString.call(sourceValue) === "[object RegExp]") {
|
|
905
|
-
merged[key] = new RegExp(
|
|
906
|
-
sourceValue.source,
|
|
907
|
-
sourceValue.flags
|
|
908
|
-
);
|
|
909
|
-
} else {
|
|
910
|
-
merged[key] = sourceValue;
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
return merged;
|
|
431
|
+
if (path.endsWith(".")) {
|
|
432
|
+
throw new Error(`LocatorSchemaPath string cannot end with a dot: ${path}`);
|
|
915
433
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
* Constructs a nested locator by iterating through each sub-path of locatorSchemaPath and chaining locators.
|
|
919
|
-
* Applies filters, indexing (nth), and logs details for debugging during test retries.
|
|
920
|
-
*/
|
|
921
|
-
buildNestedLocator = async (locatorSchemaPath, schemasMap, filterMap, indices = {}) => {
|
|
922
|
-
return await import_test.test.step(`${this.pageObjectClass.pocName}: Build Nested Locator`, async () => {
|
|
923
|
-
const pathIndexPairs = this.extractPathsFromSchema(locatorSchemaPath, indices);
|
|
924
|
-
let currentLocator = null;
|
|
925
|
-
let currentIFrame = null;
|
|
926
|
-
const nestedLocatorResults = {
|
|
927
|
-
LocatorSchema: null,
|
|
928
|
-
NestingSteps: []
|
|
929
|
-
};
|
|
930
|
-
for (const { path, index } of pathIndexPairs) {
|
|
931
|
-
const currentSchema = schemasMap.get(path);
|
|
932
|
-
if (!currentSchema) continue;
|
|
933
|
-
try {
|
|
934
|
-
const nextLocator = this.getBy.getLocator(currentSchema);
|
|
935
|
-
currentLocator = currentLocator ? currentLocator.locator(nextLocator) : nextLocator;
|
|
936
|
-
if (currentSchema.locatorMethod !== "frameLocator" /* frameLocator */ && currentSchema.filter) {
|
|
937
|
-
currentLocator = currentLocator.filter({
|
|
938
|
-
has: currentSchema.filter.has,
|
|
939
|
-
hasNot: currentSchema.filter.hasNot,
|
|
940
|
-
hasNotText: currentSchema.filter.hasNotText,
|
|
941
|
-
hasText: currentSchema.filter.hasText
|
|
942
|
-
});
|
|
943
|
-
}
|
|
944
|
-
const filterEntries = filterMap.get(path);
|
|
945
|
-
if (filterEntries) {
|
|
946
|
-
for (const filterData of filterEntries) {
|
|
947
|
-
currentLocator = currentLocator.filter({
|
|
948
|
-
has: filterData.has,
|
|
949
|
-
hasNot: filterData.hasNot,
|
|
950
|
-
hasNotText: filterData.hasNotText,
|
|
951
|
-
hasText: filterData.hasText
|
|
952
|
-
});
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
if (index != null) {
|
|
956
|
-
currentLocator = currentLocator.nth(index);
|
|
957
|
-
}
|
|
958
|
-
if (this.log.isLogLevelEnabled("debug")) {
|
|
959
|
-
if (!nestedLocatorResults.LocatorSchema) {
|
|
960
|
-
const schemaFromMap = schemasMap.get(locatorSchemaPath);
|
|
961
|
-
if (schemaFromMap) {
|
|
962
|
-
nestedLocatorResults.LocatorSchema = schemaFromMap;
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
if (currentSchema.locatorMethod === "frameLocator" /* frameLocator */) {
|
|
966
|
-
if (!currentIFrame) {
|
|
967
|
-
currentIFrame = currentSchema.frameLocator;
|
|
968
|
-
}
|
|
969
|
-
if (currentIFrame && currentSchema.frameLocator && currentIFrame.endsWith(currentSchema.frameLocator)) {
|
|
970
|
-
currentIFrame += ` -> ${currentSchema.frameLocator}`;
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
if (currentIFrame !== void 0) {
|
|
974
|
-
await this.evaluateCurrentLocator(currentLocator, nestedLocatorResults.NestingSteps, currentIFrame);
|
|
975
|
-
} else {
|
|
976
|
-
await this.evaluateCurrentLocator(currentLocator, nestedLocatorResults.NestingSteps, null);
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
} catch (error) {
|
|
980
|
-
this.logError(error, locatorSchemaPath, currentLocator, path, pathIndexPairs, nestedLocatorResults);
|
|
981
|
-
break;
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
if (!currentLocator) {
|
|
985
|
-
this.logError(
|
|
986
|
-
new Error(`Failed to build nested locator for path: ${locatorSchemaPath}`),
|
|
987
|
-
locatorSchemaPath,
|
|
988
|
-
currentLocator,
|
|
989
|
-
locatorSchemaPath,
|
|
990
|
-
pathIndexPairs
|
|
991
|
-
);
|
|
992
|
-
}
|
|
993
|
-
if (this.log.isLogLevelEnabled("debug")) {
|
|
994
|
-
this.log.debug("Nested locator evaluation results:", safeStringifyOfNestedLocatorResults(nestedLocatorResults));
|
|
995
|
-
}
|
|
996
|
-
if (currentLocator != null) {
|
|
997
|
-
return currentLocator;
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1000
|
-
};
|
|
1001
|
-
/**
|
|
1002
|
-
* evaluateCurrentLocator:
|
|
1003
|
-
* Gathers debug information about the current locator's resolved elements.
|
|
1004
|
-
* Helps with logging and debugging complex locator chains.
|
|
1005
|
-
*/
|
|
1006
|
-
evaluateCurrentLocator = async (currentLocator, resultsArray, currentIFrame) => {
|
|
1007
|
-
if (currentIFrame) {
|
|
1008
|
-
resultsArray.push({
|
|
1009
|
-
currentLocatorString: currentLocator,
|
|
1010
|
-
currentIFrame,
|
|
1011
|
-
Note: "iFrame locators evaluation not implemented"
|
|
1012
|
-
});
|
|
1013
|
-
} else {
|
|
1014
|
-
const elementCount = await currentLocator.count();
|
|
1015
|
-
resultsArray.push({
|
|
1016
|
-
currentLocatorString: `${currentLocator}`,
|
|
1017
|
-
resolved: elementCount > 0,
|
|
1018
|
-
elementCount
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
};
|
|
1022
|
-
};
|
|
1023
|
-
var WithMethodsClass = class extends GetLocatorBase {
|
|
1024
|
-
constructor(pageObjectClass, log, locatorSubstring, schemasMap) {
|
|
1025
|
-
super(pageObjectClass, log, locatorSubstring);
|
|
1026
|
-
this.pageObjectClass = pageObjectClass;
|
|
1027
|
-
this.log = log;
|
|
1028
|
-
this.schemasMap = schemasMap;
|
|
1029
|
-
}
|
|
1030
|
-
locatorSchemaPath;
|
|
1031
|
-
/**
|
|
1032
|
-
* init:
|
|
1033
|
-
* Assigns the locatorSchemaPath and binds methods (update, addFilter, getNestedLocator, getLocator)
|
|
1034
|
-
* directly on the locatorSchemaCopy. Returns the modified copy, now fully chainable and type-safe.
|
|
1035
|
-
*/
|
|
1036
|
-
init(locatorSchemaPath, locatorSchemaCopy) {
|
|
1037
|
-
this.locatorSchemaPath = locatorSchemaPath;
|
|
1038
|
-
const self = this;
|
|
1039
|
-
locatorSchemaCopy.update = function(subPath, updates) {
|
|
1040
|
-
const fullPath = this.locatorSchemaPath;
|
|
1041
|
-
if (!(subPath === fullPath || fullPath.startsWith(`${subPath}.`))) {
|
|
1042
|
-
throw new Error(`Invalid sub-path: '${subPath}' is not a valid sub-path of '${fullPath}'.`);
|
|
1043
|
-
}
|
|
1044
|
-
self.applyUpdateToSubPath(self.schemasMap, subPath, updates);
|
|
1045
|
-
return this;
|
|
1046
|
-
};
|
|
1047
|
-
locatorSchemaCopy.addFilter = function(subPath, filterData) {
|
|
1048
|
-
const fullPath = this.locatorSchemaPath;
|
|
1049
|
-
if (!self.schemasMap.has(subPath)) {
|
|
1050
|
-
const allowedPaths = self.extractPathsFromSchema(fullPath).map((p) => p.path).filter((path) => self.schemasMap.has(path));
|
|
1051
|
-
throw new Error(
|
|
1052
|
-
`Invalid sub-path '${subPath}' in addFilter. Allowed sub-paths are:
|
|
1053
|
-
${allowedPaths.join(",\n")}`
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
if (!this.filterMap) {
|
|
1057
|
-
this.filterMap = /* @__PURE__ */ new Map();
|
|
1058
|
-
}
|
|
1059
|
-
const existingFilters = this.filterMap.get(subPath) || [];
|
|
1060
|
-
existingFilters.push(filterData);
|
|
1061
|
-
this.filterMap.set(subPath, existingFilters);
|
|
1062
|
-
return this;
|
|
1063
|
-
};
|
|
1064
|
-
locatorSchemaCopy.getNestedLocator = async function(arg) {
|
|
1065
|
-
if (arg !== void 0 && arg !== null && typeof arg !== "object") {
|
|
1066
|
-
throw new Error("Invalid argument passed to getNestedLocator: Expected an object or null.");
|
|
1067
|
-
}
|
|
1068
|
-
if (!arg || Object.keys(arg).length === 0) {
|
|
1069
|
-
return await self.buildNestedLocator(
|
|
1070
|
-
self.locatorSchemaPath,
|
|
1071
|
-
self.schemasMap,
|
|
1072
|
-
this.filterMap,
|
|
1073
|
-
{}
|
|
1074
|
-
);
|
|
1075
|
-
}
|
|
1076
|
-
const numericIndices = {};
|
|
1077
|
-
const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
|
|
1078
|
-
const pathToIndexMap = new Map(pathIndexPairs.map((pair, idx) => [pair.path, idx]));
|
|
1079
|
-
for (const [subPath, value] of Object.entries(arg)) {
|
|
1080
|
-
if (!self.schemasMap.has(subPath)) {
|
|
1081
|
-
const validPaths = Array.from(self.schemasMap.keys());
|
|
1082
|
-
throw new Error(
|
|
1083
|
-
`Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
|
|
1084
|
-
${validPaths.join(",\n")}`
|
|
1085
|
-
);
|
|
1086
|
-
}
|
|
1087
|
-
if (!pathToIndexMap.has(subPath)) {
|
|
1088
|
-
const validPaths = pathIndexPairs.map((p) => p.path).filter((path) => self.schemasMap.has(path));
|
|
1089
|
-
throw new Error(
|
|
1090
|
-
`Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
|
|
1091
|
-
${validPaths.join(",\n")}`
|
|
1092
|
-
);
|
|
1093
|
-
}
|
|
1094
|
-
const numericIndex = pathToIndexMap.get(subPath);
|
|
1095
|
-
if (numericIndex === void 0) {
|
|
1096
|
-
throw new Error(`Sub-path '${subPath}' not found in pathToIndexMap.`);
|
|
1097
|
-
}
|
|
1098
|
-
if (value !== null && (typeof value !== "number" || value < 0)) {
|
|
1099
|
-
throw new Error(`Invalid index for sub-path '${subPath}': Expected a positive number or null.`);
|
|
1100
|
-
}
|
|
1101
|
-
if (value !== null) {
|
|
1102
|
-
numericIndices[numericIndex] = value;
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
return await self.buildNestedLocator(
|
|
1106
|
-
self.locatorSchemaPath,
|
|
1107
|
-
self.schemasMap,
|
|
1108
|
-
this.filterMap,
|
|
1109
|
-
numericIndices
|
|
1110
|
-
);
|
|
1111
|
-
};
|
|
1112
|
-
locatorSchemaCopy.getLocator = async () => {
|
|
1113
|
-
return self.getBy.getLocator(locatorSchemaCopy);
|
|
1114
|
-
};
|
|
1115
|
-
return locatorSchemaCopy;
|
|
434
|
+
if (path.includes("..")) {
|
|
435
|
+
throw new Error(`LocatorSchemaPath string cannot contain consecutive dots: ${path}`);
|
|
1116
436
|
}
|
|
1117
437
|
};
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
438
|
+
var expandSchemaPath = (path) => {
|
|
439
|
+
validateLocatorSchemaPath(path);
|
|
440
|
+
const parts = path.split(".");
|
|
441
|
+
return parts.map((_part, index) => parts.slice(0, index + 1).join("."));
|
|
442
|
+
};
|
|
443
|
+
var cssEscape = (value) => {
|
|
444
|
+
return value.replace(/([\\"'#.:;,?*+<>{}[\\]()])/g, "\\$1");
|
|
445
|
+
};
|
|
446
|
+
var normalizeSteps = (steps) => steps ? steps.map((step2) => ({ ...step2 })) : [];
|
|
447
|
+
function normalizeIdValue(id) {
|
|
448
|
+
if (typeof id !== "string") {
|
|
449
|
+
return id;
|
|
1126
450
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
queuedStates = {};
|
|
1130
|
-
// Indicates if the session storage manipulation has been initiated.
|
|
1131
|
-
isInitiated = false;
|
|
1132
|
-
/** Writes states to session storage. Accepts an object with key-value pairs representing the states. */
|
|
1133
|
-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
1134
|
-
async writeToSessionStorage(states) {
|
|
1135
|
-
await this.page.evaluate((storage) => {
|
|
1136
|
-
for (const [key, value] of Object.entries(storage)) {
|
|
1137
|
-
window.sessionStorage.setItem(key, JSON.stringify(value));
|
|
1138
|
-
}
|
|
1139
|
-
}, states);
|
|
451
|
+
if (id.startsWith("#")) {
|
|
452
|
+
return id.slice(1);
|
|
1140
453
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
}
|
|
454
|
+
if (id.startsWith("id=")) {
|
|
455
|
+
return id.slice("id=".length);
|
|
456
|
+
}
|
|
457
|
+
return id;
|
|
458
|
+
}
|
|
459
|
+
var stringifyForLog = (value) => {
|
|
460
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
461
|
+
return JSON.stringify(
|
|
462
|
+
value,
|
|
463
|
+
(_key, current) => {
|
|
464
|
+
if (typeof current === "object" && current !== null) {
|
|
465
|
+
if (seen.has(current)) {
|
|
466
|
+
return "[Circular]";
|
|
1155
467
|
}
|
|
468
|
+
seen.add(current);
|
|
1156
469
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
}
|
|
1160
|
-
/**
|
|
1161
|
-
* Sets the specified states in session storage.
|
|
1162
|
-
* Optionally reloads the page after setting the data to ensure the new session storage state is active.
|
|
1163
|
-
*
|
|
1164
|
-
* Parameters:
|
|
1165
|
-
* states: Object representing the states to set in session storage.
|
|
1166
|
-
* reload: Boolean indicating whether to reload the page after setting the session storage data.
|
|
1167
|
-
*/
|
|
1168
|
-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
1169
|
-
async set(states, reload) {
|
|
1170
|
-
await import_test2.test.step(`${this.pocName}: setSessionStorage`, async () => {
|
|
1171
|
-
await this.writeToSessionStorage(states);
|
|
1172
|
-
if (reload) {
|
|
1173
|
-
await this.page.reload();
|
|
470
|
+
if (current instanceof RegExp) {
|
|
471
|
+
return { type: "RegExp", source: current.source, flags: current.flags };
|
|
1174
472
|
}
|
|
1175
|
-
|
|
473
|
+
return current;
|
|
474
|
+
},
|
|
475
|
+
2
|
|
476
|
+
);
|
|
477
|
+
};
|
|
478
|
+
var applyIndexSelector = (locator, selector) => {
|
|
479
|
+
if (selector === void 0 || selector === null) {
|
|
480
|
+
return locator;
|
|
1176
481
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
* Handles different scenarios based on whether the context exists or multiple calls are made.
|
|
1180
|
-
*
|
|
1181
|
-
* 1. No Context, Single Call: Queues and sets states upon the next navigation.
|
|
1182
|
-
* 2. No Context, Multiple Calls: Merges states from multiple calls and sets them upon the next navigation.
|
|
1183
|
-
* 3. With Context: Directly sets states in sessionStorage if the context already exists.
|
|
1184
|
-
*
|
|
1185
|
-
* Parameters:
|
|
1186
|
-
* states: Object representing the states to queue for setting in session storage.
|
|
1187
|
-
*/
|
|
1188
|
-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
1189
|
-
async setOnNextNavigation(states) {
|
|
1190
|
-
this.queuedStates = { ...this.queuedStates, ...states };
|
|
1191
|
-
const populateStorage = async () => {
|
|
1192
|
-
await import_test2.test.step(`${this.pocName}: setSessionStorageBeforeNavigation`, async () => {
|
|
1193
|
-
await this.writeToSessionStorage(this.queuedStates);
|
|
1194
|
-
});
|
|
1195
|
-
this.queuedStates = {};
|
|
1196
|
-
};
|
|
1197
|
-
let contextExists = false;
|
|
1198
|
-
try {
|
|
1199
|
-
contextExists = await this.page.evaluate(() => {
|
|
1200
|
-
return typeof window !== "undefined" && window.sessionStorage !== void 0;
|
|
1201
|
-
});
|
|
1202
|
-
} catch (_e) {
|
|
1203
|
-
contextExists = false;
|
|
1204
|
-
}
|
|
1205
|
-
if (contextExists) {
|
|
1206
|
-
await populateStorage();
|
|
1207
|
-
return;
|
|
1208
|
-
}
|
|
1209
|
-
if (!this.isInitiated) {
|
|
1210
|
-
this.isInitiated = true;
|
|
1211
|
-
this.page.once("framenavigated", async () => {
|
|
1212
|
-
await populateStorage();
|
|
1213
|
-
});
|
|
1214
|
-
}
|
|
482
|
+
if (selector === "first") {
|
|
483
|
+
return locator.first();
|
|
1215
484
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
485
|
+
if (selector === "last") {
|
|
486
|
+
return locator.last();
|
|
487
|
+
}
|
|
488
|
+
return locator.nth(selector);
|
|
489
|
+
};
|
|
490
|
+
var createLocator = (target, definition) => {
|
|
491
|
+
switch (definition.type) {
|
|
492
|
+
case "role":
|
|
493
|
+
return target.getByRole(definition.role, definition.options);
|
|
494
|
+
case "text":
|
|
495
|
+
return target.getByText(definition.text, definition.options);
|
|
496
|
+
case "label":
|
|
497
|
+
return target.getByLabel(definition.text, definition.options);
|
|
498
|
+
case "placeholder":
|
|
499
|
+
return target.getByPlaceholder(definition.text, definition.options);
|
|
500
|
+
case "altText":
|
|
501
|
+
return target.getByAltText(definition.text, definition.options);
|
|
502
|
+
case "title":
|
|
503
|
+
return target.getByTitle(definition.text, definition.options);
|
|
504
|
+
case "locator":
|
|
505
|
+
return target.locator(definition.selector, definition.options);
|
|
506
|
+
case "frameLocator":
|
|
507
|
+
return target.frameLocator(definition.selector);
|
|
508
|
+
case "testId":
|
|
509
|
+
return target.getByTestId(definition.testId);
|
|
510
|
+
case "id": {
|
|
511
|
+
if (typeof definition.id === "string") {
|
|
512
|
+
const normalized = normalizeIdValue(definition.id);
|
|
513
|
+
return target.locator(`#${cssEscape(normalized ?? "")}`);
|
|
1239
514
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
515
|
+
const pattern = definition.id.source;
|
|
516
|
+
const safePattern = cssEscape(pattern);
|
|
517
|
+
return target.locator(`[id*="${safePattern}"]`);
|
|
518
|
+
}
|
|
519
|
+
default: {
|
|
520
|
+
const exhaustive = definition;
|
|
521
|
+
return exhaustive;
|
|
522
|
+
}
|
|
1242
523
|
}
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
524
|
+
};
|
|
525
|
+
var cloneLocatorStrategyDefinition = (definition) => {
|
|
526
|
+
switch (definition.type) {
|
|
527
|
+
case "role":
|
|
528
|
+
return {
|
|
529
|
+
type: "role",
|
|
530
|
+
role: definition.role,
|
|
531
|
+
...definition.options ? { options: { ...definition.options } } : {}
|
|
532
|
+
};
|
|
533
|
+
case "text":
|
|
534
|
+
return {
|
|
535
|
+
type: "text",
|
|
536
|
+
text: definition.text,
|
|
537
|
+
...definition.options ? { options: { ...definition.options } } : {}
|
|
538
|
+
};
|
|
539
|
+
case "label":
|
|
540
|
+
return {
|
|
541
|
+
type: "label",
|
|
542
|
+
text: definition.text,
|
|
543
|
+
...definition.options ? { options: { ...definition.options } } : {}
|
|
544
|
+
};
|
|
545
|
+
case "placeholder":
|
|
546
|
+
return {
|
|
547
|
+
type: "placeholder",
|
|
548
|
+
text: definition.text,
|
|
549
|
+
...definition.options ? { options: { ...definition.options } } : {}
|
|
550
|
+
};
|
|
551
|
+
case "altText":
|
|
552
|
+
return {
|
|
553
|
+
type: "altText",
|
|
554
|
+
text: definition.text,
|
|
555
|
+
...definition.options ? { options: { ...definition.options } } : {}
|
|
556
|
+
};
|
|
557
|
+
case "title":
|
|
558
|
+
return {
|
|
559
|
+
type: "title",
|
|
560
|
+
text: definition.text,
|
|
561
|
+
...definition.options ? { options: { ...definition.options } } : {}
|
|
562
|
+
};
|
|
563
|
+
case "locator":
|
|
564
|
+
return {
|
|
565
|
+
type: "locator",
|
|
566
|
+
selector: definition.selector,
|
|
567
|
+
...definition.options ? { options: { ...definition.options } } : {}
|
|
568
|
+
};
|
|
569
|
+
case "frameLocator":
|
|
570
|
+
return { type: "frameLocator", selector: definition.selector };
|
|
571
|
+
case "testId":
|
|
572
|
+
return { type: "testId", testId: definition.testId };
|
|
573
|
+
case "id":
|
|
574
|
+
return { type: "id", id: definition.id };
|
|
575
|
+
default: {
|
|
576
|
+
const exhaustive = definition;
|
|
577
|
+
return exhaustive;
|
|
578
|
+
}
|
|
1250
579
|
}
|
|
1251
580
|
};
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
*
|
|
1260
|
-
* Parameters:
|
|
1261
|
-
* - document: An object that mimics the global document, having a querySelector method.
|
|
1262
|
-
* - selector: A string representing the value of the 'data-cy' attribute to search for.
|
|
1263
|
-
*
|
|
1264
|
-
* Returns the first HTML element matching the 'data-cy' attribute, or null if no match is found.
|
|
1265
|
-
*/
|
|
1266
|
-
query(document, selector) {
|
|
1267
|
-
const attr = `[data-cy="${selector}"]`;
|
|
1268
|
-
const el = document.querySelector(attr);
|
|
1269
|
-
return el;
|
|
1270
|
-
},
|
|
1271
|
-
/**
|
|
1272
|
-
* Uses the document's querySelectorAll method to find all elements with a specific 'data-cy' attribute.
|
|
1273
|
-
* Constructs a selector string for the 'data-cy' attribute and retrieves all matching elements in the DOM.
|
|
1274
|
-
* Converts the NodeList from querySelectorAll into an array for easier handling and manipulation.
|
|
1275
|
-
*
|
|
1276
|
-
* Parameters:
|
|
1277
|
-
* - document: An object that mimics the global document, having a querySelectorAll method.
|
|
1278
|
-
* - selector: A string representing the value of the 'data-cy' attribute to search for.
|
|
1279
|
-
*
|
|
1280
|
-
* Returns an array of HTML elements matching the 'data-cy' attribute. Returns an empty array if no matches are found.
|
|
1281
|
-
*/
|
|
1282
|
-
queryAll(document, selector) {
|
|
1283
|
-
const attr = `[data-cy="${selector}"]`;
|
|
1284
|
-
const els = Array.from(document.querySelectorAll(attr));
|
|
1285
|
-
return els;
|
|
581
|
+
var applyDefinitionPatch = (seed, patch) => {
|
|
582
|
+
const base2 = cloneLocatorStrategyDefinition(seed);
|
|
583
|
+
switch (patch.type) {
|
|
584
|
+
case "locator": {
|
|
585
|
+
const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
|
|
586
|
+
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
587
|
+
return { type: "locator", selector, ...options ? { options } : {} };
|
|
1286
588
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
var selectorRegistered = false;
|
|
1292
|
-
var BasePage = class {
|
|
1293
|
-
/** Provides Playwright page methods */
|
|
1294
|
-
page;
|
|
1295
|
-
/** Playwright TestInfo contains information about currently running test, available to any test function */
|
|
1296
|
-
testInfo;
|
|
1297
|
-
/** Selectors can be used to install custom selector engines.*/
|
|
1298
|
-
selector;
|
|
1299
|
-
/** The base URL of the Page Object Class */
|
|
1300
|
-
baseUrl;
|
|
1301
|
-
/** The URL path of the Page Object Class */
|
|
1302
|
-
urlPath;
|
|
1303
|
-
/** The full URL of the Page Object Class */
|
|
1304
|
-
fullUrl;
|
|
1305
|
-
/** The name of the Page Object Class */
|
|
1306
|
-
pocName;
|
|
1307
|
-
/** The Page Object Class' PlaywrightReportLogger instance, prefixed with its name. Log levels: debug, info, warn, and error. */
|
|
1308
|
-
log;
|
|
1309
|
-
/** The SessionStorage class provides methods for setting and getting session storage data in Playwright.*/
|
|
1310
|
-
sessionStorage;
|
|
1311
|
-
/**
|
|
1312
|
-
* locators:
|
|
1313
|
-
* An instance of GetLocatorBase that handles schema management and provides getLocatorSchema calls.
|
|
1314
|
-
* Initially, LocatorSubstring is undefined. Once getLocatorSchema(path) is called,
|
|
1315
|
-
* we get a chainable object typed with LocatorSubstring = P.
|
|
1316
|
-
*/
|
|
1317
|
-
locators;
|
|
1318
|
-
constructor(page, testInfo, baseUrl, urlPath, pocName, pwrl, locatorSubstring) {
|
|
1319
|
-
this.page = page;
|
|
1320
|
-
this.testInfo = testInfo;
|
|
1321
|
-
this.selector = import_test3.selectors;
|
|
1322
|
-
this.baseUrl = baseUrl;
|
|
1323
|
-
this.urlPath = urlPath;
|
|
1324
|
-
this.fullUrl = this.constructFullUrl(baseUrl, urlPath);
|
|
1325
|
-
this.pocName = pocName;
|
|
1326
|
-
this.log = pwrl.getNewChildLogger(pocName);
|
|
1327
|
-
const classDeprecationMessage = "[POMWright] BasePage is depricated and will be removed in 2.0.0. Migrate to v2, preferably directly to PageObject or through the transitional bridge BasePageV1toV2 and then to PageObject.";
|
|
1328
|
-
warnDeprecationOncePerTest(`${this.constructor.name}-class-deprecation`, classDeprecationMessage, this.log);
|
|
1329
|
-
this.locators = new GetLocatorBase(
|
|
1330
|
-
this,
|
|
1331
|
-
this.log.getNewChildLogger("GetLocator"),
|
|
1332
|
-
locatorSubstring
|
|
1333
|
-
);
|
|
1334
|
-
this.initLocatorSchemas();
|
|
1335
|
-
this.sessionStorage = new SessionStorage(this.page, this.pocName);
|
|
1336
|
-
if (!selectorRegistered) {
|
|
1337
|
-
import_test3.selectors.register("data-cy", createCypressIdEngine);
|
|
1338
|
-
selectorRegistered = true;
|
|
589
|
+
case "role": {
|
|
590
|
+
const role = patch.role ?? base2.role;
|
|
591
|
+
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
592
|
+
return { type: "role", role, ...options ? { options } : {} };
|
|
1339
593
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
* Ensures a flexible approach to URL matching (string or regex-based).
|
|
1345
|
-
*/
|
|
1346
|
-
constructFullUrl(baseUrl, urlPath) {
|
|
1347
|
-
const escapeStringForRegExp = (str) => str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
1348
|
-
if (typeof baseUrl === "string" && typeof urlPath === "string") {
|
|
1349
|
-
return `${baseUrl}${urlPath}`;
|
|
594
|
+
case "text": {
|
|
595
|
+
const text = patch.text ?? base2.text;
|
|
596
|
+
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
597
|
+
return { type: "text", text, ...options ? { options } : {} };
|
|
1350
598
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
599
|
+
case "label": {
|
|
600
|
+
const text = patch.text ?? base2.text;
|
|
601
|
+
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
602
|
+
return { type: "label", text, ...options ? { options } : {} };
|
|
1353
603
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
604
|
+
case "placeholder": {
|
|
605
|
+
const text = patch.text ?? base2.text;
|
|
606
|
+
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
607
|
+
return { type: "placeholder", text, ...options ? { options } : {} };
|
|
608
|
+
}
|
|
609
|
+
case "altText": {
|
|
610
|
+
const text = patch.text ?? base2.text;
|
|
611
|
+
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
612
|
+
return { type: "altText", text, ...options ? { options } : {} };
|
|
613
|
+
}
|
|
614
|
+
case "title": {
|
|
615
|
+
const text = patch.text ?? base2.text;
|
|
616
|
+
const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
|
|
617
|
+
return { type: "title", text, ...options ? { options } : {} };
|
|
618
|
+
}
|
|
619
|
+
case "frameLocator": {
|
|
620
|
+
const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
|
|
621
|
+
return { type: "frameLocator", selector };
|
|
622
|
+
}
|
|
623
|
+
case "testId": {
|
|
624
|
+
const testId = patch.testId !== void 0 ? patch.testId : base2.testId;
|
|
625
|
+
return { type: "testId", testId };
|
|
626
|
+
}
|
|
627
|
+
case "id": {
|
|
628
|
+
const id = patch.id !== void 0 ? normalizeIdValue(patch.id) ?? base2.id : base2.id;
|
|
629
|
+
return { type: "id", id };
|
|
1356
630
|
}
|
|
1357
|
-
|
|
1358
|
-
|
|
631
|
+
default: {
|
|
632
|
+
const exhaustive = patch;
|
|
633
|
+
return exhaustive;
|
|
1359
634
|
}
|
|
1360
|
-
throw new Error("Invalid baseUrl or urlPath types. Expected string or RegExp.");
|
|
1361
|
-
}
|
|
1362
|
-
/**
|
|
1363
|
-
* Implementation of getNestedLocator.
|
|
1364
|
-
*/
|
|
1365
|
-
async getNestedLocator(locatorSchemaPath, subPathIndices) {
|
|
1366
|
-
const withValidation = new WithSubPathValidation(
|
|
1367
|
-
this,
|
|
1368
|
-
this.log.getNewChildLogger("SubPathValidation"),
|
|
1369
|
-
locatorSchemaPath
|
|
1370
|
-
);
|
|
1371
|
-
return await withValidation.getNestedLocator(subPathIndices);
|
|
1372
|
-
}
|
|
1373
|
-
/**
|
|
1374
|
-
* Short-hand wrapper method for calling .getLocatorSchema(LocatorSchemaPath).getLocator()
|
|
1375
|
-
*
|
|
1376
|
-
* This method does not perform nesting,and will return the locator for which the full LocatorSchemaPath resolves to,
|
|
1377
|
-
* provided by getLocatorSchema("...")
|
|
1378
|
-
*
|
|
1379
|
-
* Note: This short-hand wrapper method is useful for quickly getting a locator without having to call
|
|
1380
|
-
* getLocatorSchema("...") first. On the other hand, it can't be used to update or add filters to the LocatorSchema.
|
|
1381
|
-
*
|
|
1382
|
-
* @example
|
|
1383
|
-
* // Usage:
|
|
1384
|
-
* const submitButton = await poc.getLocator("main.form.button@submit");
|
|
1385
|
-
* await expect(submitButton, "should only exist one submit button").toHaveCount(1);
|
|
1386
|
-
*/
|
|
1387
|
-
getLocator = async (locatorSchemaPath) => {
|
|
1388
|
-
return await this.getLocatorSchema(locatorSchemaPath).getLocator();
|
|
1389
|
-
};
|
|
1390
|
-
/**
|
|
1391
|
-
* getLocatorSchema:
|
|
1392
|
-
* Delegates to this.locators.getLocatorSchema.
|
|
1393
|
-
* Returns a chainable schema object for the given path.
|
|
1394
|
-
* Once called with a specific path P, the update and addFilter methods are restricted to sub-paths of P.
|
|
1395
|
-
*
|
|
1396
|
-
* The "getLocatorSchema" method is used to retrieve an updatable deep copy of a LocatorSchema defined in the
|
|
1397
|
-
* GetLocatorBase class. It enriches the returned schema with additional methods to handle updates and retrieval of
|
|
1398
|
-
* deep copy locators.
|
|
1399
|
-
*
|
|
1400
|
-
* getLocatorSchema adds the following chainable methods to the returned LocatorSchemaWithMethods object:
|
|
1401
|
-
*
|
|
1402
|
-
* update
|
|
1403
|
-
* - Allows updating any schema in the chain by specifying the subPath directly.
|
|
1404
|
-
* - Gives compile-time suggestions for valid sub-paths of the LocatorSchemaPath provided to .getLocatorSchema().
|
|
1405
|
-
* - If you want to update multiple schemas, chain multiple .update() calls.
|
|
1406
|
-
*
|
|
1407
|
-
* addFilter(subPath: SubPaths<LocatorSchemaPathType, LocatorSubstring>, filterData: FilterEntry)
|
|
1408
|
-
* - The equivalent of the Playwright locator.filter() method
|
|
1409
|
-
* - This method is used for filtering the specified locator based on the provided filterData.
|
|
1410
|
-
* - Can be chained multiple times to add multiple filters to the same or different LocatorSchema.
|
|
1411
|
-
*
|
|
1412
|
-
* getNestedLocator
|
|
1413
|
-
* - Asynchronously builds a nested locator based on the LocatorSchemaPath provided by getLocatorSchema("...")
|
|
1414
|
-
* - Can be chained once after the update and addFilter methods or directly on the .getLocatorSchema method.
|
|
1415
|
-
* - getNestedLocator will end the method chain and return a nested Playwright Locator.
|
|
1416
|
-
* - Optionally parameter takes a list of key(subPath)-value(index) pairs, the locator constructed from the LocatorSchema
|
|
1417
|
-
* with the specified subPath will resolve to the .nth(n) occurrence of the element, within the chain.
|
|
1418
|
-
*
|
|
1419
|
-
* getLocator()
|
|
1420
|
-
* - Asynchronously retrieves a locator based on the current LocatorSchemaPath.
|
|
1421
|
-
* - This method does not perform nesting and will return the locator for which the full LocatorSchemaPath resolves to, provided by getLocatorSchema("...")
|
|
1422
|
-
* - Can be chained once after the update and addFilter methods or directly on the .getLocatorSchema method.
|
|
1423
|
-
* - getLocator will end the method chain and return a Playwright Locator.
|
|
1424
|
-
*
|
|
1425
|
-
* Note: Calling getLocator() and getNestedLocator() on the same LocatorSchemaPath will return a Locator for the same
|
|
1426
|
-
* element, but the Locator returned by getNestedLocator() will be a locator resolving to said same element through
|
|
1427
|
-
* a chain of locators. While the Locator returned by getLocator() will be a single locator which resolves directly
|
|
1428
|
-
* to said element. Thus getLocator() is rarely used, while getNestedLocator() is used extensively.
|
|
1429
|
-
*
|
|
1430
|
-
* That said, for certain use cases, getLocator() can be useful, and you could use it to manually chain locators
|
|
1431
|
-
* yourself if some edge case required it. Though, it would be likely be more prudent to expand your LocatorSchemaPath
|
|
1432
|
-
* type and initLocatorSchemas() method to include the additional locators you need for the given POC, and then use
|
|
1433
|
-
* getNestedLocator() instead, or by implementing a helper method on your Page Object Class.
|
|
1434
|
-
*/
|
|
1435
|
-
getLocatorSchema(path) {
|
|
1436
|
-
return this.locators.getLocatorSchema(path);
|
|
1437
635
|
}
|
|
1438
636
|
};
|
|
1439
|
-
var
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
this.locatorSchemaPath = locatorSchemaPath;
|
|
1443
|
-
}
|
|
1444
|
-
async getNestedLocator(arg) {
|
|
1445
|
-
return await this.pageObjectClass.getLocatorSchema(this.locatorSchemaPath).getNestedLocator(arg);
|
|
1446
|
-
}
|
|
637
|
+
var isFrameLocatorDefinition = (definition) => definition.type === "frameLocator";
|
|
638
|
+
var isLocatorInstance = (value) => {
|
|
639
|
+
return !!value && typeof value === "object" && typeof value.filter === "function";
|
|
1447
640
|
};
|
|
1448
641
|
|
|
1449
|
-
// src/
|
|
1450
|
-
var import_test4 = require("@playwright/test");
|
|
1451
|
-
|
|
1452
|
-
// srcV2/locators/locatorUpdateBuilder.ts
|
|
642
|
+
// src/locators/locatorUpdateBuilder.ts
|
|
1453
643
|
var parseUpdateArguments = (primaryOrOptions, options, optionsProvided) => {
|
|
1454
644
|
let primary;
|
|
1455
645
|
let parsedOptions;
|
|
@@ -1939,7 +1129,7 @@ var LocatorUpdateBuilder = class {
|
|
|
1939
1129
|
}
|
|
1940
1130
|
};
|
|
1941
1131
|
|
|
1942
|
-
//
|
|
1132
|
+
// src/locators/locatorQueryBuilder.ts
|
|
1943
1133
|
var LocatorQueryBuilder = class {
|
|
1944
1134
|
constructor(registry, path) {
|
|
1945
1135
|
this.registry = registry;
|
|
@@ -2162,7 +1352,7 @@ var LocatorQueryBuilder = class {
|
|
|
2162
1352
|
}
|
|
2163
1353
|
};
|
|
2164
1354
|
|
|
2165
|
-
//
|
|
1355
|
+
// src/locators/locatorRegistrationBuilder.ts
|
|
2166
1356
|
var LocatorRegistrationBuilder = class {
|
|
2167
1357
|
constructor(registry, path, seed) {
|
|
2168
1358
|
this.registry = registry;
|
|
@@ -2386,7 +1576,7 @@ var LocatorRegistrationBuilder = class {
|
|
|
2386
1576
|
}
|
|
2387
1577
|
};
|
|
2388
1578
|
|
|
2389
|
-
//
|
|
1579
|
+
// src/locators/reusableLocatorBuilder.ts
|
|
2390
1580
|
var ReusableLocatorBuilder = class {
|
|
2391
1581
|
stepsList;
|
|
2392
1582
|
definitionValue;
|
|
@@ -2462,7 +1652,7 @@ var ReusableLocatorFactory = class {
|
|
|
2462
1652
|
}
|
|
2463
1653
|
};
|
|
2464
1654
|
|
|
2465
|
-
//
|
|
1655
|
+
// src/locators/locatorRegistry.ts
|
|
2466
1656
|
var LocatorRegistryInternal = class {
|
|
2467
1657
|
constructor(page) {
|
|
2468
1658
|
this.page = page;
|
|
@@ -2796,98 +1986,8 @@ var createRegistryWithAccessors = (page) => {
|
|
|
2796
1986
|
return { registry, add, getLocator, getNestedLocator, getLocatorSchema };
|
|
2797
1987
|
};
|
|
2798
1988
|
|
|
2799
|
-
// src/
|
|
2800
|
-
var
|
|
2801
|
-
/** Provides Playwright page methods */
|
|
2802
|
-
page;
|
|
2803
|
-
/** Playwright TestInfo contains information about currently running test, available to any test function */
|
|
2804
|
-
testInfo;
|
|
2805
|
-
/** Selectors can be used to install custom selector engines.*/
|
|
2806
|
-
selector;
|
|
2807
|
-
/** The base URL of the Page Object Class */
|
|
2808
|
-
baseUrl;
|
|
2809
|
-
/** The URL path of the Page Object Class */
|
|
2810
|
-
urlPath;
|
|
2811
|
-
/** The full URL of the Page Object Class */
|
|
2812
|
-
fullUrl;
|
|
2813
|
-
/** The name of the Page Object Class */
|
|
2814
|
-
pocName;
|
|
2815
|
-
/** The Page Object Class' PlaywrightReportLogger instance, prefixed with its name. Log levels: debug, info, warn, and error. */
|
|
2816
|
-
log;
|
|
2817
|
-
/** The SessionStorage class provides methods for setting and getting session storage data in Playwright.*/
|
|
2818
|
-
sessionStorage;
|
|
2819
|
-
/**
|
|
2820
|
-
* locators:
|
|
2821
|
-
* An instance of GetLocatorBase that handles schema management and provides getLocatorSchema calls.
|
|
2822
|
-
* Initially, LocatorSubstring is undefined. Once getLocatorSchema(path) is called,
|
|
2823
|
-
* we get a chainable object typed with LocatorSubstring = P.
|
|
2824
|
-
*/
|
|
2825
|
-
locators;
|
|
2826
|
-
/**
|
|
2827
|
-
* v2 locator registry and accessors, used for migration to the fluent registry DSL.
|
|
2828
|
-
*/
|
|
2829
|
-
locatorRegistry;
|
|
2830
|
-
add;
|
|
2831
|
-
getLocator;
|
|
2832
|
-
getLocatorSchema;
|
|
2833
|
-
getNestedLocator;
|
|
2834
|
-
constructor(page, testInfo, baseUrl, urlPath, pocName, pwrl, locatorSubstring) {
|
|
2835
|
-
this.page = page;
|
|
2836
|
-
this.testInfo = testInfo;
|
|
2837
|
-
this.selector = import_test4.selectors;
|
|
2838
|
-
this.baseUrl = baseUrl;
|
|
2839
|
-
this.urlPath = urlPath;
|
|
2840
|
-
this.fullUrl = this.constructFullUrl(baseUrl, urlPath);
|
|
2841
|
-
this.pocName = pocName;
|
|
2842
|
-
this.log = pwrl.getNewChildLogger(pocName);
|
|
2843
|
-
const classDeprecationMessage = "[POMWright] BasePageV1toV2 is a transitional bridge and will be removed in 2.0.0. Prefer PageObject for new work and migrate existing classes to PageObject.";
|
|
2844
|
-
warnDeprecationOncePerTest(`${this.constructor.name}-class-deprecation`, classDeprecationMessage, this.log);
|
|
2845
|
-
const { registry, add, getLocator, getNestedLocator, getLocatorSchema } = createRegistryWithAccessors(page);
|
|
2846
|
-
this.locatorRegistry = registry;
|
|
2847
|
-
this.add = add;
|
|
2848
|
-
this.getLocator = getLocator;
|
|
2849
|
-
this.getLocatorSchema = getLocatorSchema;
|
|
2850
|
-
this.getNestedLocator = getNestedLocator;
|
|
2851
|
-
this.defineLocators();
|
|
2852
|
-
this.locators = new GetLocatorBase(
|
|
2853
|
-
this,
|
|
2854
|
-
this.log.getNewChildLogger("GetLocator"),
|
|
2855
|
-
locatorSubstring
|
|
2856
|
-
);
|
|
2857
|
-
const initLocatorSchemasDeprecationMessage = "[POMWright] initLocatorSchemas is deprecated and will be removed in 2.0.0. Define locators with the v2 registry DSL in defineLocators instead.";
|
|
2858
|
-
warnDeprecationOncePerTest(
|
|
2859
|
-
`${this.constructor.name}-initLocatorSchemas-deprecation`,
|
|
2860
|
-
initLocatorSchemasDeprecationMessage,
|
|
2861
|
-
this.log
|
|
2862
|
-
);
|
|
2863
|
-
this.initLocatorSchemas();
|
|
2864
|
-
this.sessionStorage = new SessionStorage(this.page, this.pocName);
|
|
2865
|
-
}
|
|
2866
|
-
/**
|
|
2867
|
-
* constructFullUrl:
|
|
2868
|
-
* Combines baseUrl and urlPath, handling both strings and RegExps.
|
|
2869
|
-
* Ensures a flexible approach to URL matching (string or regex-based).
|
|
2870
|
-
*/
|
|
2871
|
-
constructFullUrl(baseUrl, urlPath) {
|
|
2872
|
-
const escapeStringForRegExp = (str) => str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
2873
|
-
if (typeof baseUrl === "string" && typeof urlPath === "string") {
|
|
2874
|
-
return `${baseUrl}${urlPath}`;
|
|
2875
|
-
}
|
|
2876
|
-
if (typeof baseUrl === "string" && urlPath instanceof RegExp) {
|
|
2877
|
-
return new RegExp(`^${escapeStringForRegExp(baseUrl)}${urlPath.source}`);
|
|
2878
|
-
}
|
|
2879
|
-
if (baseUrl instanceof RegExp && typeof urlPath === "string") {
|
|
2880
|
-
return new RegExp(`${baseUrl.source}${escapeStringForRegExp(urlPath)}$`);
|
|
2881
|
-
}
|
|
2882
|
-
if (baseUrl instanceof RegExp && urlPath instanceof RegExp) {
|
|
2883
|
-
return new RegExp(`${baseUrl.source}${urlPath.source}`);
|
|
2884
|
-
}
|
|
2885
|
-
throw new Error("Invalid baseUrl or urlPath types. Expected string or RegExp.");
|
|
2886
|
-
}
|
|
2887
|
-
};
|
|
2888
|
-
|
|
2889
|
-
// srcV2/helpers/navigation.ts
|
|
2890
|
-
var import_test5 = require("@playwright/test");
|
|
1989
|
+
// src/helpers/navigation.ts
|
|
1990
|
+
var import_test4 = require("@playwright/test");
|
|
2891
1991
|
var DEFAULT_WAIT_UNTIL = "load";
|
|
2892
1992
|
var DEFAULT_LOAD_STATE = "load";
|
|
2893
1993
|
var Navigation = class {
|
|
@@ -2922,7 +2022,7 @@ var Navigation = class {
|
|
|
2922
2022
|
if (typeof this.baseUrl !== "string" || typeof this.urlPath !== "string") {
|
|
2923
2023
|
throw new Error("goto() is not supported when baseUrl or urlPath is a RegExp.");
|
|
2924
2024
|
}
|
|
2925
|
-
await
|
|
2025
|
+
await import_test4.test.step(`${this.label}: Navigate to the provided URL or URL Path`, async () => {
|
|
2926
2026
|
const targetUrl = urlPathOrUrl.startsWith("/") ? `${this.baseUrl}${urlPathOrUrl}` : urlPathOrUrl;
|
|
2927
2027
|
await this.page.goto(targetUrl, { waitUntil });
|
|
2928
2028
|
});
|
|
@@ -2937,242 +2037,55 @@ var Navigation = class {
|
|
|
2937
2037
|
}
|
|
2938
2038
|
const waitUntil = this.resolveWaitUntil(options);
|
|
2939
2039
|
const fullUrl = this.fullUrl;
|
|
2940
|
-
await
|
|
2941
|
-
await this.page.goto(fullUrl, { waitUntil });
|
|
2942
|
-
await this.executeActions();
|
|
2943
|
-
});
|
|
2944
|
-
}
|
|
2945
|
-
/**
|
|
2946
|
-
* Expect to be on this page. Works with both string and RegExp fullUrl values.
|
|
2947
|
-
* Uses waitUntil from navigation options when waiting for URL.
|
|
2948
|
-
*/
|
|
2949
|
-
async expectThisPage(options) {
|
|
2950
|
-
const waitUntil = this.resolveWaitUntil(options);
|
|
2951
|
-
await import_test5.test.step(`${this.label}: Expect this Page`, async () => {
|
|
2952
|
-
await this.page.waitForURL(this.fullUrl, { waitUntil });
|
|
2953
|
-
await (0, import_test5.expect)(async () => {
|
|
2954
|
-
if (this.fullUrl instanceof RegExp) {
|
|
2955
|
-
(0, import_test5.expect)(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toMatch(this.fullUrl);
|
|
2956
|
-
} else {
|
|
2957
|
-
(0, import_test5.expect)(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toBe(this.fullUrl);
|
|
2958
|
-
}
|
|
2959
|
-
}).toPass();
|
|
2960
|
-
await this.executeActions();
|
|
2961
|
-
});
|
|
2962
|
-
}
|
|
2963
|
-
/**
|
|
2964
|
-
* Expect to be on any other page (i.e. not this page).
|
|
2965
|
-
* Uses waitForLoadState from navigation options before validating URL.
|
|
2966
|
-
*/
|
|
2967
|
-
async expectAnotherPage(options) {
|
|
2968
|
-
const waitForLoadState = this.resolveWaitForLoadState(options);
|
|
2969
|
-
await import_test5.test.step(`${this.label}: Expect any other Page`, async () => {
|
|
2970
|
-
await this.page.waitForLoadState(waitForLoadState);
|
|
2971
|
-
if (this.fullUrl instanceof RegExp) {
|
|
2972
|
-
await import_test5.expect.poll(async () => this.page.url(), {
|
|
2973
|
-
message: `expected url to not match '${this.fullUrl}'`
|
|
2974
|
-
}).not.toMatch(this.fullUrl);
|
|
2975
|
-
} else {
|
|
2976
|
-
await import_test5.expect.poll(async () => this.page.url(), {
|
|
2977
|
-
message: `expected url to not be '${this.fullUrl}', found '${this.page.url()}'`
|
|
2978
|
-
}).not.toBe(this.fullUrl);
|
|
2979
|
-
}
|
|
2980
|
-
});
|
|
2981
|
-
}
|
|
2982
|
-
};
|
|
2983
|
-
function createNavigation(page, baseUrl, urlPath, fullUrl, label, actions = null, defaultOptions) {
|
|
2984
|
-
const navigation = new Navigation(page, baseUrl, urlPath, fullUrl, label, actions, defaultOptions);
|
|
2985
|
-
return navigation;
|
|
2986
|
-
}
|
|
2987
|
-
|
|
2988
|
-
// srcV2/helpers/sessionStorage.ts
|
|
2989
|
-
var import_test6 = require("@playwright/test");
|
|
2990
|
-
var SessionStorage2 = class {
|
|
2991
|
-
// Initializes the class with a Playwright Page object and an optional label for step titles.
|
|
2992
|
-
constructor(page, options = {}) {
|
|
2993
|
-
this.page = page;
|
|
2994
|
-
this.options = options;
|
|
2995
|
-
}
|
|
2996
|
-
// Defines an object to hold states to be set in session storage, allowing any value type.
|
|
2997
|
-
queuedStates = {};
|
|
2998
|
-
// Indicates if the session storage manipulation has been initiated.
|
|
2999
|
-
isInitiated = false;
|
|
3000
|
-
getStepLabel(methodName) {
|
|
3001
|
-
const prefix = this.options.label ? `${this.options.label}.` : "";
|
|
3002
|
-
return `${prefix}SessionStorage.${methodName}:`;
|
|
3003
|
-
}
|
|
3004
|
-
async hasContext() {
|
|
3005
|
-
return await this.page.evaluate(() => {
|
|
3006
|
-
return typeof window !== "undefined" && window.sessionStorage !== void 0;
|
|
3007
|
-
});
|
|
3008
|
-
}
|
|
3009
|
-
async waitForContextAvailability() {
|
|
3010
|
-
try {
|
|
3011
|
-
const contextExists = await this.hasContext();
|
|
3012
|
-
if (contextExists) {
|
|
3013
|
-
return;
|
|
3014
|
-
}
|
|
3015
|
-
} catch (_e) {
|
|
3016
|
-
}
|
|
3017
|
-
await new Promise((resolve) => {
|
|
3018
|
-
const handler = async (frame) => {
|
|
3019
|
-
if (frame !== this.page.mainFrame()) {
|
|
3020
|
-
return;
|
|
3021
|
-
}
|
|
3022
|
-
try {
|
|
3023
|
-
const contextExists = await this.hasContext();
|
|
3024
|
-
if (!contextExists) {
|
|
3025
|
-
return;
|
|
3026
|
-
}
|
|
3027
|
-
} catch (_e) {
|
|
3028
|
-
return;
|
|
3029
|
-
}
|
|
3030
|
-
this.page.off("framenavigated", handler);
|
|
3031
|
-
resolve();
|
|
3032
|
-
};
|
|
3033
|
-
this.page.on("framenavigated", handler);
|
|
3034
|
-
});
|
|
3035
|
-
}
|
|
3036
|
-
async ensureContext({ waitForContext = false } = {}) {
|
|
3037
|
-
try {
|
|
3038
|
-
const contextExists = await this.hasContext();
|
|
3039
|
-
if (contextExists) {
|
|
3040
|
-
return;
|
|
3041
|
-
}
|
|
3042
|
-
} catch (_e) {
|
|
3043
|
-
}
|
|
3044
|
-
if (!waitForContext) {
|
|
3045
|
-
throw new Error("SessionStorage context is not available.");
|
|
3046
|
-
}
|
|
3047
|
-
await this.waitForContextAvailability();
|
|
3048
|
-
}
|
|
3049
|
-
/** Writes states to session storage. Accepts an object with key-value pairs representing the states. */
|
|
3050
|
-
async writeToSessionStorage(states) {
|
|
3051
|
-
await this.page.evaluate((storage) => {
|
|
3052
|
-
for (const [key, value] of Object.entries(storage)) {
|
|
3053
|
-
window.sessionStorage.setItem(key, JSON.stringify(value));
|
|
3054
|
-
}
|
|
3055
|
-
}, states);
|
|
3056
|
-
}
|
|
3057
|
-
/** Reads all states from session storage and returns them as an object. */
|
|
3058
|
-
async readFromSessionStorage() {
|
|
3059
|
-
const storage = await this.page.evaluate(() => {
|
|
3060
|
-
const storage2 = {};
|
|
3061
|
-
for (let i = 0; i < sessionStorage.length; i++) {
|
|
3062
|
-
const key = sessionStorage.key(i);
|
|
3063
|
-
if (key !== null) {
|
|
3064
|
-
const item = sessionStorage.getItem(key);
|
|
3065
|
-
try {
|
|
3066
|
-
storage2[key] = item ? JSON.parse(item) : null;
|
|
3067
|
-
} catch (_e) {
|
|
3068
|
-
storage2[key] = item;
|
|
3069
|
-
}
|
|
3070
|
-
}
|
|
3071
|
-
}
|
|
3072
|
-
return storage2;
|
|
3073
|
-
});
|
|
3074
|
-
return storage;
|
|
3075
|
-
}
|
|
3076
|
-
/**
|
|
3077
|
-
* Sets the specified states in session storage.
|
|
3078
|
-
* Optionally waits for the next main-frame navigation to establish a valid context before writing,
|
|
3079
|
-
* and reloads the page after setting the data.
|
|
3080
|
-
*
|
|
3081
|
-
* Parameters:
|
|
3082
|
-
* states: Object representing the states to set in session storage.
|
|
3083
|
-
* reload: Boolean indicating whether to reload the page after setting the session storage data.
|
|
3084
|
-
* waitForContext: Boolean indicating whether to wait for a main-frame navigation and a valid context.
|
|
3085
|
-
*/
|
|
3086
|
-
async set(states, options = {}) {
|
|
3087
|
-
await import_test6.test.step(this.getStepLabel("set"), async () => {
|
|
3088
|
-
await this.ensureContext({ waitForContext: options.waitForContext });
|
|
3089
|
-
await this.writeToSessionStorage(states);
|
|
3090
|
-
if (options.reload) {
|
|
3091
|
-
await this.page.reload();
|
|
3092
|
-
}
|
|
3093
|
-
});
|
|
3094
|
-
}
|
|
3095
|
-
/**
|
|
3096
|
-
* Queues states to be set in the sessionStorage before the next navigation occurs.
|
|
3097
|
-
* Handles different scenarios based on multiple calls made before the navigation occurs.
|
|
3098
|
-
*
|
|
3099
|
-
* 1. No Context, Single Call: Queues and sets states upon the next navigation.
|
|
3100
|
-
* 2. No Context, Multiple Calls: Merges states from multiple calls and sets them upon the next navigation.
|
|
3101
|
-
* 3. With Context: Still queues until the next navigation.
|
|
3102
|
-
*
|
|
3103
|
-
* Parameters:
|
|
3104
|
-
* states: Object representing the states to queue for setting in session storage.
|
|
3105
|
-
*/
|
|
3106
|
-
async setOnNextNavigation(states) {
|
|
3107
|
-
this.queuedStates = { ...this.queuedStates, ...states };
|
|
3108
|
-
const populateStorage = async () => {
|
|
3109
|
-
await import_test6.test.step(this.getStepLabel("setOnNextNavigation"), async () => {
|
|
3110
|
-
await this.writeToSessionStorage(this.queuedStates);
|
|
3111
|
-
});
|
|
3112
|
-
this.queuedStates = {};
|
|
3113
|
-
};
|
|
3114
|
-
if (!this.isInitiated) {
|
|
3115
|
-
this.isInitiated = true;
|
|
3116
|
-
const handler = async (frame) => {
|
|
3117
|
-
if (frame !== this.page.mainFrame()) {
|
|
3118
|
-
return;
|
|
3119
|
-
}
|
|
3120
|
-
await populateStorage();
|
|
3121
|
-
this.page.off("framenavigated", handler);
|
|
3122
|
-
this.isInitiated = false;
|
|
3123
|
-
};
|
|
3124
|
-
this.page.on("framenavigated", handler);
|
|
3125
|
-
}
|
|
2040
|
+
await import_test4.test.step(`${this.label}: Navigate to this Page`, async () => {
|
|
2041
|
+
await this.page.goto(fullUrl, { waitUntil });
|
|
2042
|
+
await this.executeActions();
|
|
2043
|
+
});
|
|
3126
2044
|
}
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
}
|
|
2045
|
+
/**
|
|
2046
|
+
* Expect to be on this page. Works with both string and RegExp fullUrl values.
|
|
2047
|
+
* Uses waitUntil from navigation options when waiting for URL.
|
|
2048
|
+
*/
|
|
2049
|
+
async expectThisPage(options) {
|
|
2050
|
+
const waitUntil = this.resolveWaitUntil(options);
|
|
2051
|
+
await import_test4.test.step(`${this.label}: Expect this Page`, async () => {
|
|
2052
|
+
await this.page.waitForURL(this.fullUrl, { waitUntil });
|
|
2053
|
+
await (0, import_test4.expect)(async () => {
|
|
2054
|
+
if (this.fullUrl instanceof RegExp) {
|
|
2055
|
+
(0, import_test4.expect)(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toMatch(this.fullUrl);
|
|
2056
|
+
} else {
|
|
2057
|
+
(0, import_test4.expect)(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toBe(this.fullUrl);
|
|
3140
2058
|
}
|
|
3141
|
-
}
|
|
3142
|
-
|
|
3143
|
-
}
|
|
2059
|
+
}).toPass();
|
|
2060
|
+
await this.executeActions();
|
|
3144
2061
|
});
|
|
3145
|
-
return result;
|
|
3146
2062
|
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
if (
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
await this.page.evaluate(() => sessionStorage.clear());
|
|
3164
|
-
return;
|
|
2063
|
+
/**
|
|
2064
|
+
* Expect to be on any other page (i.e. not this page).
|
|
2065
|
+
* Uses waitForLoadState from navigation options before validating URL.
|
|
2066
|
+
*/
|
|
2067
|
+
async expectAnotherPage(options) {
|
|
2068
|
+
const waitForLoadState = this.resolveWaitForLoadState(options);
|
|
2069
|
+
await import_test4.test.step(`${this.label}: Expect any other Page`, async () => {
|
|
2070
|
+
await this.page.waitForLoadState(waitForLoadState);
|
|
2071
|
+
if (this.fullUrl instanceof RegExp) {
|
|
2072
|
+
await import_test4.expect.poll(async () => this.page.url(), {
|
|
2073
|
+
message: `expected url to not match '${this.fullUrl}'`
|
|
2074
|
+
}).not.toMatch(this.fullUrl);
|
|
2075
|
+
} else {
|
|
2076
|
+
await import_test4.expect.poll(async () => this.page.url(), {
|
|
2077
|
+
message: `expected url to not be '${this.fullUrl}', found '${this.page.url()}'`
|
|
2078
|
+
}).not.toBe(this.fullUrl);
|
|
3165
2079
|
}
|
|
3166
|
-
await this.page.evaluate((keysToClear) => {
|
|
3167
|
-
for (const key of keysToClear) {
|
|
3168
|
-
sessionStorage.removeItem(key);
|
|
3169
|
-
}
|
|
3170
|
-
}, keys);
|
|
3171
2080
|
});
|
|
3172
2081
|
}
|
|
3173
2082
|
};
|
|
2083
|
+
function createNavigation(page, baseUrl, urlPath, fullUrl, label, actions = null, defaultOptions) {
|
|
2084
|
+
const navigation = new Navigation(page, baseUrl, urlPath, fullUrl, label, actions, defaultOptions);
|
|
2085
|
+
return navigation;
|
|
2086
|
+
}
|
|
3174
2087
|
|
|
3175
|
-
//
|
|
2088
|
+
// src/pageObject.ts
|
|
3176
2089
|
var PageObject = class {
|
|
3177
2090
|
page;
|
|
3178
2091
|
baseUrl;
|
|
@@ -3199,7 +2112,7 @@ var PageObject = class {
|
|
|
3199
2112
|
this.getLocator = getLocator;
|
|
3200
2113
|
this.getLocatorSchema = getLocatorSchema;
|
|
3201
2114
|
this.getNestedLocator = getNestedLocator;
|
|
3202
|
-
this.sessionStorage = new
|
|
2115
|
+
this.sessionStorage = new SessionStorage(page, { label });
|
|
3203
2116
|
this.defineLocators();
|
|
3204
2117
|
this.navigation = createNavigation(
|
|
3205
2118
|
this.page,
|
|
@@ -3228,208 +2141,8 @@ var PageObject = class {
|
|
|
3228
2141
|
throw new Error("Invalid baseUrl or urlPath types. Expected string or RegExp.");
|
|
3229
2142
|
}
|
|
3230
2143
|
};
|
|
3231
|
-
|
|
3232
|
-
// srcV2/fixture/base.fixtures.ts
|
|
3233
|
-
var import_test7 = require("@playwright/test");
|
|
3234
|
-
|
|
3235
|
-
// srcV2/helpers/playwrightReportLogger.ts
|
|
3236
|
-
var PlaywrightReportLogger = class _PlaywrightReportLogger {
|
|
3237
|
-
// Initializes the logger with shared log level, log entries, and a context name.
|
|
3238
|
-
constructor(sharedLogLevel, sharedLogEntry, contextName) {
|
|
3239
|
-
this.sharedLogLevel = sharedLogLevel;
|
|
3240
|
-
this.sharedLogEntry = sharedLogEntry;
|
|
3241
|
-
this.contextName = contextName;
|
|
3242
|
-
}
|
|
3243
|
-
contextName;
|
|
3244
|
-
logLevels = ["debug", "info", "warn", "error"];
|
|
3245
|
-
/**
|
|
3246
|
-
* Creates a child logger with a new contextual name, sharing the same log level and log entries with the parent logger.
|
|
3247
|
-
*
|
|
3248
|
-
* The root loggers log "level" is referenced by all child loggers and their child loggers and so on...
|
|
3249
|
-
* Changing the log "level" of one, will change it for all.
|
|
3250
|
-
*/
|
|
3251
|
-
getNewChildLogger(prefix) {
|
|
3252
|
-
return new _PlaywrightReportLogger(this.sharedLogLevel, this.sharedLogEntry, `${this.contextName} -> ${prefix}`);
|
|
3253
|
-
}
|
|
3254
|
-
/**
|
|
3255
|
-
* Logs a message with the specified log level, prefix, and additional arguments if the current log level permits.
|
|
3256
|
-
*/
|
|
3257
|
-
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
3258
|
-
log(level, message, ...args) {
|
|
3259
|
-
const logLevelIndex = this.logLevels.indexOf(level);
|
|
3260
|
-
if (logLevelIndex < this.getCurrentLogLevelIndex()) {
|
|
3261
|
-
return;
|
|
3262
|
-
}
|
|
3263
|
-
this.sharedLogEntry.push({
|
|
3264
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
3265
|
-
logLevel: level,
|
|
3266
|
-
prefix: this.contextName,
|
|
3267
|
-
message: `${message}
|
|
3268
|
-
|
|
3269
|
-
${args.join("\n\n")}`
|
|
3270
|
-
});
|
|
3271
|
-
}
|
|
3272
|
-
/**
|
|
3273
|
-
* Logs a debug-level message with the specified message and arguments.
|
|
3274
|
-
*/
|
|
3275
|
-
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
3276
|
-
debug(message, ...args) {
|
|
3277
|
-
this.log("debug", message, ...args);
|
|
3278
|
-
}
|
|
3279
|
-
/**
|
|
3280
|
-
* Logs a info-level message with the specified message and arguments.
|
|
3281
|
-
*/
|
|
3282
|
-
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
3283
|
-
info(message, ...args) {
|
|
3284
|
-
this.log("info", message, ...args);
|
|
3285
|
-
}
|
|
3286
|
-
/**
|
|
3287
|
-
* Logs a warn-level message with the specified message and arguments.
|
|
3288
|
-
*/
|
|
3289
|
-
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
3290
|
-
warn(message, ...args) {
|
|
3291
|
-
this.log("warn", message, ...args);
|
|
3292
|
-
}
|
|
3293
|
-
/**
|
|
3294
|
-
* Logs a error-level message with the specified message and arguments.
|
|
3295
|
-
*/
|
|
3296
|
-
// biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
|
|
3297
|
-
error(message, ...args) {
|
|
3298
|
-
this.log("error", message, ...args);
|
|
3299
|
-
}
|
|
3300
|
-
/**
|
|
3301
|
-
* Sets the current log level to the specified level during runTime.
|
|
3302
|
-
*/
|
|
3303
|
-
setLogLevel(level) {
|
|
3304
|
-
this.sharedLogLevel.current = level;
|
|
3305
|
-
}
|
|
3306
|
-
/**
|
|
3307
|
-
* Retrieves the current log level during runtime.
|
|
3308
|
-
*/
|
|
3309
|
-
getCurrentLogLevel() {
|
|
3310
|
-
return this.sharedLogLevel.current;
|
|
3311
|
-
}
|
|
3312
|
-
/**
|
|
3313
|
-
* Retrieves the index of the current log level in the logLevels array during runtime.
|
|
3314
|
-
*/
|
|
3315
|
-
getCurrentLogLevelIndex() {
|
|
3316
|
-
return this.logLevels.indexOf(this.sharedLogLevel.current);
|
|
3317
|
-
}
|
|
3318
|
-
/**
|
|
3319
|
-
* Resets the current log level to the initial level during runtime.
|
|
3320
|
-
*/
|
|
3321
|
-
resetLogLevel() {
|
|
3322
|
-
this.sharedLogLevel.current = this.sharedLogLevel.initial;
|
|
3323
|
-
}
|
|
3324
|
-
/**
|
|
3325
|
-
* Checks if the input log level is equal to the current log level of the PlaywrightReportLogger instance.
|
|
3326
|
-
*/
|
|
3327
|
-
isCurrentLogLevel(level) {
|
|
3328
|
-
return this.sharedLogLevel.current === level;
|
|
3329
|
-
}
|
|
3330
|
-
/**
|
|
3331
|
-
* Returns 'true' if the "level" parameter provided has an equal or greater index than the current logLevel.
|
|
3332
|
-
*/
|
|
3333
|
-
isLogLevelEnabled(level) {
|
|
3334
|
-
const logLevelIndex = this.logLevels.indexOf(level);
|
|
3335
|
-
if (logLevelIndex < this.getCurrentLogLevelIndex()) {
|
|
3336
|
-
return false;
|
|
3337
|
-
}
|
|
3338
|
-
return true;
|
|
3339
|
-
}
|
|
3340
|
-
/**
|
|
3341
|
-
* Attaches the recorded log entries to the Playwright HTML report in a sorted and formatted manner.
|
|
3342
|
-
*/
|
|
3343
|
-
attachLogsToTest(testInfo) {
|
|
3344
|
-
this.sharedLogEntry.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
3345
|
-
for (const log of this.sharedLogEntry) {
|
|
3346
|
-
const printTime = log.timestamp.toLocaleTimeString("nb-NO", {
|
|
3347
|
-
hour: "2-digit",
|
|
3348
|
-
minute: "2-digit",
|
|
3349
|
-
second: "2-digit"
|
|
3350
|
-
});
|
|
3351
|
-
const printDate = log.timestamp.toLocaleDateString("nb-NO", {
|
|
3352
|
-
day: "2-digit",
|
|
3353
|
-
month: "2-digit",
|
|
3354
|
-
year: "numeric"
|
|
3355
|
-
});
|
|
3356
|
-
const printLogLevel = `${log.logLevel.toUpperCase()}`;
|
|
3357
|
-
const printPrefix = log.prefix ? `: [${log.prefix}]` : "";
|
|
3358
|
-
let messageBody = "";
|
|
3359
|
-
let messageContentType = "";
|
|
3360
|
-
try {
|
|
3361
|
-
const parsedMessage = JSON.parse(log.message);
|
|
3362
|
-
messageContentType = "application/json";
|
|
3363
|
-
messageBody = JSON.stringify(parsedMessage, null, 2);
|
|
3364
|
-
} catch (_error) {
|
|
3365
|
-
messageContentType = "text/plain";
|
|
3366
|
-
messageBody = log.message;
|
|
3367
|
-
}
|
|
3368
|
-
testInfo.attach(`${printTime} ${printDate} - ${printLogLevel} ${printPrefix}`, {
|
|
3369
|
-
contentType: messageContentType,
|
|
3370
|
-
body: Buffer.from(messageBody)
|
|
3371
|
-
});
|
|
3372
|
-
}
|
|
3373
|
-
}
|
|
3374
|
-
};
|
|
3375
|
-
|
|
3376
|
-
// srcV2/fixture/base.fixtures.ts
|
|
3377
|
-
var test5 = import_test7.test.extend({
|
|
3378
|
-
// biome-ignore lint/correctness/noEmptyPattern: Playwright does not support the use of _
|
|
3379
|
-
log: async ({}, use, testInfo) => {
|
|
3380
|
-
const contextName = "TestCase";
|
|
3381
|
-
const sharedLogEntry = [];
|
|
3382
|
-
const sharedLogLevel = testInfo.retry === 0 ? { current: "warn", initial: "warn" } : { current: "debug", initial: "debug" };
|
|
3383
|
-
const log = new PlaywrightReportLogger(sharedLogLevel, sharedLogEntry, contextName);
|
|
3384
|
-
await use(log);
|
|
3385
|
-
log.attachLogsToTest(testInfo);
|
|
3386
|
-
}
|
|
3387
|
-
});
|
|
3388
|
-
|
|
3389
|
-
// srcV2/helpers/stepDecorator.ts
|
|
3390
|
-
var import_test8 = require("@playwright/test");
|
|
3391
|
-
var isMethodDecoratorArgs = (args) => args.length === 3 && typeof args[0] === "object" && (typeof args[1] === "string" || typeof args[1] === "symbol");
|
|
3392
|
-
var isStage3MethodDecoratorArgs = (args) => args.length === 2 && typeof args[0] === "function" && args[1] !== null && typeof args[1] === "object";
|
|
3393
|
-
var normalizeStepArguments = (args) => {
|
|
3394
|
-
const [titleOrOptions, maybeOptions] = args;
|
|
3395
|
-
const title = typeof titleOrOptions === "string" ? titleOrOptions : void 0;
|
|
3396
|
-
const options = typeof titleOrOptions === "string" ? maybeOptions : titleOrOptions;
|
|
3397
|
-
return { title, options };
|
|
3398
|
-
};
|
|
3399
|
-
var createWrappedMethod = (original, methodName, title, options) => function(...methodArgs) {
|
|
3400
|
-
const rawClassName = this.constructor?.name ?? "";
|
|
3401
|
-
const className = rawClassName && rawClassName !== "Object" ? rawClassName : "Anonymous";
|
|
3402
|
-
const resolvedTitle = title ?? `${className}.${String(methodName)}`;
|
|
3403
|
-
return import_test8.test.step(resolvedTitle, () => original.apply(this, methodArgs), options);
|
|
3404
|
-
};
|
|
3405
|
-
var createStepDecorator = ({ title, options }) => (valueOrTarget, contextOrKey, descriptor) => {
|
|
3406
|
-
if (typeof valueOrTarget === "function" && isStage3MethodDecoratorArgs([valueOrTarget, contextOrKey])) {
|
|
3407
|
-
const [original2, context] = [valueOrTarget, contextOrKey];
|
|
3408
|
-
return createWrappedMethod(original2, context.name, title, options);
|
|
3409
|
-
}
|
|
3410
|
-
if (!descriptor || typeof descriptor.value !== "function") {
|
|
3411
|
-
throw new Error("@step decorator can only be applied to methods.");
|
|
3412
|
-
}
|
|
3413
|
-
const original = descriptor.value;
|
|
3414
|
-
descriptor.value = createWrappedMethod(original, contextOrKey, title, options);
|
|
3415
|
-
return descriptor;
|
|
3416
|
-
};
|
|
3417
|
-
function step(...args) {
|
|
3418
|
-
if (isStage3MethodDecoratorArgs(args)) {
|
|
3419
|
-
return createStepDecorator(normalizeStepArguments([]))(...args);
|
|
3420
|
-
}
|
|
3421
|
-
if (isMethodDecoratorArgs(args)) {
|
|
3422
|
-
return createStepDecorator(normalizeStepArguments([]))(...args);
|
|
3423
|
-
}
|
|
3424
|
-
return createStepDecorator(normalizeStepArguments(args));
|
|
3425
|
-
}
|
|
3426
2144
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3427
2145
|
0 && (module.exports = {
|
|
3428
|
-
BaseApi,
|
|
3429
|
-
BasePage,
|
|
3430
|
-
BasePageV1toV2,
|
|
3431
|
-
GetByMethod,
|
|
3432
|
-
GetLocatorBase,
|
|
3433
2146
|
PageObject,
|
|
3434
2147
|
PlaywrightReportLogger,
|
|
3435
2148
|
SessionStorage,
|