pomwright 1.5.0 → 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.
Files changed (117) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +5 -5
  3. package/dist/index.d.mts +91 -989
  4. package/dist/index.d.ts +91 -989
  5. package/dist/index.js +627 -1887
  6. package/dist/index.mjs +633 -1888
  7. package/package.json +9 -11
  8. package/AGENTS.md +0 -37
  9. package/docs/v1/BaseApi-explanation.md +0 -63
  10. package/docs/v1/BasePage-explanation.md +0 -96
  11. package/docs/v1/LocatorSchema-explanation.md +0 -271
  12. package/docs/v1/LocatorSchemaPath-explanation.md +0 -165
  13. package/docs/v1/PlaywrightReportLogger-explanation.md +0 -56
  14. package/docs/v1/get-locator-methods-explanation.md +0 -250
  15. package/docs/v1/intro-to-using-pomwright.md +0 -899
  16. package/docs/v1/sessionStorage-methods-explanation.md +0 -38
  17. package/docs/v1/tips-folder-structure.md +0 -38
  18. package/docs/v1-to-v2-migration/bridge-migration-guide.md +0 -159
  19. package/docs/v1-to-v2-migration/direct-migration-guide.md +0 -238
  20. package/docs/v1-to-v2-migration/v1-to-v2-comparison.md +0 -547
  21. package/docs/v2/PageObject.md +0 -293
  22. package/docs/v2/composing-locator-modules.md +0 -93
  23. package/docs/v2/locator-registry.md +0 -693
  24. package/docs/v2/logging.md +0 -168
  25. package/docs/v2/overview.md +0 -515
  26. package/docs/v2/session-storage.md +0 -160
  27. package/index.ts +0 -75
  28. package/intTestV2/.env +0 -0
  29. package/intTestV2/fixtures/testApp.fixtures.ts +0 -43
  30. package/intTestV2/package.json +0 -22
  31. package/intTestV2/page-object-models/testApp/pages/iframe/iframe.locatorSchema.ts +0 -24
  32. package/intTestV2/page-object-models/testApp/pages/iframe/iframe.page.ts +0 -17
  33. package/intTestV2/page-object-models/testApp/pages/testPage.locatorSchema.ts +0 -32
  34. package/intTestV2/page-object-models/testApp/pages/testPage.page.ts +0 -119
  35. package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.locatorSchema.ts +0 -29
  36. package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.page.ts +0 -48
  37. package/intTestV2/page-object-models/testApp/pages/testPath/testPath.locatorSchema.ts +0 -9
  38. package/intTestV2/page-object-models/testApp/pages/testPath/testPath.page.ts +0 -23
  39. package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.locatorSchema.ts +0 -114
  40. package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.page.ts +0 -23
  41. package/intTestV2/page-object-models/testApp/testApp.base.ts +0 -20
  42. package/intTestV2/playwright.config.ts +0 -54
  43. package/intTestV2/server.js +0 -216
  44. package/intTestV2/test-data/staticPage/index.html +0 -280
  45. package/intTestV2/test-data/staticPage/w3images/avatar2.png +0 -0
  46. package/intTestV2/test-data/staticPage/w3images/avatar3.png +0 -0
  47. package/intTestV2/test-data/staticPage/w3images/avatar5.png +0 -0
  48. package/intTestV2/test-data/staticPage/w3images/avatar6.png +0 -0
  49. package/intTestV2/test-data/staticPage/w3images/forest.jpg +0 -0
  50. package/intTestV2/test-data/staticPage/w3images/lights.jpg +0 -0
  51. package/intTestV2/test-data/staticPage/w3images/mountains.jpg +0 -0
  52. package/intTestV2/test-data/staticPage/w3images/nature.jpg +0 -0
  53. package/intTestV2/test-data/staticPage/w3images/snow.jpg +0 -0
  54. package/intTestV2/tests/locatorRegistry/add/add.describe.spec.ts +0 -54
  55. package/intTestV2/tests/locatorRegistry/add/add.filter.spec.ts +0 -143
  56. package/intTestV2/tests/locatorRegistry/add/add.frameLocator.spec.ts +0 -23
  57. package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
  58. package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
  59. package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
  60. package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
  61. package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
  62. package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
  63. package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
  64. package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
  65. package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
  66. package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -66
  67. package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
  68. package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
  69. package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
  70. package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
  71. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
  72. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
  73. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
  74. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
  75. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
  76. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
  77. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
  78. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
  79. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
  80. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
  81. package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
  82. package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
  83. package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
  84. package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
  85. package/intTestV2/tests/step/step.spec.ts +0 -49
  86. package/intTestV2/tests/testApp/color.spec.ts +0 -15
  87. package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
  88. package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
  89. package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
  90. package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
  91. package/pack-build.sh +0 -11
  92. package/pack-test-v2.sh +0 -36
  93. package/playwright.base.ts +0 -42
  94. package/skills/README.md +0 -56
  95. package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
  96. package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
  97. package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
  98. package/skills/pomwright-v2-migration/SKILL.md +0 -63
  99. package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
  100. package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
  101. package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
  102. package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
  103. package/srcV2/fixture/base.fixtures.ts +0 -23
  104. package/srcV2/helpers/navigation.ts +0 -153
  105. package/srcV2/helpers/playwrightReportLogger.ts +0 -196
  106. package/srcV2/helpers/sessionStorage.ts +0 -251
  107. package/srcV2/helpers/stepDecorator.ts +0 -106
  108. package/srcV2/locators/index.ts +0 -15
  109. package/srcV2/locators/locatorQueryBuilder.ts +0 -427
  110. package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
  111. package/srcV2/locators/locatorRegistry.ts +0 -541
  112. package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
  113. package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
  114. package/srcV2/locators/types.ts +0 -256
  115. package/srcV2/locators/utils.ts +0 -309
  116. package/srcV2/locators/v1SchemaTranslator.ts +0 -178
  117. package/srcV2/pageObject.ts +0 -105
package/dist/index.mjs CHANGED
@@ -1,1201 +1,311 @@
1
- // src/helpers/locatorSchema.interface.ts
2
- var GetByMethod = /* @__PURE__ */ ((GetByMethod2) => {
3
- GetByMethod2["role"] = "role";
4
- GetByMethod2["text"] = "text";
5
- GetByMethod2["label"] = "label";
6
- GetByMethod2["placeholder"] = "placeholder";
7
- GetByMethod2["altText"] = "altText";
8
- GetByMethod2["title"] = "title";
9
- GetByMethod2["locator"] = "locator";
10
- GetByMethod2["frameLocator"] = "frameLocator";
11
- GetByMethod2["testId"] = "testId";
12
- GetByMethod2["dataCy"] = "dataCy";
13
- GetByMethod2["id"] = "id";
14
- return GetByMethod2;
15
- })(GetByMethod || {});
16
- var locatorSchemaDummy = {
17
- role: void 0,
18
- roleOptions: {
19
- checked: void 0,
20
- disabled: void 0,
21
- exact: void 0,
22
- expanded: void 0,
23
- includeHidden: void 0,
24
- level: void 0,
25
- name: void 0,
26
- pressed: void 0,
27
- selected: void 0
28
- },
29
- text: void 0,
30
- textOptions: {
31
- exact: void 0
32
- },
33
- label: void 0,
34
- labelOptions: {
35
- exact: void 0
36
- },
37
- placeholder: void 0,
38
- placeholderOptions: {
39
- exact: void 0
40
- },
41
- altText: void 0,
42
- altTextOptions: {
43
- exact: void 0
44
- },
45
- title: void 0,
46
- titleOptions: {
47
- exact: void 0
48
- },
49
- locator: void 0,
50
- locatorOptions: {
51
- has: void 0,
52
- hasNot: void 0,
53
- hasNotText: void 0,
54
- hasText: void 0
55
- },
56
- frameLocator: void 0,
57
- testId: void 0,
58
- dataCy: void 0,
59
- id: void 0,
60
- filter: {
61
- has: void 0,
62
- hasNot: void 0,
63
- hasNotText: void 0,
64
- hasText: void 0
65
- },
66
- locatorMethod: void 0,
67
- locatorSchemaPath: void 0
68
- };
69
- function getLocatorSchemaDummy() {
70
- return locatorSchemaDummy;
71
- }
1
+ // src/fixture/base.fixtures.ts
2
+ import { test as base } from "@playwright/test";
72
3
 
73
- // src/helpers/deprecationWarnings.ts
74
- var warnedDeprecationsByScope = /* @__PURE__ */ new WeakMap();
75
- var getWarningScope = (logger) => {
76
- if (!logger) {
77
- return globalThis;
78
- }
79
- const maybeSharedLogEntries = logger.sharedLogEntry;
80
- if (Array.isArray(maybeSharedLogEntries)) {
81
- return maybeSharedLogEntries;
4
+ // src/helpers/playwrightReportLogger.ts
5
+ var PlaywrightReportLogger = class _PlaywrightReportLogger {
6
+ // Initializes the logger with shared log level, log entries, and a context name.
7
+ constructor(sharedLogLevel, sharedLogEntry, contextName) {
8
+ this.sharedLogLevel = sharedLogLevel;
9
+ this.sharedLogEntry = sharedLogEntry;
10
+ this.contextName = contextName;
82
11
  }
83
- return logger;
84
- };
85
- var warnDeprecationOncePerTest = (key, message, logger) => {
86
- const warningScope = getWarningScope(logger);
87
- const warnedDeprecations = warnedDeprecationsByScope.get(warningScope) ?? /* @__PURE__ */ new Set();
88
- if (warnedDeprecations.has(key)) {
89
- return;
90
- }
91
- warnedDeprecations.add(key);
92
- warnedDeprecationsByScope.set(warningScope, warnedDeprecations);
93
- logger?.warn(message);
94
- };
95
-
96
- // src/api/baseApi.ts
97
- var BaseApi = class {
98
- baseUrl;
99
- apiName;
100
- log;
101
- request;
102
- constructor(baseUrl, apiName, context, pwrl) {
103
- this.baseUrl = baseUrl;
104
- this.apiName = apiName;
105
- this.log = pwrl.getNewChildLogger(apiName);
106
- this.request = context;
107
- 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.";
108
- warnDeprecationOncePerTest(`${this.constructor.name}-class-deprecation`, classDeprecationMessage, this.log);
12
+ contextName;
13
+ logLevels = ["debug", "info", "warn", "error"];
14
+ /**
15
+ * Creates a child logger with a new contextual name, sharing the same log level and log entries with the parent logger.
16
+ *
17
+ * The root loggers log "level" is referenced by all child loggers and their child loggers and so on...
18
+ * Changing the log "level" of one, will change it for all.
19
+ */
20
+ getNewChildLogger(prefix) {
21
+ return new _PlaywrightReportLogger(this.sharedLogLevel, this.sharedLogEntry, `${this.contextName} -> ${prefix}`);
109
22
  }
110
- };
111
-
112
- // src/basePage.ts
113
- import { selectors } from "@playwright/test";
114
-
115
- // src/helpers/getLocatorBase.ts
116
- import { test } from "@playwright/test";
23
+ /**
24
+ * Logs a message with the specified log level, prefix, and additional arguments if the current log level permits.
25
+ */
26
+ // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
27
+ log(level, message, ...args) {
28
+ const logLevelIndex = this.logLevels.indexOf(level);
29
+ if (logLevelIndex < this.getCurrentLogLevelIndex()) {
30
+ return;
31
+ }
32
+ this.sharedLogEntry.push({
33
+ timestamp: /* @__PURE__ */ new Date(),
34
+ logLevel: level,
35
+ prefix: this.contextName,
36
+ message: `${message}
117
37
 
118
- // srcV2/locators/utils.ts
119
- var formatLocatorSchemaPathForError = (path) => {
120
- const json = JSON.stringify(path);
121
- return json.slice(1, -1);
122
- };
123
- var RUNTIME_WHITESPACE_REGEX = /[\s\u0085]/u;
124
- var validateLocatorSchemaPath = (path) => {
125
- if (!path) {
126
- throw new Error("LocatorSchemaPath string cannot be empty");
38
+ ${args.join("\n\n")}`
39
+ });
127
40
  }
128
- if (RUNTIME_WHITESPACE_REGEX.test(path)) {
129
- const escaped = formatLocatorSchemaPathForError(path);
130
- throw new Error(`LocatorSchemaPath string cannot contain whitespace chars: ${escaped}`);
41
+ /**
42
+ * Logs a debug-level message with the specified message and arguments.
43
+ */
44
+ // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
45
+ debug(message, ...args) {
46
+ this.log("debug", message, ...args);
131
47
  }
132
- if (path.startsWith(".")) {
133
- throw new Error(`LocatorSchemaPath string cannot start with a dot: ${path}`);
48
+ /**
49
+ * Logs a info-level message with the specified message and arguments.
50
+ */
51
+ // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
52
+ info(message, ...args) {
53
+ this.log("info", message, ...args);
134
54
  }
135
- if (path.endsWith(".")) {
136
- throw new Error(`LocatorSchemaPath string cannot end with a dot: ${path}`);
55
+ /**
56
+ * Logs a warn-level message with the specified message and arguments.
57
+ */
58
+ // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
59
+ warn(message, ...args) {
60
+ this.log("warn", message, ...args);
137
61
  }
138
- if (path.includes("..")) {
139
- throw new Error(`LocatorSchemaPath string cannot contain consecutive dots: ${path}`);
62
+ /**
63
+ * Logs a error-level message with the specified message and arguments.
64
+ */
65
+ // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
66
+ error(message, ...args) {
67
+ this.log("error", message, ...args);
140
68
  }
141
- };
142
- var expandSchemaPath = (path) => {
143
- validateLocatorSchemaPath(path);
144
- const parts = path.split(".");
145
- return parts.map((_part, index) => parts.slice(0, index + 1).join("."));
146
- };
147
- var cssEscape = (value) => {
148
- return value.replace(/([\\"'#.:;,?*+<>{}[\\]()])/g, "\\$1");
149
- };
150
- var normalizeSteps = (steps) => steps ? steps.map((step2) => ({ ...step2 })) : [];
151
- function normalizeIdValue(id) {
152
- if (typeof id !== "string") {
153
- return id;
69
+ /**
70
+ * Sets the current log level to the specified level during runTime.
71
+ */
72
+ setLogLevel(level) {
73
+ this.sharedLogLevel.current = level;
154
74
  }
155
- if (id.startsWith("#")) {
156
- return id.slice(1);
75
+ /**
76
+ * Retrieves the current log level during runtime.
77
+ */
78
+ getCurrentLogLevel() {
79
+ return this.sharedLogLevel.current;
157
80
  }
158
- if (id.startsWith("id=")) {
159
- return id.slice("id=".length);
81
+ /**
82
+ * Retrieves the index of the current log level in the logLevels array during runtime.
83
+ */
84
+ getCurrentLogLevelIndex() {
85
+ return this.logLevels.indexOf(this.sharedLogLevel.current);
160
86
  }
161
- return id;
162
- }
163
- var stringifyForLog = (value) => {
164
- const seen = /* @__PURE__ */ new WeakSet();
165
- return JSON.stringify(
166
- value,
167
- (_key, current) => {
168
- if (typeof current === "object" && current !== null) {
169
- if (seen.has(current)) {
170
- return "[Circular]";
171
- }
172
- seen.add(current);
173
- }
174
- if (current instanceof RegExp) {
175
- return { type: "RegExp", source: current.source, flags: current.flags };
176
- }
177
- return current;
178
- },
179
- 2
180
- );
181
- };
182
- var applyIndexSelector = (locator, selector) => {
183
- if (selector === void 0 || selector === null) {
184
- return locator;
87
+ /**
88
+ * Resets the current log level to the initial level during runtime.
89
+ */
90
+ resetLogLevel() {
91
+ this.sharedLogLevel.current = this.sharedLogLevel.initial;
185
92
  }
186
- if (selector === "first") {
187
- return locator.first();
93
+ /**
94
+ * Checks if the input log level is equal to the current log level of the PlaywrightReportLogger instance.
95
+ */
96
+ isCurrentLogLevel(level) {
97
+ return this.sharedLogLevel.current === level;
188
98
  }
189
- if (selector === "last") {
190
- return locator.last();
99
+ /**
100
+ * Returns 'true' if the "level" parameter provided has an equal or greater index than the current logLevel.
101
+ */
102
+ isLogLevelEnabled(level) {
103
+ const logLevelIndex = this.logLevels.indexOf(level);
104
+ if (logLevelIndex < this.getCurrentLogLevelIndex()) {
105
+ return false;
106
+ }
107
+ return true;
191
108
  }
192
- return locator.nth(selector);
193
- };
194
- var createLocator = (target, definition) => {
195
- switch (definition.type) {
196
- case "role":
197
- return target.getByRole(definition.role, definition.options);
198
- case "text":
199
- return target.getByText(definition.text, definition.options);
200
- case "label":
201
- return target.getByLabel(definition.text, definition.options);
202
- case "placeholder":
203
- return target.getByPlaceholder(definition.text, definition.options);
204
- case "altText":
205
- return target.getByAltText(definition.text, definition.options);
206
- case "title":
207
- return target.getByTitle(definition.text, definition.options);
208
- case "locator":
209
- return target.locator(definition.selector, definition.options);
210
- case "frameLocator":
211
- return target.frameLocator(definition.selector);
212
- case "testId":
213
- return target.getByTestId(definition.testId);
214
- case "id": {
215
- if (typeof definition.id === "string") {
216
- const normalized = normalizeIdValue(definition.id);
217
- return target.locator(`#${cssEscape(normalized ?? "")}`);
109
+ /**
110
+ * Attaches the recorded log entries to the Playwright HTML report in a sorted and formatted manner.
111
+ */
112
+ attachLogsToTest(testInfo) {
113
+ this.sharedLogEntry.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
114
+ for (const log of this.sharedLogEntry) {
115
+ const printTime = log.timestamp.toLocaleTimeString("nb-NO", {
116
+ hour: "2-digit",
117
+ minute: "2-digit",
118
+ second: "2-digit"
119
+ });
120
+ const printDate = log.timestamp.toLocaleDateString("nb-NO", {
121
+ day: "2-digit",
122
+ month: "2-digit",
123
+ year: "numeric"
124
+ });
125
+ const printLogLevel = `${log.logLevel.toUpperCase()}`;
126
+ const printPrefix = log.prefix ? `: [${log.prefix}]` : "";
127
+ let messageBody = "";
128
+ let messageContentType = "";
129
+ try {
130
+ const parsedMessage = JSON.parse(log.message);
131
+ messageContentType = "application/json";
132
+ messageBody = JSON.stringify(parsedMessage, null, 2);
133
+ } catch (_error) {
134
+ messageContentType = "text/plain";
135
+ messageBody = log.message;
218
136
  }
219
- const pattern = definition.id.source;
220
- const safePattern = cssEscape(pattern);
221
- return target.locator(`[id*="${safePattern}"]`);
222
- }
223
- default: {
224
- const exhaustive = definition;
225
- return exhaustive;
137
+ testInfo.attach(`${printTime} ${printDate} - ${printLogLevel} ${printPrefix}`, {
138
+ contentType: messageContentType,
139
+ body: Buffer.from(messageBody)
140
+ });
226
141
  }
227
142
  }
228
143
  };
229
- var cloneLocatorStrategyDefinition = (definition) => {
230
- switch (definition.type) {
231
- case "role":
232
- return {
233
- type: "role",
234
- role: definition.role,
235
- ...definition.options ? { options: { ...definition.options } } : {}
236
- };
237
- case "text":
238
- return {
239
- type: "text",
240
- text: definition.text,
241
- ...definition.options ? { options: { ...definition.options } } : {}
242
- };
243
- case "label":
244
- return {
245
- type: "label",
246
- text: definition.text,
247
- ...definition.options ? { options: { ...definition.options } } : {}
248
- };
249
- case "placeholder":
250
- return {
251
- type: "placeholder",
252
- text: definition.text,
253
- ...definition.options ? { options: { ...definition.options } } : {}
254
- };
255
- case "altText":
256
- return {
257
- type: "altText",
258
- text: definition.text,
259
- ...definition.options ? { options: { ...definition.options } } : {}
260
- };
261
- case "title":
262
- return {
263
- type: "title",
264
- text: definition.text,
265
- ...definition.options ? { options: { ...definition.options } } : {}
266
- };
267
- case "locator":
268
- return {
269
- type: "locator",
270
- selector: definition.selector,
271
- ...definition.options ? { options: { ...definition.options } } : {}
272
- };
273
- case "frameLocator":
274
- return { type: "frameLocator", selector: definition.selector };
275
- case "testId":
276
- return { type: "testId", testId: definition.testId };
277
- case "id":
278
- return { type: "id", id: definition.id };
279
- default: {
280
- const exhaustive = definition;
281
- return exhaustive;
282
- }
283
- }
284
- };
285
- var applyDefinitionPatch = (seed, patch) => {
286
- const base2 = cloneLocatorStrategyDefinition(seed);
287
- switch (patch.type) {
288
- case "locator": {
289
- const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
290
- const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
291
- return { type: "locator", selector, ...options ? { options } : {} };
292
- }
293
- case "role": {
294
- const role = patch.role ?? base2.role;
295
- const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
296
- return { type: "role", role, ...options ? { options } : {} };
297
- }
298
- case "text": {
299
- const text = patch.text ?? base2.text;
300
- const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
301
- return { type: "text", text, ...options ? { options } : {} };
302
- }
303
- case "label": {
304
- const text = patch.text ?? base2.text;
305
- const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
306
- return { type: "label", text, ...options ? { options } : {} };
307
- }
308
- case "placeholder": {
309
- const text = patch.text ?? base2.text;
310
- const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
311
- return { type: "placeholder", text, ...options ? { options } : {} };
312
- }
313
- case "altText": {
314
- const text = patch.text ?? base2.text;
315
- const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
316
- return { type: "altText", text, ...options ? { options } : {} };
317
- }
318
- case "title": {
319
- const text = patch.text ?? base2.text;
320
- const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
321
- return { type: "title", text, ...options ? { options } : {} };
322
- }
323
- case "frameLocator": {
324
- const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
325
- return { type: "frameLocator", selector };
326
- }
327
- case "testId": {
328
- const testId = patch.testId !== void 0 ? patch.testId : base2.testId;
329
- return { type: "testId", testId };
330
- }
331
- case "id": {
332
- const id = patch.id !== void 0 ? normalizeIdValue(patch.id) ?? base2.id : base2.id;
333
- return { type: "id", id };
334
- }
335
- default: {
336
- const exhaustive = patch;
337
- return exhaustive;
338
- }
144
+
145
+ // src/fixture/base.fixtures.ts
146
+ var test = base.extend({
147
+ // biome-ignore lint/correctness/noEmptyPattern: Playwright does not support the use of _
148
+ log: async ({}, use, testInfo) => {
149
+ const contextName = "TestCase";
150
+ const sharedLogEntry = [];
151
+ const sharedLogLevel = testInfo.retry === 0 ? { current: "warn", initial: "warn" } : { current: "debug", initial: "debug" };
152
+ const log = new PlaywrightReportLogger(sharedLogLevel, sharedLogEntry, contextName);
153
+ await use(log);
154
+ log.attachLogsToTest(testInfo);
339
155
  }
340
- };
341
- var isFrameLocatorDefinition = (definition) => definition.type === "frameLocator";
342
- var isLocatorInstance = (value) => {
343
- return !!value && typeof value === "object" && typeof value.filter === "function";
344
- };
156
+ });
345
157
 
346
- // srcV2/locators/v1SchemaTranslator.ts
347
- var getRegistryLookup = (registry) => registry;
348
- var logMissingDefinition = (path, field) => {
349
- console.warn(
350
- `[POMWright] Skipping v2 translation for "${path}" because "${field}" is missing. Rewrite this locator in defineLocators() using the v2 registry.`
351
- );
352
- };
353
- var logLocatorInstanceWarning = (path) => {
354
- console.warn(
355
- `[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.`
356
- );
357
- };
358
- var addV1SchemaToV2Registry = (registry, locatorSchema) => {
359
- const path = locatorSchema.locatorSchemaPath;
360
- validateLocatorSchemaPath(path);
361
- const registryWithLookup = getRegistryLookup(registry);
362
- const existing = registryWithLookup.getIfExists?.(path);
363
- if (existing) {
364
- return;
158
+ // src/helpers/sessionStorage.ts
159
+ import { test as test2 } from "@playwright/test";
160
+ var SessionStorage = class {
161
+ // Initializes the class with a Playwright Page object and an optional label for step titles.
162
+ constructor(page, options = {}) {
163
+ this.page = page;
164
+ this.options = options;
365
165
  }
366
- console.info(
367
- `[POMWright] LocatorSchemaPath "${path}" is not registered in the v2 registry. Translating and adding v1 schema to v2 Locator Registry; update this path to use registry.add in defineLocators().`
368
- );
369
- const registration = registry.add(path);
370
- if (!registration) {
371
- return;
372
- }
373
- let postDefinition = null;
374
- switch (locatorSchema.locatorMethod) {
375
- case "role" /* role */: {
376
- if (!locatorSchema.role) {
377
- logMissingDefinition(path, "role");
378
- return;
379
- }
380
- postDefinition = registration.getByRole(locatorSchema.role, locatorSchema.roleOptions);
381
- break;
382
- }
383
- case "text" /* text */: {
384
- if (!locatorSchema.text) {
385
- logMissingDefinition(path, "text");
386
- return;
387
- }
388
- postDefinition = registration.getByText(locatorSchema.text, locatorSchema.textOptions);
389
- break;
390
- }
391
- case "label" /* label */: {
392
- if (!locatorSchema.label) {
393
- logMissingDefinition(path, "label");
394
- return;
395
- }
396
- postDefinition = registration.getByLabel(locatorSchema.label, locatorSchema.labelOptions);
397
- break;
398
- }
399
- case "placeholder" /* placeholder */: {
400
- if (!locatorSchema.placeholder) {
401
- logMissingDefinition(path, "placeholder");
402
- return;
403
- }
404
- postDefinition = registration.getByPlaceholder(locatorSchema.placeholder, locatorSchema.placeholderOptions);
405
- break;
406
- }
407
- case "altText" /* altText */: {
408
- if (!locatorSchema.altText) {
409
- logMissingDefinition(path, "altText");
410
- return;
411
- }
412
- postDefinition = registration.getByAltText(locatorSchema.altText, locatorSchema.altTextOptions);
413
- break;
414
- }
415
- case "title" /* title */: {
416
- if (!locatorSchema.title) {
417
- logMissingDefinition(path, "title");
418
- return;
419
- }
420
- postDefinition = registration.getByTitle(locatorSchema.title, locatorSchema.titleOptions);
421
- break;
422
- }
423
- case "locator" /* locator */: {
424
- if (!locatorSchema.locator) {
425
- logMissingDefinition(path, "locator");
426
- return;
427
- }
428
- if (isLocatorInstance(locatorSchema.locator)) {
429
- logLocatorInstanceWarning(path);
430
- return;
431
- }
432
- postDefinition = registration.locator(locatorSchema.locator, locatorSchema.locatorOptions);
433
- break;
434
- }
435
- case "frameLocator" /* frameLocator */: {
436
- if (!locatorSchema.frameLocator) {
437
- logMissingDefinition(path, "frameLocator");
438
- return;
439
- }
440
- postDefinition = registration.frameLocator(locatorSchema.frameLocator);
441
- break;
442
- }
443
- case "testId" /* testId */: {
444
- if (!locatorSchema.testId) {
445
- logMissingDefinition(path, "testId");
446
- return;
447
- }
448
- postDefinition = registration.getByTestId(locatorSchema.testId);
449
- break;
450
- }
451
- case "dataCy" /* dataCy */: {
452
- if (!locatorSchema.dataCy) {
453
- logMissingDefinition(path, "dataCy");
166
+ // Defines an object to hold states to be set in session storage, allowing any value type.
167
+ queuedStates = {};
168
+ // Indicates if the session storage manipulation has been initiated.
169
+ isInitiated = false;
170
+ getStepLabel(methodName) {
171
+ const prefix = this.options.label ? `${this.options.label}.` : "";
172
+ return `${prefix}SessionStorage.${methodName}:`;
173
+ }
174
+ async hasContext() {
175
+ return await this.page.evaluate(() => {
176
+ return typeof window !== "undefined" && window.sessionStorage !== void 0;
177
+ });
178
+ }
179
+ async waitForContextAvailability() {
180
+ try {
181
+ const contextExists = await this.hasContext();
182
+ if (contextExists) {
454
183
  return;
455
184
  }
456
- postDefinition = registration.locator(`[data-cy="${locatorSchema.dataCy}"]`);
457
- break;
185
+ } catch (_e) {
458
186
  }
459
- case "id" /* id */: {
460
- if (!locatorSchema.id) {
461
- logMissingDefinition(path, "id");
187
+ await new Promise((resolve) => {
188
+ const handler = async (frame) => {
189
+ if (frame !== this.page.mainFrame()) {
190
+ return;
191
+ }
192
+ try {
193
+ const contextExists = await this.hasContext();
194
+ if (!contextExists) {
195
+ return;
196
+ }
197
+ } catch (_e) {
198
+ return;
199
+ }
200
+ this.page.off("framenavigated", handler);
201
+ resolve();
202
+ };
203
+ this.page.on("framenavigated", handler);
204
+ });
205
+ }
206
+ async ensureContext({ waitForContext = false } = {}) {
207
+ try {
208
+ const contextExists = await this.hasContext();
209
+ if (contextExists) {
462
210
  return;
463
211
  }
464
- postDefinition = registration.getById(locatorSchema.id);
465
- break;
212
+ } catch (_e) {
466
213
  }
467
- default: {
468
- const exhaustive = locatorSchema.locatorMethod;
469
- return exhaustive;
214
+ if (!waitForContext) {
215
+ throw new Error("SessionStorage context is not available.");
470
216
  }
217
+ await this.waitForContextAvailability();
471
218
  }
472
- if (!postDefinition) {
473
- return;
474
- }
475
- if (locatorSchema.filter && locatorSchema.locatorMethod !== "frameLocator" /* frameLocator */) {
476
- const filter = locatorSchema.filter;
477
- postDefinition.filter(filter);
219
+ /** Writes states to session storage. Accepts an object with key-value pairs representing the states. */
220
+ async writeToSessionStorage(states) {
221
+ await this.page.evaluate((storage) => {
222
+ for (const [key, value] of Object.entries(storage)) {
223
+ window.sessionStorage.setItem(key, JSON.stringify(value));
224
+ }
225
+ }, states);
478
226
  }
479
- };
480
-
481
- // src/helpers/getBy.locator.ts
482
- var GetBy = class {
483
- constructor(page, pwrl) {
484
- this.page = page;
485
- this.log = pwrl.getNewChildLogger(this.constructor.name);
486
- this.methodMap = {
487
- ["role" /* role */]: this.role,
488
- ["text" /* text */]: this.text,
489
- ["label" /* label */]: this.label,
490
- ["placeholder" /* placeholder */]: this.placeholder,
491
- ["altText" /* altText */]: this.altText,
492
- ["title" /* title */]: this.title,
493
- ["locator" /* locator */]: this.locator,
494
- ["frameLocator" /* frameLocator */]: this.frameLocator,
495
- ["testId" /* testId */]: this.testId,
496
- ["dataCy" /* dataCy */]: this.dataCy,
497
- ["id" /* id */]: this.id
498
- };
499
- this.subMethodMap = {
500
- ["role" /* role */]: this.page.getByRole,
501
- ["text" /* text */]: this.page.getByText,
502
- ["label" /* label */]: this.page.getByLabel,
503
- ["placeholder" /* placeholder */]: this.page.getByPlaceholder,
504
- ["altText" /* altText */]: this.page.getByAltText,
505
- ["title" /* title */]: this.page.getByTitle,
506
- ["locator" /* locator */]: this.page.locator
507
- };
227
+ /** Reads all states from session storage and returns them as an object. */
228
+ async readFromSessionStorage() {
229
+ const storage = await this.page.evaluate(() => {
230
+ const storage2 = {};
231
+ for (let i = 0; i < sessionStorage.length; i++) {
232
+ const key = sessionStorage.key(i);
233
+ if (key !== null) {
234
+ const item = sessionStorage.getItem(key);
235
+ try {
236
+ storage2[key] = item ? JSON.parse(item) : null;
237
+ } catch (_e) {
238
+ storage2[key] = item;
239
+ }
240
+ }
241
+ }
242
+ return storage2;
243
+ });
244
+ return storage;
508
245
  }
509
- log;
510
- methodMap;
511
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
512
- subMethodMap;
513
246
  /**
514
- * Retrieves a Locator based on the details provided in a LocatorSchema.
515
- * The method identifies the appropriate locator creation function from methodMap and invokes it.
516
- * Throws an error if the locator method is unsupported.
517
- */
518
- getLocator = (locatorSchema) => {
519
- const methodName = locatorSchema.locatorMethod;
520
- const method = this.methodMap[methodName];
521
- if (method) {
522
- return method(locatorSchema);
523
- }
524
- throw new Error(`Unsupported locator method: ${methodName}`);
525
- };
526
- /**
527
- * Internal method to retrieve a Locator using a specified GetByMethodSubset and LocatorSchema.
528
- * It identifies the appropriate locator creation function from subMethodMap and invokes it.
529
- * Throws an error if the caller is unknown or if the initial locator is not found.
247
+ * Sets the specified states in session storage.
248
+ * Optionally waits for the next main-frame navigation to establish a valid context before writing,
249
+ * and reloads the page after setting the data.
250
+ *
251
+ * Parameters:
252
+ * states: Object representing the states to set in session storage.
253
+ * reload: Boolean indicating whether to reload the page after setting the session storage data.
254
+ * waitForContext: Boolean indicating whether to wait for a main-frame navigation and a valid context.
530
255
  */
531
- getBy = (caller, locator) => {
532
- const method = this.subMethodMap[caller];
533
- if (!method) {
534
- const errorText = "Error: unknown caller of method getBy(caller, locator) in getBy.locators.ts";
535
- this.log.error(errorText);
536
- throw new Error(errorText);
537
- }
538
- const initialPWLocator = locator[caller] ? method.call(this.page, locator[caller], locator?.[`${caller}Options`]) : null;
539
- if (!initialPWLocator) {
540
- const errorText = `Locator "${locator.locatorSchemaPath}" .${caller} is undefined.`;
541
- this.log.warn(errorText);
542
- throw new Error(errorText);
543
- }
544
- return initialPWLocator;
545
- };
256
+ async set(states, options = {}) {
257
+ await test2.step(this.getStepLabel("set"), async () => {
258
+ await this.ensureContext({ waitForContext: options.waitForContext });
259
+ await this.writeToSessionStorage(states);
260
+ if (options.reload) {
261
+ await this.page.reload();
262
+ }
263
+ });
264
+ }
546
265
  /**
547
- * Creates a method for generating a Locator using a specific GetByMethodSubset.
548
- * Returns a function that takes a LocatorSchema and returns a Locator.
549
- * The returned function is a locator creation function corresponding to the specified methodName.
266
+ * Queues states to be set in the sessionStorage before the next navigation occurs.
267
+ * Handles different scenarios based on multiple calls made before the navigation occurs.
268
+ *
269
+ * 1. No Context, Single Call: Queues and sets states upon the next navigation.
270
+ * 2. No Context, Multiple Calls: Merges states from multiple calls and sets them upon the next navigation.
271
+ * 3. With Context: Still queues until the next navigation.
272
+ *
273
+ * Parameters:
274
+ * states: Object representing the states to queue for setting in session storage.
550
275
  */
551
- createByMethod = (methodName) => {
552
- return (locator) => {
553
- return this.getBy(methodName, locator);
276
+ async setOnNextNavigation(states) {
277
+ this.queuedStates = { ...this.queuedStates, ...states };
278
+ const populateStorage = async () => {
279
+ await test2.step(this.getStepLabel("setOnNextNavigation"), async () => {
280
+ await this.writeToSessionStorage(this.queuedStates);
281
+ });
282
+ this.queuedStates = {};
554
283
  };
555
- };
556
- // Methods for creating locators using different locator methods.
557
- // These methods are generated using createByMethod and provide a unified way to create locators based on LocatorSchema.
558
- // Each method is responsible for creating a Locator based on a specific attribute (role, text, label, etc.) provided in LocatorSchema.
559
- // These methods return a Locator and throw an error if the necessary attribute is not defined in the LocatorSchema.
560
- role = this.createByMethod("role" /* role */);
561
- text = this.createByMethod("text" /* text */);
562
- label = this.createByMethod("label" /* label */);
563
- placeholder = this.createByMethod("placeholder" /* placeholder */);
564
- altText = this.createByMethod("altText" /* altText */);
565
- title = this.createByMethod("title" /* title */);
566
- locator = this.createByMethod("locator" /* locator */);
567
- /**
568
- * Returns a FrameLocator using the 'frameLocator' selector from a LocatorSchema.
569
- * Throws an error if the frameLocator is not defined.
570
- */
571
- frameLocator = (locatorSchema) => {
572
- const initialFrameLocator = locatorSchema.frameLocator ? this.page.frameLocator(locatorSchema.frameLocator) : null;
573
- if (!initialFrameLocator) {
574
- const errorText = `Locator "${locatorSchema.locatorSchemaPath}" .frameLocator is not defined.`;
575
- this.log.warn(errorText);
576
- throw new Error(errorText);
577
- }
578
- return initialFrameLocator;
579
- };
580
- /**
581
- * Returns a Locator using the 'testId' selector from a LocatorSchema.
582
- * Throws an error if the testId is not defined.
583
- */
584
- testId = (locator) => {
585
- const initialPWLocator = locator.testId ? this.page.getByTestId(locator.testId) : null;
586
- if (!initialPWLocator) {
587
- const errorText = `Locator "${locator.locatorSchemaPath}" .testId is not defined.`;
588
- this.log.warn(`Locator "${locator.locatorSchemaPath}" .testId is not defined.`);
589
- throw new Error(errorText);
590
- }
591
- return initialPWLocator;
592
- };
593
- /**
594
- * Returns a Locator using the 'dataCy' selector from a LocatorSchema.
595
- * Throws an error if the dataCy is undefined.
596
- */
597
- dataCy = (locator) => {
598
- let initialPWLocator = null;
599
- if (locator.dataCy) {
600
- initialPWLocator = locator.dataCy.startsWith("data-cy=") ? this.page.locator(locator.dataCy) : this.page.locator(`data-cy=${locator.dataCy}`);
601
- } else {
602
- const errorText = `Locator "${locator.locatorSchemaPath}" .dataCy is undefined.`;
603
- this.log.warn(errorText);
604
- throw new Error(errorText);
605
- }
606
- return initialPWLocator;
607
- };
608
- /**
609
- * Returns a Locator using the 'id' selector from a LocatorSchema.
610
- * Throws an error if the id is not defined or the id type is unsupported.
611
- */
612
- id = (locator) => {
613
- let initialPWLocator = null;
614
- let selector;
615
- let regexPattern;
616
- if (!locator.id) {
617
- const errorText = `Locator "${locator.locatorSchemaPath}" .id is not defined.`;
618
- this.log.warn(errorText);
619
- throw new Error(errorText);
620
- }
621
- if (typeof locator.id === "string") {
622
- if (locator.id.startsWith("#")) {
623
- selector = locator.id;
624
- } else if (locator.id.startsWith("id=")) {
625
- selector = `#${locator.id.slice("id=".length)}`;
626
- } else {
627
- selector = `#${locator.id}`;
628
- }
629
- } else if (locator.id instanceof RegExp) {
630
- regexPattern = locator.id.source;
631
- selector = `*[id^="${regexPattern}"]`;
632
- } else {
633
- const errorText = `Unsupported id type: ${typeof locator.id}`;
634
- this.log.error(errorText);
635
- throw new Error(errorText);
636
- }
637
- initialPWLocator = this.page.locator(selector);
638
- return initialPWLocator;
639
- };
640
- };
641
-
642
- // src/helpers/getLocatorBase.ts
643
- var REQUIRED_PROPERTIES_FOR_LOCATOR_SCHEMA_WITH_METHODS = [
644
- "update",
645
- "addFilter",
646
- "getNestedLocator",
647
- "getLocator",
648
- "locatorSchemaPath",
649
- "locatorMethod",
650
- "schemasMap",
651
- "filterMap"
652
- ];
653
- var safeStringifyOfNestedLocatorResults = (obj) => {
654
- const seen = /* @__PURE__ */ new WeakSet();
655
- return JSON.stringify(
656
- obj,
657
- (key, value) => {
658
- if (value instanceof Map) {
659
- return Array.from(value.entries());
660
- }
661
- if (value instanceof RegExp) {
662
- return { type: "RegExp", source: value.source, flags: value.flags };
663
- }
664
- if (value && typeof value === "object" && value.constructor && value.constructor.name === "Locator") {
665
- return { type: "Locator", note: "Custom placeholder - Locators are complex." };
666
- }
667
- if (typeof value === "object" && value !== null) {
668
- if (seen.has(value)) return "[Circular]";
669
- seen.add(value);
670
- }
671
- return value;
672
- },
673
- 2
674
- );
675
- };
676
- var GetLocatorBase = class {
677
- constructor(pageObjectClass, log, locatorSubstring) {
678
- this.pageObjectClass = pageObjectClass;
679
- this.log = log;
680
- this.locatorSubstring = locatorSubstring;
681
- this.locatorSchemas = /* @__PURE__ */ new Map();
682
- this.getBy = new GetBy(this.pageObjectClass.page, this.log.getNewChildLogger("GetBy"));
683
- }
684
- getBy;
685
- locatorSchemas;
686
- /**
687
- * getLocatorSchema:
688
- * Given a path P, we:
689
- * 1. Collect deep copies of the schemas involved.
690
- * 2. Create a WithMethodsClass instance with LocatorSubstring = P.
691
- * 3. Return a locator schema copy enriched with chainable methods.
692
- */
693
- getLocatorSchema(locatorSchemaPath) {
694
- const pathIndexPairs = this.extractPathsFromSchema(locatorSchemaPath);
695
- const schemasMap = this.collectDeepCopies(locatorSchemaPath, pathIndexPairs);
696
- const locatorSchemaCopy = schemasMap.get(locatorSchemaPath);
697
- locatorSchemaCopy.schemasMap = schemasMap;
698
- locatorSchemaCopy.filterMap = /* @__PURE__ */ new Map();
699
- const wrapper = new WithMethodsClass(
700
- this.pageObjectClass,
701
- this.log,
702
- locatorSchemaPath,
703
- schemasMap
704
- );
705
- return wrapper.init(locatorSchemaPath, locatorSchemaCopy);
706
- }
707
- /**
708
- * collectDeepCopies:
709
- * Clones and stores all schemas related to the chosen path and its sub-paths.
710
- * Ensures updates and filters don't affect original schema definitions.
711
- */
712
- collectDeepCopies(locatorSchemaPath, pathIndexPairs) {
713
- const schemasMap = /* @__PURE__ */ new Map();
714
- const fullSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
715
- if (!fullSchemaFunc) {
716
- const errorMessage = `LocatorSchema not found for path: '${locatorSchemaPath}'`;
717
- this.log.error(errorMessage);
718
- throw new Error(`[${this.pageObjectClass.pocName}] ${errorMessage}`);
719
- }
720
- schemasMap.set(locatorSchemaPath, structuredClone(fullSchemaFunc()));
721
- for (const { path } of pathIndexPairs) {
722
- if (path !== locatorSchemaPath) {
723
- const schemaFunc = this.safeGetLocatorSchema(path);
724
- if (schemaFunc) {
725
- schemasMap.set(path, structuredClone(schemaFunc()));
726
- }
727
- }
728
- }
729
- return schemasMap;
730
- }
731
- isLocatorSchemaWithMethods(schema) {
732
- return REQUIRED_PROPERTIES_FOR_LOCATOR_SCHEMA_WITH_METHODS.every((p) => p in schema);
733
- }
734
- /**
735
- * applyUpdateToSubPath:
736
- * Applies updates to a specific sub-path schema within schemasMap.
737
- * Similar to applyUpdate, but we locate the sub-path schema directly by its path.
738
- */
739
- applyUpdateToSubPath(schemasMap, subPath, updates) {
740
- const schema = schemasMap.get(subPath);
741
- if (!schema) {
742
- throw new Error(`No schema found for sub-path: '${subPath}'`);
743
- }
744
- const updatedSchema = this.deepMerge(schema, updates);
745
- if (this.isLocatorSchemaWithMethods(schema)) {
746
- Object.assign(schema, updatedSchema);
747
- } else {
748
- schemasMap.set(subPath, updatedSchema);
749
- }
750
- }
751
- /**
752
- * createLocatorSchema:
753
- * Creates a fresh LocatorSchema object by merging provided schemaDetails with a required locatorSchemaPath.
754
- */
755
- createLocatorSchema(schemaDetails, locatorSchemaPath) {
756
- const schema = { ...schemaDetails, locatorSchemaPath };
757
- return schema;
758
- }
759
- /**
760
- * addSchema:
761
- * Registers a new LocatorSchema under the given locatorSchemaPath.
762
- * Throws an error if a schema already exists at that path.
763
- */
764
- addSchema(locatorSchemaPath, schemaDetails) {
765
- if (locatorSchemaPath.length === 0 || locatorSchemaPath.startsWith(".") || locatorSchemaPath.endsWith(".") || locatorSchemaPath.includes("..")) {
766
- throw new Error(
767
- `[${this.pageObjectClass.pocName}] Invalid LocatorSchemaPath '${locatorSchemaPath}'. LocatorSchemaPath must not be empty, start or end with a '.', or contain consecutive '.'.`
768
- );
769
- }
770
- const newLocatorSchema = this.createLocatorSchema(schemaDetails, locatorSchemaPath);
771
- const existingSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
772
- if (existingSchemaFunc) {
773
- const existingLocatorSchema = existingSchemaFunc();
774
- throw new Error(
775
- `[${this.pageObjectClass.pocName}] A LocatorSchema with the path '${locatorSchemaPath}' already exists.
776
- Existing Schema: ${JSON.stringify(existingLocatorSchema, null, 2)}
777
- Attempted to Add Schema: ${JSON.stringify(newLocatorSchema, null, 2)}`
778
- );
779
- }
780
- this.locatorSchemas.set(locatorSchemaPath, () => newLocatorSchema);
781
- const v2Registry = this.pageObjectClass.locatorRegistry;
782
- if (v2Registry) {
783
- addV1SchemaToV2Registry(v2Registry, newLocatorSchema);
784
- }
785
- }
786
- /**
787
- * safeGetLocatorSchema:
788
- * Safely retrieves a schema function if available for the given path.
789
- */
790
- safeGetLocatorSchema(path) {
791
- return this.locatorSchemas.get(path);
792
- }
793
- /**
794
- * extractPathsFromSchema:
795
- * Splits a path into incremental sub-paths and associates them with optional indices.
796
- * Used by getNestedLocator methods.
797
- */
798
- extractPathsFromSchema = (paths, indices = {}) => {
799
- const schemaParts = paths.split(".");
800
- let cumulativePath = "";
801
- return schemaParts.map((part, index) => {
802
- cumulativePath = cumulativePath ? `${cumulativePath}.${part}` : part;
803
- return {
804
- path: cumulativePath,
805
- index: indices[index] ?? void 0
806
- };
807
- });
808
- };
809
- /**
810
- * logError:
811
- * Logs detailed error information and re-throws the error to ensure tests fail as expected.
812
- */
813
- logError = (error, locatorSchemaPath, currentLocator, currentPath, pathIndexPairs, nestedLocatorResults) => {
814
- const errorDetails = {
815
- error: error.message,
816
- locatorSchemaPath,
817
- currentPath,
818
- pathIndexPairs: JSON.stringify(pathIndexPairs, null, 2),
819
- currentLocatorDetails: currentLocator ? {
820
- locatorString: currentLocator,
821
- isNotNull: true
822
- } : { isNotNull: false },
823
- nestedLocatorResults: safeStringifyOfNestedLocatorResults(nestedLocatorResults)
824
- };
825
- this.log.error(
826
- "An error occurred during nested locator construction.\n",
827
- "Error details:\n",
828
- JSON.stringify(errorDetails, null, 2)
829
- );
830
- throw error;
831
- };
832
- /**
833
- * deepMerge:
834
- * Recursively merges source properties into target, validating them against LocatorSchema to ensure no invalid keys.
835
- * Ensures immutability by creating a new object rather than modifying in place.
836
- */
837
- deepMerge(target, source, schema = getLocatorSchemaDummy()) {
838
- const merged = { ...target };
839
- for (const key of Object.keys(source)) {
840
- if (key === "locatorSchemaPath") {
841
- throw new Error(
842
- `[${this.pageObjectClass.pocName}] Invalid property: 'locatorSchemaPath' cannot be updated. Attempted to update LocatorSchemaPath from '${target[key]}' to '${source[key]}'.`
843
- );
844
- }
845
- if (!(key in schema)) {
846
- throw new Error(`Invalid property: '${key}' is not a valid property of LocatorSchema`);
847
- }
848
- const sourceValue = source[key];
849
- const targetValue = target[key];
850
- if (typeof sourceValue === "object" && sourceValue !== null && schema[key] && typeof schema[key] === "object") {
851
- if (targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
852
- merged[key] = this.deepMerge(
853
- targetValue,
854
- // Updated type here
855
- sourceValue,
856
- schema[key]
857
- );
858
- } else {
859
- merged[key] = this.deepMerge(
860
- {},
861
- sourceValue,
862
- schema[key]
863
- );
864
- }
865
- } else {
866
- if (Array.isArray(sourceValue)) {
867
- merged[key] = Array.isArray(targetValue) ? targetValue.concat(sourceValue) : [...sourceValue];
868
- } else if (typeof sourceValue === "object" && sourceValue !== null && Object.prototype.toString.call(sourceValue) === "[object RegExp]") {
869
- merged[key] = new RegExp(
870
- sourceValue.source,
871
- sourceValue.flags
872
- );
873
- } else {
874
- merged[key] = sourceValue;
875
- }
876
- }
877
- }
878
- return merged;
879
- }
880
- /**
881
- * buildNestedLocator:
882
- * Constructs a nested locator by iterating through each sub-path of locatorSchemaPath and chaining locators.
883
- * Applies filters, indexing (nth), and logs details for debugging during test retries.
884
- */
885
- buildNestedLocator = async (locatorSchemaPath, schemasMap, filterMap, indices = {}) => {
886
- return await test.step(`${this.pageObjectClass.pocName}: Build Nested Locator`, async () => {
887
- const pathIndexPairs = this.extractPathsFromSchema(locatorSchemaPath, indices);
888
- let currentLocator = null;
889
- let currentIFrame = null;
890
- const nestedLocatorResults = {
891
- LocatorSchema: null,
892
- NestingSteps: []
893
- };
894
- for (const { path, index } of pathIndexPairs) {
895
- const currentSchema = schemasMap.get(path);
896
- if (!currentSchema) continue;
897
- try {
898
- const nextLocator = this.getBy.getLocator(currentSchema);
899
- currentLocator = currentLocator ? currentLocator.locator(nextLocator) : nextLocator;
900
- if (currentSchema.locatorMethod !== "frameLocator" /* frameLocator */ && currentSchema.filter) {
901
- currentLocator = currentLocator.filter({
902
- has: currentSchema.filter.has,
903
- hasNot: currentSchema.filter.hasNot,
904
- hasNotText: currentSchema.filter.hasNotText,
905
- hasText: currentSchema.filter.hasText
906
- });
907
- }
908
- const filterEntries = filterMap.get(path);
909
- if (filterEntries) {
910
- for (const filterData of filterEntries) {
911
- currentLocator = currentLocator.filter({
912
- has: filterData.has,
913
- hasNot: filterData.hasNot,
914
- hasNotText: filterData.hasNotText,
915
- hasText: filterData.hasText
916
- });
917
- }
918
- }
919
- if (index != null) {
920
- currentLocator = currentLocator.nth(index);
921
- }
922
- if (this.log.isLogLevelEnabled("debug")) {
923
- if (!nestedLocatorResults.LocatorSchema) {
924
- const schemaFromMap = schemasMap.get(locatorSchemaPath);
925
- if (schemaFromMap) {
926
- nestedLocatorResults.LocatorSchema = schemaFromMap;
927
- }
928
- }
929
- if (currentSchema.locatorMethod === "frameLocator" /* frameLocator */) {
930
- if (!currentIFrame) {
931
- currentIFrame = currentSchema.frameLocator;
932
- }
933
- if (currentIFrame && currentSchema.frameLocator && currentIFrame.endsWith(currentSchema.frameLocator)) {
934
- currentIFrame += ` -> ${currentSchema.frameLocator}`;
935
- }
936
- }
937
- if (currentIFrame !== void 0) {
938
- await this.evaluateCurrentLocator(currentLocator, nestedLocatorResults.NestingSteps, currentIFrame);
939
- } else {
940
- await this.evaluateCurrentLocator(currentLocator, nestedLocatorResults.NestingSteps, null);
941
- }
942
- }
943
- } catch (error) {
944
- this.logError(error, locatorSchemaPath, currentLocator, path, pathIndexPairs, nestedLocatorResults);
945
- break;
946
- }
947
- }
948
- if (!currentLocator) {
949
- this.logError(
950
- new Error(`Failed to build nested locator for path: ${locatorSchemaPath}`),
951
- locatorSchemaPath,
952
- currentLocator,
953
- locatorSchemaPath,
954
- pathIndexPairs
955
- );
956
- }
957
- if (this.log.isLogLevelEnabled("debug")) {
958
- this.log.debug("Nested locator evaluation results:", safeStringifyOfNestedLocatorResults(nestedLocatorResults));
959
- }
960
- if (currentLocator != null) {
961
- return currentLocator;
962
- }
963
- });
964
- };
965
- /**
966
- * evaluateCurrentLocator:
967
- * Gathers debug information about the current locator's resolved elements.
968
- * Helps with logging and debugging complex locator chains.
969
- */
970
- evaluateCurrentLocator = async (currentLocator, resultsArray, currentIFrame) => {
971
- if (currentIFrame) {
972
- resultsArray.push({
973
- currentLocatorString: currentLocator,
974
- currentIFrame,
975
- Note: "iFrame locators evaluation not implemented"
976
- });
977
- } else {
978
- const elementCount = await currentLocator.count();
979
- resultsArray.push({
980
- currentLocatorString: `${currentLocator}`,
981
- resolved: elementCount > 0,
982
- elementCount
983
- });
984
- }
985
- };
986
- };
987
- var WithMethodsClass = class extends GetLocatorBase {
988
- constructor(pageObjectClass, log, locatorSubstring, schemasMap) {
989
- super(pageObjectClass, log, locatorSubstring);
990
- this.pageObjectClass = pageObjectClass;
991
- this.log = log;
992
- this.schemasMap = schemasMap;
993
- }
994
- locatorSchemaPath;
995
- /**
996
- * init:
997
- * Assigns the locatorSchemaPath and binds methods (update, addFilter, getNestedLocator, getLocator)
998
- * directly on the locatorSchemaCopy. Returns the modified copy, now fully chainable and type-safe.
999
- */
1000
- init(locatorSchemaPath, locatorSchemaCopy) {
1001
- this.locatorSchemaPath = locatorSchemaPath;
1002
- const self = this;
1003
- locatorSchemaCopy.update = function(subPath, updates) {
1004
- const fullPath = this.locatorSchemaPath;
1005
- if (!(subPath === fullPath || fullPath.startsWith(`${subPath}.`))) {
1006
- throw new Error(`Invalid sub-path: '${subPath}' is not a valid sub-path of '${fullPath}'.`);
1007
- }
1008
- self.applyUpdateToSubPath(self.schemasMap, subPath, updates);
1009
- return this;
1010
- };
1011
- locatorSchemaCopy.addFilter = function(subPath, filterData) {
1012
- const fullPath = this.locatorSchemaPath;
1013
- if (!self.schemasMap.has(subPath)) {
1014
- const allowedPaths = self.extractPathsFromSchema(fullPath).map((p) => p.path).filter((path) => self.schemasMap.has(path));
1015
- throw new Error(
1016
- `Invalid sub-path '${subPath}' in addFilter. Allowed sub-paths are:
1017
- ${allowedPaths.join(",\n")}`
1018
- );
1019
- }
1020
- if (!this.filterMap) {
1021
- this.filterMap = /* @__PURE__ */ new Map();
1022
- }
1023
- const existingFilters = this.filterMap.get(subPath) || [];
1024
- existingFilters.push(filterData);
1025
- this.filterMap.set(subPath, existingFilters);
1026
- return this;
1027
- };
1028
- locatorSchemaCopy.getNestedLocator = async function(arg) {
1029
- if (arg !== void 0 && arg !== null && typeof arg !== "object") {
1030
- throw new Error("Invalid argument passed to getNestedLocator: Expected an object or null.");
1031
- }
1032
- if (!arg || Object.keys(arg).length === 0) {
1033
- return await self.buildNestedLocator(
1034
- self.locatorSchemaPath,
1035
- self.schemasMap,
1036
- this.filterMap,
1037
- {}
1038
- );
1039
- }
1040
- const numericIndices = {};
1041
- const pathIndexPairs = self.extractPathsFromSchema(self.locatorSchemaPath);
1042
- const pathToIndexMap = new Map(pathIndexPairs.map((pair, idx) => [pair.path, idx]));
1043
- for (const [subPath, value] of Object.entries(arg)) {
1044
- if (!self.schemasMap.has(subPath)) {
1045
- const validPaths = Array.from(self.schemasMap.keys());
1046
- throw new Error(
1047
- `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
1048
- ${validPaths.join(",\n")}`
1049
- );
1050
- }
1051
- if (!pathToIndexMap.has(subPath)) {
1052
- const validPaths = pathIndexPairs.map((p) => p.path).filter((path) => self.schemasMap.has(path));
1053
- throw new Error(
1054
- `Invalid sub-path '${subPath}' in getNestedLocator. Allowed sub-paths are:
1055
- ${validPaths.join(",\n")}`
1056
- );
1057
- }
1058
- const numericIndex = pathToIndexMap.get(subPath);
1059
- if (numericIndex === void 0) {
1060
- throw new Error(`Sub-path '${subPath}' not found in pathToIndexMap.`);
1061
- }
1062
- if (value !== null && (typeof value !== "number" || value < 0)) {
1063
- throw new Error(`Invalid index for sub-path '${subPath}': Expected a positive number or null.`);
1064
- }
1065
- if (value !== null) {
1066
- numericIndices[numericIndex] = value;
1067
- }
1068
- }
1069
- return await self.buildNestedLocator(
1070
- self.locatorSchemaPath,
1071
- self.schemasMap,
1072
- this.filterMap,
1073
- numericIndices
1074
- );
1075
- };
1076
- locatorSchemaCopy.getLocator = async () => {
1077
- return self.getBy.getLocator(locatorSchemaCopy);
1078
- };
1079
- return locatorSchemaCopy;
1080
- }
1081
- };
1082
-
1083
- // src/helpers/sessionStorage.actions.ts
1084
- import { test as test2 } from "@playwright/test";
1085
- var SessionStorage = class {
1086
- // Initializes the class with a Playwright Page object and a name for the Page Object Class.
1087
- constructor(page, pocName) {
1088
- this.page = page;
1089
- this.pocName = pocName;
1090
- }
1091
- // Defines an object to hold states to be set in session storage, allowing any value type.
1092
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1093
- queuedStates = {};
1094
- // Indicates if the session storage manipulation has been initiated.
1095
- isInitiated = false;
1096
- /** Writes states to session storage. Accepts an object with key-value pairs representing the states. */
1097
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1098
- async writeToSessionStorage(states) {
1099
- await this.page.evaluate((storage) => {
1100
- for (const [key, value] of Object.entries(storage)) {
1101
- window.sessionStorage.setItem(key, JSON.stringify(value));
1102
- }
1103
- }, states);
1104
- }
1105
- /** Reads all states from session storage and returns them as an object. */
1106
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1107
- async readFromSessionStorage() {
1108
- return await this.page.evaluate(() => {
1109
- const storage = {};
1110
- for (let i = 0; i < sessionStorage.length; i++) {
1111
- const key = sessionStorage.key(i);
1112
- if (key !== null) {
1113
- const item = sessionStorage.getItem(key);
1114
- try {
1115
- storage[key] = item ? JSON.parse(item) : null;
1116
- } catch (_e) {
1117
- storage[key] = item;
1118
- }
1119
- }
1120
- }
1121
- return storage;
1122
- });
1123
- }
1124
- /**
1125
- * Sets the specified states in session storage.
1126
- * Optionally reloads the page after setting the data to ensure the new session storage state is active.
1127
- *
1128
- * Parameters:
1129
- * states: Object representing the states to set in session storage.
1130
- * reload: Boolean indicating whether to reload the page after setting the session storage data.
1131
- */
1132
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1133
- async set(states, reload) {
1134
- await test2.step(`${this.pocName}: setSessionStorage`, async () => {
1135
- await this.writeToSessionStorage(states);
1136
- if (reload) {
1137
- await this.page.reload();
1138
- }
1139
- });
1140
- }
1141
- /**
1142
- * Queues states to be set in the sessionStorage before the next navigation occurs.
1143
- * Handles different scenarios based on whether the context exists or multiple calls are made.
1144
- *
1145
- * 1. No Context, Single Call: Queues and sets states upon the next navigation.
1146
- * 2. No Context, Multiple Calls: Merges states from multiple calls and sets them upon the next navigation.
1147
- * 3. With Context: Directly sets states in sessionStorage if the context already exists.
1148
- *
1149
- * Parameters:
1150
- * states: Object representing the states to queue for setting in session storage.
1151
- */
1152
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1153
- async setOnNextNavigation(states) {
1154
- this.queuedStates = { ...this.queuedStates, ...states };
1155
- const populateStorage = async () => {
1156
- await test2.step(`${this.pocName}: setSessionStorageBeforeNavigation`, async () => {
1157
- await this.writeToSessionStorage(this.queuedStates);
1158
- });
1159
- this.queuedStates = {};
1160
- };
1161
- let contextExists = false;
1162
- try {
1163
- contextExists = await this.page.evaluate(() => {
1164
- return typeof window !== "undefined" && window.sessionStorage !== void 0;
1165
- });
1166
- } catch (_e) {
1167
- contextExists = false;
1168
- }
1169
- if (contextExists) {
1170
- await populateStorage();
1171
- return;
1172
- }
1173
284
  if (!this.isInitiated) {
1174
285
  this.isInitiated = true;
1175
- this.page.once("framenavigated", async () => {
286
+ const handler = async (frame) => {
287
+ if (frame !== this.page.mainFrame()) {
288
+ return;
289
+ }
1176
290
  await populateStorage();
1177
- });
291
+ this.page.off("framenavigated", handler);
292
+ this.isInitiated = false;
293
+ };
294
+ this.page.on("framenavigated", handler);
1178
295
  }
1179
296
  }
1180
- /**
1181
- * Fetches states from session storage.
1182
- * If specific keys are provided, fetches only those states; otherwise, fetches all states.
1183
- *
1184
- * Parameters:
1185
- * keys: Optional array of keys to specify which states to fetch from session storage.
1186
- *
1187
- * Returns:
1188
- * Object containing the fetched states.
1189
- */
1190
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
1191
- async get(keys) {
297
+ async get(keys, options = {}) {
1192
298
  let result = {};
1193
- await test2.step(`${this.pocName}: getSessionStorage`, async () => {
299
+ await test2.step(this.getStepLabel("get"), async () => {
300
+ await this.ensureContext(options);
1194
301
  const allData = await this.readFromSessionStorage();
1195
302
  if (keys && keys.length > 0) {
1196
303
  for (const key of keys) {
1197
304
  if (Object.hasOwn(allData, key)) {
1198
- result[key] = allData[key];
305
+ const value = allData[key];
306
+ if (value !== void 0) {
307
+ result[key] = value;
308
+ }
1199
309
  }
1200
310
  }
1201
311
  } else {
@@ -1204,216 +314,301 @@ var SessionStorage = class {
1204
314
  });
1205
315
  return result;
1206
316
  }
1207
- /**
1208
- * Clears all states in sessionStorage.
1209
- */
1210
- async clear() {
1211
- await test2.step(`${this.pocName}: clear SessionStorage`, async () => {
1212
- await this.page.evaluate(() => sessionStorage.clear());
317
+ async clear(keyOrOptions, options = {}) {
318
+ const { keys, waitForContext } = (() => {
319
+ if (Array.isArray(keyOrOptions)) {
320
+ return { keys: keyOrOptions, waitForContext: options.waitForContext };
321
+ }
322
+ if (typeof keyOrOptions === "string") {
323
+ return { keys: [keyOrOptions], waitForContext: options.waitForContext };
324
+ }
325
+ if (keyOrOptions) {
326
+ return { keys: void 0, waitForContext: keyOrOptions.waitForContext };
327
+ }
328
+ return { keys: void 0, waitForContext: options.waitForContext };
329
+ })();
330
+ await test2.step(this.getStepLabel("clear"), async () => {
331
+ await this.ensureContext({ waitForContext });
332
+ if (!keys || keys.length === 0) {
333
+ await this.page.evaluate(() => sessionStorage.clear());
334
+ return;
335
+ }
336
+ await this.page.evaluate((keysToClear) => {
337
+ for (const key of keysToClear) {
338
+ sessionStorage.removeItem(key);
339
+ }
340
+ }, keys);
1213
341
  });
1214
342
  }
1215
343
  };
1216
344
 
1217
- // src/utils/selectorEngines.ts
1218
- function createCypressIdEngine() {
1219
- return {
1220
- /**
1221
- * Uses the document's querySelector method to find the first element with a specific 'data-cy' attribute.
1222
- * Constructs a selector string for the 'data-cy' attribute and searches the DOM for the first match.
1223
- *
1224
- * Parameters:
1225
- * - document: An object that mimics the global document, having a querySelector method.
1226
- * - selector: A string representing the value of the 'data-cy' attribute to search for.
1227
- *
1228
- * Returns the first HTML element matching the 'data-cy' attribute, or null if no match is found.
1229
- */
1230
- query(document, selector) {
1231
- const attr = `[data-cy="${selector}"]`;
1232
- const el = document.querySelector(attr);
1233
- return el;
1234
- },
1235
- /**
1236
- * Uses the document's querySelectorAll method to find all elements with a specific 'data-cy' attribute.
1237
- * Constructs a selector string for the 'data-cy' attribute and retrieves all matching elements in the DOM.
1238
- * Converts the NodeList from querySelectorAll into an array for easier handling and manipulation.
1239
- *
1240
- * Parameters:
1241
- * - document: An object that mimics the global document, having a querySelectorAll method.
1242
- * - selector: A string representing the value of the 'data-cy' attribute to search for.
1243
- *
1244
- * Returns an array of HTML elements matching the 'data-cy' attribute. Returns an empty array if no matches are found.
1245
- */
1246
- queryAll(document, selector) {
1247
- const attr = `[data-cy="${selector}"]`;
1248
- const els = Array.from(document.querySelectorAll(attr));
1249
- return els;
1250
- }
1251
- };
1252
- }
1253
-
1254
- // src/basePage.ts
1255
- var selectorRegistered = false;
1256
- var BasePage = class {
1257
- /** Provides Playwright page methods */
1258
- page;
1259
- /** Playwright TestInfo contains information about currently running test, available to any test function */
1260
- testInfo;
1261
- /** Selectors can be used to install custom selector engines.*/
1262
- selector;
1263
- /** The base URL of the Page Object Class */
1264
- baseUrl;
1265
- /** The URL path of the Page Object Class */
1266
- urlPath;
1267
- /** The full URL of the Page Object Class */
1268
- fullUrl;
1269
- /** The name of the Page Object Class */
1270
- pocName;
1271
- /** The Page Object Class' PlaywrightReportLogger instance, prefixed with its name. Log levels: debug, info, warn, and error. */
1272
- log;
1273
- /** The SessionStorage class provides methods for setting and getting session storage data in Playwright.*/
1274
- sessionStorage;
1275
- /**
1276
- * locators:
1277
- * An instance of GetLocatorBase that handles schema management and provides getLocatorSchema calls.
1278
- * Initially, LocatorSubstring is undefined. Once getLocatorSchema(path) is called,
1279
- * we get a chainable object typed with LocatorSubstring = P.
1280
- */
1281
- locators;
1282
- constructor(page, testInfo, baseUrl, urlPath, pocName, pwrl, locatorSubstring) {
1283
- this.page = page;
1284
- this.testInfo = testInfo;
1285
- this.selector = selectors;
1286
- this.baseUrl = baseUrl;
1287
- this.urlPath = urlPath;
1288
- this.fullUrl = this.constructFullUrl(baseUrl, urlPath);
1289
- this.pocName = pocName;
1290
- this.log = pwrl.getNewChildLogger(pocName);
1291
- 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.";
1292
- warnDeprecationOncePerTest(`${this.constructor.name}-class-deprecation`, classDeprecationMessage, this.log);
1293
- this.locators = new GetLocatorBase(
1294
- this,
1295
- this.log.getNewChildLogger("GetLocator"),
1296
- locatorSubstring
1297
- );
1298
- this.initLocatorSchemas();
1299
- this.sessionStorage = new SessionStorage(this.page, this.pocName);
1300
- if (!selectorRegistered) {
1301
- selectors.register("data-cy", createCypressIdEngine);
1302
- selectorRegistered = true;
345
+ // src/helpers/stepDecorator.ts
346
+ import { test as test3 } from "@playwright/test";
347
+ var isMethodDecoratorArgs = (args) => args.length === 3 && typeof args[0] === "object" && (typeof args[1] === "string" || typeof args[1] === "symbol");
348
+ var isStage3MethodDecoratorArgs = (args) => args.length === 2 && typeof args[0] === "function" && args[1] !== null && typeof args[1] === "object";
349
+ var normalizeStepArguments = (args) => {
350
+ const [titleOrOptions, maybeOptions] = args;
351
+ const title = typeof titleOrOptions === "string" ? titleOrOptions : void 0;
352
+ const options = typeof titleOrOptions === "string" ? maybeOptions : titleOrOptions;
353
+ return { title, options };
354
+ };
355
+ var createWrappedMethod = (original, methodName, title, options) => function(...methodArgs) {
356
+ const rawClassName = this.constructor?.name ?? "";
357
+ const className = rawClassName && rawClassName !== "Object" ? rawClassName : "Anonymous";
358
+ const resolvedTitle = title ?? `${className}.${String(methodName)}`;
359
+ return test3.step(resolvedTitle, () => original.apply(this, methodArgs), options);
360
+ };
361
+ var createStepDecorator = ({ title, options }) => (valueOrTarget, contextOrKey, descriptor) => {
362
+ if (typeof valueOrTarget === "function" && isStage3MethodDecoratorArgs([valueOrTarget, contextOrKey])) {
363
+ const [original2, context] = [valueOrTarget, contextOrKey];
364
+ return createWrappedMethod(original2, context.name, title, options);
365
+ }
366
+ if (!descriptor || typeof descriptor.value !== "function") {
367
+ throw new Error("@step decorator can only be applied to methods.");
368
+ }
369
+ const original = descriptor.value;
370
+ descriptor.value = createWrappedMethod(original, contextOrKey, title, options);
371
+ return descriptor;
372
+ };
373
+ function step(...args) {
374
+ if (isStage3MethodDecoratorArgs(args)) {
375
+ return createStepDecorator(normalizeStepArguments([]))(...args);
376
+ }
377
+ if (isMethodDecoratorArgs(args)) {
378
+ return createStepDecorator(normalizeStepArguments([]))(...args);
379
+ }
380
+ return createStepDecorator(normalizeStepArguments(args));
381
+ }
382
+
383
+ // src/locators/utils.ts
384
+ var formatLocatorSchemaPathForError = (path) => {
385
+ const json = JSON.stringify(path);
386
+ return json.slice(1, -1);
387
+ };
388
+ var RUNTIME_WHITESPACE_REGEX = /[\s\u0085]/u;
389
+ var validateLocatorSchemaPath = (path) => {
390
+ if (!path) {
391
+ throw new Error("LocatorSchemaPath string cannot be empty");
392
+ }
393
+ if (RUNTIME_WHITESPACE_REGEX.test(path)) {
394
+ const escaped = formatLocatorSchemaPathForError(path);
395
+ throw new Error(`LocatorSchemaPath string cannot contain whitespace chars: ${escaped}`);
396
+ }
397
+ if (path.startsWith(".")) {
398
+ throw new Error(`LocatorSchemaPath string cannot start with a dot: ${path}`);
399
+ }
400
+ if (path.endsWith(".")) {
401
+ throw new Error(`LocatorSchemaPath string cannot end with a dot: ${path}`);
402
+ }
403
+ if (path.includes("..")) {
404
+ throw new Error(`LocatorSchemaPath string cannot contain consecutive dots: ${path}`);
405
+ }
406
+ };
407
+ var expandSchemaPath = (path) => {
408
+ validateLocatorSchemaPath(path);
409
+ const parts = path.split(".");
410
+ return parts.map((_part, index) => parts.slice(0, index + 1).join("."));
411
+ };
412
+ var cssEscape = (value) => {
413
+ return value.replace(/([\\"'#.:;,?*+<>{}[\\]()])/g, "\\$1");
414
+ };
415
+ var normalizeSteps = (steps) => steps ? steps.map((step2) => ({ ...step2 })) : [];
416
+ function normalizeIdValue(id) {
417
+ if (typeof id !== "string") {
418
+ return id;
419
+ }
420
+ if (id.startsWith("#")) {
421
+ return id.slice(1);
422
+ }
423
+ if (id.startsWith("id=")) {
424
+ return id.slice("id=".length);
425
+ }
426
+ return id;
427
+ }
428
+ var stringifyForLog = (value) => {
429
+ const seen = /* @__PURE__ */ new WeakSet();
430
+ return JSON.stringify(
431
+ value,
432
+ (_key, current) => {
433
+ if (typeof current === "object" && current !== null) {
434
+ if (seen.has(current)) {
435
+ return "[Circular]";
436
+ }
437
+ seen.add(current);
438
+ }
439
+ if (current instanceof RegExp) {
440
+ return { type: "RegExp", source: current.source, flags: current.flags };
441
+ }
442
+ return current;
443
+ },
444
+ 2
445
+ );
446
+ };
447
+ var applyIndexSelector = (locator, selector) => {
448
+ if (selector === void 0 || selector === null) {
449
+ return locator;
450
+ }
451
+ if (selector === "first") {
452
+ return locator.first();
453
+ }
454
+ if (selector === "last") {
455
+ return locator.last();
456
+ }
457
+ return locator.nth(selector);
458
+ };
459
+ var createLocator = (target, definition) => {
460
+ switch (definition.type) {
461
+ case "role":
462
+ return target.getByRole(definition.role, definition.options);
463
+ case "text":
464
+ return target.getByText(definition.text, definition.options);
465
+ case "label":
466
+ return target.getByLabel(definition.text, definition.options);
467
+ case "placeholder":
468
+ return target.getByPlaceholder(definition.text, definition.options);
469
+ case "altText":
470
+ return target.getByAltText(definition.text, definition.options);
471
+ case "title":
472
+ return target.getByTitle(definition.text, definition.options);
473
+ case "locator":
474
+ return target.locator(definition.selector, definition.options);
475
+ case "frameLocator":
476
+ return target.frameLocator(definition.selector);
477
+ case "testId":
478
+ return target.getByTestId(definition.testId);
479
+ case "id": {
480
+ if (typeof definition.id === "string") {
481
+ const normalized = normalizeIdValue(definition.id);
482
+ return target.locator(`#${cssEscape(normalized ?? "")}`);
483
+ }
484
+ const pattern = definition.id.source;
485
+ const safePattern = cssEscape(pattern);
486
+ return target.locator(`[id*="${safePattern}"]`);
487
+ }
488
+ default: {
489
+ const exhaustive = definition;
490
+ return exhaustive;
1303
491
  }
1304
492
  }
1305
- /**
1306
- * constructFullUrl:
1307
- * Combines baseUrl and urlPath, handling both strings and RegExps.
1308
- * Ensures a flexible approach to URL matching (string or regex-based).
1309
- */
1310
- constructFullUrl(baseUrl, urlPath) {
1311
- const escapeStringForRegExp = (str) => str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
1312
- if (typeof baseUrl === "string" && typeof urlPath === "string") {
1313
- return `${baseUrl}${urlPath}`;
493
+ };
494
+ var cloneLocatorStrategyDefinition = (definition) => {
495
+ switch (definition.type) {
496
+ case "role":
497
+ return {
498
+ type: "role",
499
+ role: definition.role,
500
+ ...definition.options ? { options: { ...definition.options } } : {}
501
+ };
502
+ case "text":
503
+ return {
504
+ type: "text",
505
+ text: definition.text,
506
+ ...definition.options ? { options: { ...definition.options } } : {}
507
+ };
508
+ case "label":
509
+ return {
510
+ type: "label",
511
+ text: definition.text,
512
+ ...definition.options ? { options: { ...definition.options } } : {}
513
+ };
514
+ case "placeholder":
515
+ return {
516
+ type: "placeholder",
517
+ text: definition.text,
518
+ ...definition.options ? { options: { ...definition.options } } : {}
519
+ };
520
+ case "altText":
521
+ return {
522
+ type: "altText",
523
+ text: definition.text,
524
+ ...definition.options ? { options: { ...definition.options } } : {}
525
+ };
526
+ case "title":
527
+ return {
528
+ type: "title",
529
+ text: definition.text,
530
+ ...definition.options ? { options: { ...definition.options } } : {}
531
+ };
532
+ case "locator":
533
+ return {
534
+ type: "locator",
535
+ selector: definition.selector,
536
+ ...definition.options ? { options: { ...definition.options } } : {}
537
+ };
538
+ case "frameLocator":
539
+ return { type: "frameLocator", selector: definition.selector };
540
+ case "testId":
541
+ return { type: "testId", testId: definition.testId };
542
+ case "id":
543
+ return { type: "id", id: definition.id };
544
+ default: {
545
+ const exhaustive = definition;
546
+ return exhaustive;
1314
547
  }
1315
- if (typeof baseUrl === "string" && urlPath instanceof RegExp) {
1316
- return new RegExp(`^${escapeStringForRegExp(baseUrl)}${urlPath.source}`);
548
+ }
549
+ };
550
+ var applyDefinitionPatch = (seed, patch) => {
551
+ const base2 = cloneLocatorStrategyDefinition(seed);
552
+ switch (patch.type) {
553
+ case "locator": {
554
+ const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
555
+ const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
556
+ return { type: "locator", selector, ...options ? { options } : {} };
1317
557
  }
1318
- if (baseUrl instanceof RegExp && typeof urlPath === "string") {
1319
- return new RegExp(`${baseUrl.source}${escapeStringForRegExp(urlPath)}$`);
558
+ case "role": {
559
+ const role = patch.role ?? base2.role;
560
+ const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
561
+ return { type: "role", role, ...options ? { options } : {} };
1320
562
  }
1321
- if (baseUrl instanceof RegExp && urlPath instanceof RegExp) {
1322
- return new RegExp(`${baseUrl.source}${urlPath.source}`);
563
+ case "text": {
564
+ const text = patch.text ?? base2.text;
565
+ const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
566
+ return { type: "text", text, ...options ? { options } : {} };
567
+ }
568
+ case "label": {
569
+ const text = patch.text ?? base2.text;
570
+ const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
571
+ return { type: "label", text, ...options ? { options } : {} };
572
+ }
573
+ case "placeholder": {
574
+ const text = patch.text ?? base2.text;
575
+ const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
576
+ return { type: "placeholder", text, ...options ? { options } : {} };
577
+ }
578
+ case "altText": {
579
+ const text = patch.text ?? base2.text;
580
+ const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
581
+ return { type: "altText", text, ...options ? { options } : {} };
582
+ }
583
+ case "title": {
584
+ const text = patch.text ?? base2.text;
585
+ const options = patch.options || base2.options ? { ...base2.options, ...patch.options } : void 0;
586
+ return { type: "title", text, ...options ? { options } : {} };
587
+ }
588
+ case "frameLocator": {
589
+ const selector = patch.selector !== void 0 ? patch.selector : base2.selector;
590
+ return { type: "frameLocator", selector };
591
+ }
592
+ case "testId": {
593
+ const testId = patch.testId !== void 0 ? patch.testId : base2.testId;
594
+ return { type: "testId", testId };
595
+ }
596
+ case "id": {
597
+ const id = patch.id !== void 0 ? normalizeIdValue(patch.id) ?? base2.id : base2.id;
598
+ return { type: "id", id };
599
+ }
600
+ default: {
601
+ const exhaustive = patch;
602
+ return exhaustive;
1323
603
  }
1324
- throw new Error("Invalid baseUrl or urlPath types. Expected string or RegExp.");
1325
- }
1326
- /**
1327
- * Implementation of getNestedLocator.
1328
- */
1329
- async getNestedLocator(locatorSchemaPath, subPathIndices) {
1330
- const withValidation = new WithSubPathValidation(
1331
- this,
1332
- this.log.getNewChildLogger("SubPathValidation"),
1333
- locatorSchemaPath
1334
- );
1335
- return await withValidation.getNestedLocator(subPathIndices);
1336
- }
1337
- /**
1338
- * Short-hand wrapper method for calling .getLocatorSchema(LocatorSchemaPath).getLocator()
1339
- *
1340
- * This method does not perform nesting,and will return the locator for which the full LocatorSchemaPath resolves to,
1341
- * provided by getLocatorSchema("...")
1342
- *
1343
- * Note: This short-hand wrapper method is useful for quickly getting a locator without having to call
1344
- * getLocatorSchema("...") first. On the other hand, it can't be used to update or add filters to the LocatorSchema.
1345
- *
1346
- * @example
1347
- * // Usage:
1348
- * const submitButton = await poc.getLocator("main.form.button@submit");
1349
- * await expect(submitButton, "should only exist one submit button").toHaveCount(1);
1350
- */
1351
- getLocator = async (locatorSchemaPath) => {
1352
- return await this.getLocatorSchema(locatorSchemaPath).getLocator();
1353
- };
1354
- /**
1355
- * getLocatorSchema:
1356
- * Delegates to this.locators.getLocatorSchema.
1357
- * Returns a chainable schema object for the given path.
1358
- * Once called with a specific path P, the update and addFilter methods are restricted to sub-paths of P.
1359
- *
1360
- * The "getLocatorSchema" method is used to retrieve an updatable deep copy of a LocatorSchema defined in the
1361
- * GetLocatorBase class. It enriches the returned schema with additional methods to handle updates and retrieval of
1362
- * deep copy locators.
1363
- *
1364
- * getLocatorSchema adds the following chainable methods to the returned LocatorSchemaWithMethods object:
1365
- *
1366
- * update
1367
- * - Allows updating any schema in the chain by specifying the subPath directly.
1368
- * - Gives compile-time suggestions for valid sub-paths of the LocatorSchemaPath provided to .getLocatorSchema().
1369
- * - If you want to update multiple schemas, chain multiple .update() calls.
1370
- *
1371
- * addFilter(subPath: SubPaths<LocatorSchemaPathType, LocatorSubstring>, filterData: FilterEntry)
1372
- * - The equivalent of the Playwright locator.filter() method
1373
- * - This method is used for filtering the specified locator based on the provided filterData.
1374
- * - Can be chained multiple times to add multiple filters to the same or different LocatorSchema.
1375
- *
1376
- * getNestedLocator
1377
- * - Asynchronously builds a nested locator based on the LocatorSchemaPath provided by getLocatorSchema("...")
1378
- * - Can be chained once after the update and addFilter methods or directly on the .getLocatorSchema method.
1379
- * - getNestedLocator will end the method chain and return a nested Playwright Locator.
1380
- * - Optionally parameter takes a list of key(subPath)-value(index) pairs, the locator constructed from the LocatorSchema
1381
- * with the specified subPath will resolve to the .nth(n) occurrence of the element, within the chain.
1382
- *
1383
- * getLocator()
1384
- * - Asynchronously retrieves a locator based on the current LocatorSchemaPath.
1385
- * - This method does not perform nesting and will return the locator for which the full LocatorSchemaPath resolves to, provided by getLocatorSchema("...")
1386
- * - Can be chained once after the update and addFilter methods or directly on the .getLocatorSchema method.
1387
- * - getLocator will end the method chain and return a Playwright Locator.
1388
- *
1389
- * Note: Calling getLocator() and getNestedLocator() on the same LocatorSchemaPath will return a Locator for the same
1390
- * element, but the Locator returned by getNestedLocator() will be a locator resolving to said same element through
1391
- * a chain of locators. While the Locator returned by getLocator() will be a single locator which resolves directly
1392
- * to said element. Thus getLocator() is rarely used, while getNestedLocator() is used extensively.
1393
- *
1394
- * That said, for certain use cases, getLocator() can be useful, and you could use it to manually chain locators
1395
- * yourself if some edge case required it. Though, it would be likely be more prudent to expand your LocatorSchemaPath
1396
- * type and initLocatorSchemas() method to include the additional locators you need for the given POC, and then use
1397
- * getNestedLocator() instead, or by implementing a helper method on your Page Object Class.
1398
- */
1399
- getLocatorSchema(path) {
1400
- return this.locators.getLocatorSchema(path);
1401
604
  }
1402
605
  };
1403
- var WithSubPathValidation = class extends GetLocatorBase {
1404
- constructor(pageObjectClass, log, locatorSchemaPath) {
1405
- super(pageObjectClass, log, locatorSchemaPath);
1406
- this.locatorSchemaPath = locatorSchemaPath;
1407
- }
1408
- async getNestedLocator(arg) {
1409
- return await this.pageObjectClass.getLocatorSchema(this.locatorSchemaPath).getNestedLocator(arg);
1410
- }
606
+ var isFrameLocatorDefinition = (definition) => definition.type === "frameLocator";
607
+ var isLocatorInstance = (value) => {
608
+ return !!value && typeof value === "object" && typeof value.filter === "function";
1411
609
  };
1412
610
 
1413
- // src/basePageV1toV2.ts
1414
- import { selectors as selectors2 } from "@playwright/test";
1415
-
1416
- // srcV2/locators/locatorUpdateBuilder.ts
611
+ // src/locators/locatorUpdateBuilder.ts
1417
612
  var parseUpdateArguments = (primaryOrOptions, options, optionsProvided) => {
1418
613
  let primary;
1419
614
  let parsedOptions;
@@ -1903,7 +1098,7 @@ var LocatorUpdateBuilder = class {
1903
1098
  }
1904
1099
  };
1905
1100
 
1906
- // srcV2/locators/locatorQueryBuilder.ts
1101
+ // src/locators/locatorQueryBuilder.ts
1907
1102
  var LocatorQueryBuilder = class {
1908
1103
  constructor(registry, path) {
1909
1104
  this.registry = registry;
@@ -2126,7 +1321,7 @@ var LocatorQueryBuilder = class {
2126
1321
  }
2127
1322
  };
2128
1323
 
2129
- // srcV2/locators/locatorRegistrationBuilder.ts
1324
+ // src/locators/locatorRegistrationBuilder.ts
2130
1325
  var LocatorRegistrationBuilder = class {
2131
1326
  constructor(registry, path, seed) {
2132
1327
  this.registry = registry;
@@ -2350,7 +1545,7 @@ var LocatorRegistrationBuilder = class {
2350
1545
  }
2351
1546
  };
2352
1547
 
2353
- // srcV2/locators/reusableLocatorBuilder.ts
1548
+ // src/locators/reusableLocatorBuilder.ts
2354
1549
  var ReusableLocatorBuilder = class {
2355
1550
  stepsList;
2356
1551
  definitionValue;
@@ -2426,7 +1621,7 @@ var ReusableLocatorFactory = class {
2426
1621
  }
2427
1622
  };
2428
1623
 
2429
- // srcV2/locators/locatorRegistry.ts
1624
+ // src/locators/locatorRegistry.ts
2430
1625
  var LocatorRegistryInternal = class {
2431
1626
  constructor(page) {
2432
1627
  this.page = page;
@@ -2462,20 +1657,45 @@ var LocatorRegistryInternal = class {
2462
1657
  ...record.description !== void 0 ? { description: record.description } : {}
2463
1658
  };
2464
1659
  }
2465
- add(path, options) {
1660
+ /**
1661
+ * Registers a locator schema at the provided dot-delimited path.
1662
+ * Accepts exactly one locator strategy (`getByRole`, `locator`, etc.) and any number of
1663
+ * `filter`/`nth` steps chained in call order. When `{ reuse }` is supplied, the seeded
1664
+ * definition is applied first and one matching override is allowed as a PATCH of the seed;
1665
+ * otherwise, calling multiple locator strategies will throw.
1666
+ *
1667
+ * @example
1668
+ * ```ts
1669
+ * registry
1670
+ * .add("list.item")
1671
+ * .getByRole("listitem", { name: /Row/ })
1672
+ * .filter({ hasText: "Row" })
1673
+ * .nth("last");
1674
+ * ```
1675
+ */
1676
+ add(path, ...args) {
1677
+ const options = args[0];
2466
1678
  const reuse = options?.reuse;
2467
- if (!reuse) {
1679
+ if (reuse === void 0) {
2468
1680
  return new LocatorRegistrationBuilder(
2469
1681
  this,
2470
1682
  path
2471
1683
  );
2472
1684
  }
2473
1685
  if (typeof reuse === "string") {
1686
+ const targetPath = path;
1687
+ if (reuse === targetPath) {
1688
+ throw new Error(`Locator reuse path cannot be the same as registration path: "${targetPath}".`);
1689
+ }
2474
1690
  const sourceRecord = this.get(reuse);
2475
- const cloned = this.cloneRecordForReuse(sourceRecord, path);
2476
- this.register(path, cloned);
1691
+ const cloned = this.cloneRecordForReuse(sourceRecord, targetPath);
1692
+ this.register(targetPath, cloned);
2477
1693
  return void 0;
2478
1694
  }
1695
+ if (Array.isArray(reuse)) {
1696
+ const [reason] = reuse;
1697
+ throw new Error(`Invalid reuse path configuration for "${path}": ${reason}`);
1698
+ }
2479
1699
  const reusedRecord = this.cloneRecordForReuse(
2480
1700
  {
2481
1701
  locatorSchemaPath: path,
@@ -2526,7 +1746,7 @@ Existing Schema: ${errorDetails}`);
2526
1746
  }
2527
1747
  return {
2528
1748
  locatorSchemaPath: record.locatorSchemaPath,
2529
- definition: record.definition,
1749
+ definition: cloneLocatorStrategyDefinition(record.definition),
2530
1750
  steps: normalizeSteps(record.steps),
2531
1751
  ...record.description !== void 0 ? { description: record.description } : {}
2532
1752
  };
@@ -2541,7 +1761,7 @@ Existing Schema: ${errorDetails}`);
2541
1761
  }
2542
1762
  return {
2543
1763
  locatorSchemaPath: record.locatorSchemaPath,
2544
- definition: record.definition,
1764
+ definition: cloneLocatorStrategyDefinition(record.definition),
2545
1765
  steps: normalizeSteps(record.steps),
2546
1766
  ...record.description !== void 0 ? { description: record.description } : {}
2547
1767
  };
@@ -2620,7 +1840,10 @@ Existing Schema: ${errorDetails}`);
2620
1840
  * ```
2621
1841
  */
2622
1842
  getLocatorSchema(path) {
2623
- return new LocatorQueryBuilder(this, path);
1843
+ return new LocatorQueryBuilder(
1844
+ this,
1845
+ path
1846
+ );
2624
1847
  }
2625
1848
  /**
2626
1849
  * Resolves the Playwright {@link Locator} for the provided path, applying only the terminal
@@ -2723,7 +1946,6 @@ Existing Schema: ${errorDetails}`);
2723
1946
  }
2724
1947
  };
2725
1948
  var createRegistryWithAccessors = (page) => {
2726
- const _assertValidPaths = true;
2727
1949
  const registryInstance = new LocatorRegistryInternal(page);
2728
1950
  const add = registryInstance.add.bind(registryInstance);
2729
1951
  const getLocator = registryInstance.getLocator.bind(registryInstance);
@@ -2733,98 +1955,8 @@ var createRegistryWithAccessors = (page) => {
2733
1955
  return { registry, add, getLocator, getNestedLocator, getLocatorSchema };
2734
1956
  };
2735
1957
 
2736
- // src/basePageV1toV2.ts
2737
- var BasePageV1toV2 = class {
2738
- /** Provides Playwright page methods */
2739
- page;
2740
- /** Playwright TestInfo contains information about currently running test, available to any test function */
2741
- testInfo;
2742
- /** Selectors can be used to install custom selector engines.*/
2743
- selector;
2744
- /** The base URL of the Page Object Class */
2745
- baseUrl;
2746
- /** The URL path of the Page Object Class */
2747
- urlPath;
2748
- /** The full URL of the Page Object Class */
2749
- fullUrl;
2750
- /** The name of the Page Object Class */
2751
- pocName;
2752
- /** The Page Object Class' PlaywrightReportLogger instance, prefixed with its name. Log levels: debug, info, warn, and error. */
2753
- log;
2754
- /** The SessionStorage class provides methods for setting and getting session storage data in Playwright.*/
2755
- sessionStorage;
2756
- /**
2757
- * locators:
2758
- * An instance of GetLocatorBase that handles schema management and provides getLocatorSchema calls.
2759
- * Initially, LocatorSubstring is undefined. Once getLocatorSchema(path) is called,
2760
- * we get a chainable object typed with LocatorSubstring = P.
2761
- */
2762
- locators;
2763
- /**
2764
- * v2 locator registry and accessors, used for migration to the fluent registry DSL.
2765
- */
2766
- locatorRegistry;
2767
- add;
2768
- getLocator;
2769
- getLocatorSchema;
2770
- getNestedLocator;
2771
- constructor(page, testInfo, baseUrl, urlPath, pocName, pwrl, locatorSubstring) {
2772
- this.page = page;
2773
- this.testInfo = testInfo;
2774
- this.selector = selectors2;
2775
- this.baseUrl = baseUrl;
2776
- this.urlPath = urlPath;
2777
- this.fullUrl = this.constructFullUrl(baseUrl, urlPath);
2778
- this.pocName = pocName;
2779
- this.log = pwrl.getNewChildLogger(pocName);
2780
- 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.";
2781
- warnDeprecationOncePerTest(`${this.constructor.name}-class-deprecation`, classDeprecationMessage, this.log);
2782
- const { registry, add, getLocator, getNestedLocator, getLocatorSchema } = createRegistryWithAccessors(page);
2783
- this.locatorRegistry = registry;
2784
- this.add = add;
2785
- this.getLocator = getLocator;
2786
- this.getLocatorSchema = getLocatorSchema;
2787
- this.getNestedLocator = getNestedLocator;
2788
- this.defineLocators();
2789
- this.locators = new GetLocatorBase(
2790
- this,
2791
- this.log.getNewChildLogger("GetLocator"),
2792
- locatorSubstring
2793
- );
2794
- const initLocatorSchemasDeprecationMessage = "[POMWright] initLocatorSchemas is deprecated and will be removed in 2.0.0. Define locators with the v2 registry DSL in defineLocators instead.";
2795
- warnDeprecationOncePerTest(
2796
- `${this.constructor.name}-initLocatorSchemas-deprecation`,
2797
- initLocatorSchemasDeprecationMessage,
2798
- this.log
2799
- );
2800
- this.initLocatorSchemas();
2801
- this.sessionStorage = new SessionStorage(this.page, this.pocName);
2802
- }
2803
- /**
2804
- * constructFullUrl:
2805
- * Combines baseUrl and urlPath, handling both strings and RegExps.
2806
- * Ensures a flexible approach to URL matching (string or regex-based).
2807
- */
2808
- constructFullUrl(baseUrl, urlPath) {
2809
- const escapeStringForRegExp = (str) => str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
2810
- if (typeof baseUrl === "string" && typeof urlPath === "string") {
2811
- return `${baseUrl}${urlPath}`;
2812
- }
2813
- if (typeof baseUrl === "string" && urlPath instanceof RegExp) {
2814
- return new RegExp(`^${escapeStringForRegExp(baseUrl)}${urlPath.source}`);
2815
- }
2816
- if (baseUrl instanceof RegExp && typeof urlPath === "string") {
2817
- return new RegExp(`${baseUrl.source}${escapeStringForRegExp(urlPath)}$`);
2818
- }
2819
- if (baseUrl instanceof RegExp && urlPath instanceof RegExp) {
2820
- return new RegExp(`${baseUrl.source}${urlPath.source}`);
2821
- }
2822
- throw new Error("Invalid baseUrl or urlPath types. Expected string or RegExp.");
2823
- }
2824
- };
2825
-
2826
- // srcV2/helpers/navigation.ts
2827
- import { expect, test as test3 } from "@playwright/test";
1958
+ // src/helpers/navigation.ts
1959
+ import { expect, test as test4 } from "@playwright/test";
2828
1960
  var DEFAULT_WAIT_UNTIL = "load";
2829
1961
  var DEFAULT_LOAD_STATE = "load";
2830
1962
  var Navigation = class {
@@ -2859,7 +1991,7 @@ var Navigation = class {
2859
1991
  if (typeof this.baseUrl !== "string" || typeof this.urlPath !== "string") {
2860
1992
  throw new Error("goto() is not supported when baseUrl or urlPath is a RegExp.");
2861
1993
  }
2862
- await test3.step(`${this.label}: Navigate to the provided URL or URL Path`, async () => {
1994
+ await test4.step(`${this.label}: Navigate to the provided URL or URL Path`, async () => {
2863
1995
  const targetUrl = urlPathOrUrl.startsWith("/") ? `${this.baseUrl}${urlPathOrUrl}` : urlPathOrUrl;
2864
1996
  await this.page.goto(targetUrl, { waitUntil });
2865
1997
  });
@@ -2869,247 +2001,60 @@ var Navigation = class {
2869
2001
  * Available only when fullUrl is a string.
2870
2002
  */
2871
2003
  async gotoThisPage(options) {
2872
- if (typeof this.fullUrl !== "string") {
2873
- throw new Error("gotoThisPage() is not supported when fullUrl is a RegExp.");
2874
- }
2875
- const waitUntil = this.resolveWaitUntil(options);
2876
- const fullUrl = this.fullUrl;
2877
- await test3.step(`${this.label}: Navigate to this Page`, async () => {
2878
- await this.page.goto(fullUrl, { waitUntil });
2879
- await this.executeActions();
2880
- });
2881
- }
2882
- /**
2883
- * Expect to be on this page. Works with both string and RegExp fullUrl values.
2884
- * Uses waitUntil from navigation options when waiting for URL.
2885
- */
2886
- async expectThisPage(options) {
2887
- const waitUntil = this.resolveWaitUntil(options);
2888
- await test3.step(`${this.label}: Expect this Page`, async () => {
2889
- await this.page.waitForURL(this.fullUrl, { waitUntil });
2890
- await expect(async () => {
2891
- if (this.fullUrl instanceof RegExp) {
2892
- expect(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toMatch(this.fullUrl);
2893
- } else {
2894
- expect(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toBe(this.fullUrl);
2895
- }
2896
- }).toPass();
2897
- await this.executeActions();
2898
- });
2899
- }
2900
- /**
2901
- * Expect to be on any other page (i.e. not this page).
2902
- * Uses waitForLoadState from navigation options before validating URL.
2903
- */
2904
- async expectAnotherPage(options) {
2905
- const waitForLoadState = this.resolveWaitForLoadState(options);
2906
- await test3.step(`${this.label}: Expect any other Page`, async () => {
2907
- await this.page.waitForLoadState(waitForLoadState);
2908
- if (this.fullUrl instanceof RegExp) {
2909
- await expect.poll(async () => this.page.url(), {
2910
- message: `expected url to not match '${this.fullUrl}'`
2911
- }).not.toMatch(this.fullUrl);
2912
- } else {
2913
- await expect.poll(async () => this.page.url(), {
2914
- message: `expected url to not be '${this.fullUrl}', found '${this.page.url()}'`
2915
- }).not.toBe(this.fullUrl);
2916
- }
2917
- });
2918
- }
2919
- };
2920
- function createNavigation(page, baseUrl, urlPath, fullUrl, label, actions = null, defaultOptions) {
2921
- const navigation = new Navigation(page, baseUrl, urlPath, fullUrl, label, actions, defaultOptions);
2922
- return navigation;
2923
- }
2924
-
2925
- // srcV2/helpers/sessionStorage.ts
2926
- import { test as test4 } from "@playwright/test";
2927
- var SessionStorage2 = class {
2928
- // Initializes the class with a Playwright Page object and an optional label for step titles.
2929
- constructor(page, options = {}) {
2930
- this.page = page;
2931
- this.options = options;
2932
- }
2933
- // Defines an object to hold states to be set in session storage, allowing any value type.
2934
- queuedStates = {};
2935
- // Indicates if the session storage manipulation has been initiated.
2936
- isInitiated = false;
2937
- getStepLabel(methodName) {
2938
- const prefix = this.options.label ? `${this.options.label}.` : "";
2939
- return `${prefix}SessionStorage.${methodName}:`;
2940
- }
2941
- async hasContext() {
2942
- return await this.page.evaluate(() => {
2943
- return typeof window !== "undefined" && window.sessionStorage !== void 0;
2944
- });
2945
- }
2946
- async waitForContextAvailability() {
2947
- try {
2948
- const contextExists = await this.hasContext();
2949
- if (contextExists) {
2950
- return;
2951
- }
2952
- } catch (_e) {
2953
- }
2954
- await new Promise((resolve) => {
2955
- const handler = async (frame) => {
2956
- if (frame !== this.page.mainFrame()) {
2957
- return;
2958
- }
2959
- try {
2960
- const contextExists = await this.hasContext();
2961
- if (!contextExists) {
2962
- return;
2963
- }
2964
- } catch (_e) {
2965
- return;
2966
- }
2967
- this.page.off("framenavigated", handler);
2968
- resolve();
2969
- };
2970
- this.page.on("framenavigated", handler);
2971
- });
2972
- }
2973
- async ensureContext({ waitForContext = false } = {}) {
2974
- try {
2975
- const contextExists = await this.hasContext();
2976
- if (contextExists) {
2977
- return;
2978
- }
2979
- } catch (_e) {
2980
- }
2981
- if (!waitForContext) {
2982
- throw new Error("SessionStorage context is not available.");
2983
- }
2984
- await this.waitForContextAvailability();
2985
- }
2986
- /** Writes states to session storage. Accepts an object with key-value pairs representing the states. */
2987
- async writeToSessionStorage(states) {
2988
- await this.page.evaluate((storage) => {
2989
- for (const [key, value] of Object.entries(storage)) {
2990
- window.sessionStorage.setItem(key, JSON.stringify(value));
2991
- }
2992
- }, states);
2993
- }
2994
- /** Reads all states from session storage and returns them as an object. */
2995
- async readFromSessionStorage() {
2996
- const storage = await this.page.evaluate(() => {
2997
- const storage2 = {};
2998
- for (let i = 0; i < sessionStorage.length; i++) {
2999
- const key = sessionStorage.key(i);
3000
- if (key !== null) {
3001
- const item = sessionStorage.getItem(key);
3002
- try {
3003
- storage2[key] = item ? JSON.parse(item) : null;
3004
- } catch (_e) {
3005
- storage2[key] = item;
3006
- }
3007
- }
3008
- }
3009
- return storage2;
3010
- });
3011
- return storage;
3012
- }
3013
- /**
3014
- * Sets the specified states in session storage.
3015
- * Optionally waits for the next main-frame navigation to establish a valid context before writing,
3016
- * and reloads the page after setting the data.
3017
- *
3018
- * Parameters:
3019
- * states: Object representing the states to set in session storage.
3020
- * reload: Boolean indicating whether to reload the page after setting the session storage data.
3021
- * waitForContext: Boolean indicating whether to wait for a main-frame navigation and a valid context.
3022
- */
3023
- async set(states, options = {}) {
3024
- await test4.step(this.getStepLabel("set"), async () => {
3025
- await this.ensureContext({ waitForContext: options.waitForContext });
3026
- await this.writeToSessionStorage(states);
3027
- if (options.reload) {
3028
- await this.page.reload();
3029
- }
3030
- });
3031
- }
3032
- /**
3033
- * Queues states to be set in the sessionStorage before the next navigation occurs.
3034
- * Handles different scenarios based on multiple calls made before the navigation occurs.
3035
- *
3036
- * 1. No Context, Single Call: Queues and sets states upon the next navigation.
3037
- * 2. No Context, Multiple Calls: Merges states from multiple calls and sets them upon the next navigation.
3038
- * 3. With Context: Still queues until the next navigation.
3039
- *
3040
- * Parameters:
3041
- * states: Object representing the states to queue for setting in session storage.
3042
- */
3043
- async setOnNextNavigation(states) {
3044
- this.queuedStates = { ...this.queuedStates, ...states };
3045
- const populateStorage = async () => {
3046
- await test4.step(this.getStepLabel("setOnNextNavigation"), async () => {
3047
- await this.writeToSessionStorage(this.queuedStates);
3048
- });
3049
- this.queuedStates = {};
3050
- };
3051
- if (!this.isInitiated) {
3052
- this.isInitiated = true;
3053
- const handler = async (frame) => {
3054
- if (frame !== this.page.mainFrame()) {
3055
- return;
3056
- }
3057
- await populateStorage();
3058
- this.page.off("framenavigated", handler);
3059
- this.isInitiated = false;
3060
- };
3061
- this.page.on("framenavigated", handler);
3062
- }
3063
- }
3064
- async get(keys, options = {}) {
3065
- let result = {};
3066
- await test4.step(this.getStepLabel("get"), async () => {
3067
- await this.ensureContext(options);
3068
- const allData = await this.readFromSessionStorage();
3069
- if (keys && keys.length > 0) {
3070
- for (const key of keys) {
3071
- if (Object.hasOwn(allData, key)) {
3072
- const value = allData[key];
3073
- if (value !== void 0) {
3074
- result[key] = value;
3075
- }
3076
- }
2004
+ if (typeof this.fullUrl !== "string") {
2005
+ throw new Error("gotoThisPage() is not supported when fullUrl is a RegExp.");
2006
+ }
2007
+ const waitUntil = this.resolveWaitUntil(options);
2008
+ const fullUrl = this.fullUrl;
2009
+ await test4.step(`${this.label}: Navigate to this Page`, async () => {
2010
+ await this.page.goto(fullUrl, { waitUntil });
2011
+ await this.executeActions();
2012
+ });
2013
+ }
2014
+ /**
2015
+ * Expect to be on this page. Works with both string and RegExp fullUrl values.
2016
+ * Uses waitUntil from navigation options when waiting for URL.
2017
+ */
2018
+ async expectThisPage(options) {
2019
+ const waitUntil = this.resolveWaitUntil(options);
2020
+ await test4.step(`${this.label}: Expect this Page`, async () => {
2021
+ await this.page.waitForURL(this.fullUrl, { waitUntil });
2022
+ await expect(async () => {
2023
+ if (this.fullUrl instanceof RegExp) {
2024
+ expect(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toMatch(this.fullUrl);
2025
+ } else {
2026
+ expect(this.page.url(), `expected '${this.fullUrl}', found '${this.page.url()}'`).toBe(this.fullUrl);
3077
2027
  }
3078
- } else {
3079
- result = allData;
3080
- }
2028
+ }).toPass();
2029
+ await this.executeActions();
3081
2030
  });
3082
- return result;
3083
2031
  }
3084
- async clear(keyOrOptions, options = {}) {
3085
- const { keys, waitForContext } = (() => {
3086
- if (Array.isArray(keyOrOptions)) {
3087
- return { keys: keyOrOptions, waitForContext: options.waitForContext };
3088
- }
3089
- if (typeof keyOrOptions === "string") {
3090
- return { keys: [keyOrOptions], waitForContext: options.waitForContext };
3091
- }
3092
- if (keyOrOptions) {
3093
- return { keys: void 0, waitForContext: keyOrOptions.waitForContext };
3094
- }
3095
- return { keys: void 0, waitForContext: options.waitForContext };
3096
- })();
3097
- await test4.step(this.getStepLabel("clear"), async () => {
3098
- await this.ensureContext({ waitForContext });
3099
- if (!keys || keys.length === 0) {
3100
- await this.page.evaluate(() => sessionStorage.clear());
3101
- return;
2032
+ /**
2033
+ * Expect to be on any other page (i.e. not this page).
2034
+ * Uses waitForLoadState from navigation options before validating URL.
2035
+ */
2036
+ async expectAnotherPage(options) {
2037
+ const waitForLoadState = this.resolveWaitForLoadState(options);
2038
+ await test4.step(`${this.label}: Expect any other Page`, async () => {
2039
+ await this.page.waitForLoadState(waitForLoadState);
2040
+ if (this.fullUrl instanceof RegExp) {
2041
+ await expect.poll(async () => this.page.url(), {
2042
+ message: `expected url to not match '${this.fullUrl}'`
2043
+ }).not.toMatch(this.fullUrl);
2044
+ } else {
2045
+ await expect.poll(async () => this.page.url(), {
2046
+ message: `expected url to not be '${this.fullUrl}', found '${this.page.url()}'`
2047
+ }).not.toBe(this.fullUrl);
3102
2048
  }
3103
- await this.page.evaluate((keysToClear) => {
3104
- for (const key of keysToClear) {
3105
- sessionStorage.removeItem(key);
3106
- }
3107
- }, keys);
3108
2049
  });
3109
2050
  }
3110
2051
  };
2052
+ function createNavigation(page, baseUrl, urlPath, fullUrl, label, actions = null, defaultOptions) {
2053
+ const navigation = new Navigation(page, baseUrl, urlPath, fullUrl, label, actions, defaultOptions);
2054
+ return navigation;
2055
+ }
3111
2056
 
3112
- // srcV2/pageObject.ts
2057
+ // src/pageObject.ts
3113
2058
  var PageObject = class {
3114
2059
  page;
3115
2060
  baseUrl;
@@ -3136,7 +2081,7 @@ var PageObject = class {
3136
2081
  this.getLocator = getLocator;
3137
2082
  this.getLocatorSchema = getLocatorSchema;
3138
2083
  this.getNestedLocator = getNestedLocator;
3139
- this.sessionStorage = new SessionStorage2(page, { label });
2084
+ this.sessionStorage = new SessionStorage(page, { label });
3140
2085
  this.defineLocators();
3141
2086
  this.navigation = createNavigation(
3142
2087
  this.page,
@@ -3165,211 +2110,11 @@ var PageObject = class {
3165
2110
  throw new Error("Invalid baseUrl or urlPath types. Expected string or RegExp.");
3166
2111
  }
3167
2112
  };
3168
-
3169
- // srcV2/fixture/base.fixtures.ts
3170
- import { test as base } from "@playwright/test";
3171
-
3172
- // srcV2/helpers/playwrightReportLogger.ts
3173
- var PlaywrightReportLogger = class _PlaywrightReportLogger {
3174
- // Initializes the logger with shared log level, log entries, and a context name.
3175
- constructor(sharedLogLevel, sharedLogEntry, contextName) {
3176
- this.sharedLogLevel = sharedLogLevel;
3177
- this.sharedLogEntry = sharedLogEntry;
3178
- this.contextName = contextName;
3179
- }
3180
- contextName;
3181
- logLevels = ["debug", "info", "warn", "error"];
3182
- /**
3183
- * Creates a child logger with a new contextual name, sharing the same log level and log entries with the parent logger.
3184
- *
3185
- * The root loggers log "level" is referenced by all child loggers and their child loggers and so on...
3186
- * Changing the log "level" of one, will change it for all.
3187
- */
3188
- getNewChildLogger(prefix) {
3189
- return new _PlaywrightReportLogger(this.sharedLogLevel, this.sharedLogEntry, `${this.contextName} -> ${prefix}`);
3190
- }
3191
- /**
3192
- * Logs a message with the specified log level, prefix, and additional arguments if the current log level permits.
3193
- */
3194
- // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
3195
- log(level, message, ...args) {
3196
- const logLevelIndex = this.logLevels.indexOf(level);
3197
- if (logLevelIndex < this.getCurrentLogLevelIndex()) {
3198
- return;
3199
- }
3200
- this.sharedLogEntry.push({
3201
- timestamp: /* @__PURE__ */ new Date(),
3202
- logLevel: level,
3203
- prefix: this.contextName,
3204
- message: `${message}
3205
-
3206
- ${args.join("\n\n")}`
3207
- });
3208
- }
3209
- /**
3210
- * Logs a debug-level message with the specified message and arguments.
3211
- */
3212
- // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
3213
- debug(message, ...args) {
3214
- this.log("debug", message, ...args);
3215
- }
3216
- /**
3217
- * Logs a info-level message with the specified message and arguments.
3218
- */
3219
- // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
3220
- info(message, ...args) {
3221
- this.log("info", message, ...args);
3222
- }
3223
- /**
3224
- * Logs a warn-level message with the specified message and arguments.
3225
- */
3226
- // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
3227
- warn(message, ...args) {
3228
- this.log("warn", message, ...args);
3229
- }
3230
- /**
3231
- * Logs a error-level message with the specified message and arguments.
3232
- */
3233
- // biome-ignore lint/suspicious/noExplicitAny: logger accepts arbitrary payloads for debug output.
3234
- error(message, ...args) {
3235
- this.log("error", message, ...args);
3236
- }
3237
- /**
3238
- * Sets the current log level to the specified level during runTime.
3239
- */
3240
- setLogLevel(level) {
3241
- this.sharedLogLevel.current = level;
3242
- }
3243
- /**
3244
- * Retrieves the current log level during runtime.
3245
- */
3246
- getCurrentLogLevel() {
3247
- return this.sharedLogLevel.current;
3248
- }
3249
- /**
3250
- * Retrieves the index of the current log level in the logLevels array during runtime.
3251
- */
3252
- getCurrentLogLevelIndex() {
3253
- return this.logLevels.indexOf(this.sharedLogLevel.current);
3254
- }
3255
- /**
3256
- * Resets the current log level to the initial level during runtime.
3257
- */
3258
- resetLogLevel() {
3259
- this.sharedLogLevel.current = this.sharedLogLevel.initial;
3260
- }
3261
- /**
3262
- * Checks if the input log level is equal to the current log level of the PlaywrightReportLogger instance.
3263
- */
3264
- isCurrentLogLevel(level) {
3265
- return this.sharedLogLevel.current === level;
3266
- }
3267
- /**
3268
- * Returns 'true' if the "level" parameter provided has an equal or greater index than the current logLevel.
3269
- */
3270
- isLogLevelEnabled(level) {
3271
- const logLevelIndex = this.logLevels.indexOf(level);
3272
- if (logLevelIndex < this.getCurrentLogLevelIndex()) {
3273
- return false;
3274
- }
3275
- return true;
3276
- }
3277
- /**
3278
- * Attaches the recorded log entries to the Playwright HTML report in a sorted and formatted manner.
3279
- */
3280
- attachLogsToTest(testInfo) {
3281
- this.sharedLogEntry.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
3282
- for (const log of this.sharedLogEntry) {
3283
- const printTime = log.timestamp.toLocaleTimeString("nb-NO", {
3284
- hour: "2-digit",
3285
- minute: "2-digit",
3286
- second: "2-digit"
3287
- });
3288
- const printDate = log.timestamp.toLocaleDateString("nb-NO", {
3289
- day: "2-digit",
3290
- month: "2-digit",
3291
- year: "numeric"
3292
- });
3293
- const printLogLevel = `${log.logLevel.toUpperCase()}`;
3294
- const printPrefix = log.prefix ? `: [${log.prefix}]` : "";
3295
- let messageBody = "";
3296
- let messageContentType = "";
3297
- try {
3298
- const parsedMessage = JSON.parse(log.message);
3299
- messageContentType = "application/json";
3300
- messageBody = JSON.stringify(parsedMessage, null, 2);
3301
- } catch (_error) {
3302
- messageContentType = "text/plain";
3303
- messageBody = log.message;
3304
- }
3305
- testInfo.attach(`${printTime} ${printDate} - ${printLogLevel} ${printPrefix}`, {
3306
- contentType: messageContentType,
3307
- body: Buffer.from(messageBody)
3308
- });
3309
- }
3310
- }
3311
- };
3312
-
3313
- // srcV2/fixture/base.fixtures.ts
3314
- var test5 = base.extend({
3315
- // biome-ignore lint/correctness/noEmptyPattern: Playwright does not support the use of _
3316
- log: async ({}, use, testInfo) => {
3317
- const contextName = "TestCase";
3318
- const sharedLogEntry = [];
3319
- const sharedLogLevel = testInfo.retry === 0 ? { current: "warn", initial: "warn" } : { current: "debug", initial: "debug" };
3320
- const log = new PlaywrightReportLogger(sharedLogLevel, sharedLogEntry, contextName);
3321
- await use(log);
3322
- log.attachLogsToTest(testInfo);
3323
- }
3324
- });
3325
-
3326
- // srcV2/helpers/stepDecorator.ts
3327
- import { test as test6 } from "@playwright/test";
3328
- var isMethodDecoratorArgs = (args) => args.length === 3 && typeof args[0] === "object" && (typeof args[1] === "string" || typeof args[1] === "symbol");
3329
- var isStage3MethodDecoratorArgs = (args) => args.length === 2 && typeof args[0] === "function" && args[1] !== null && typeof args[1] === "object";
3330
- var normalizeStepArguments = (args) => {
3331
- const [titleOrOptions, maybeOptions] = args;
3332
- const title = typeof titleOrOptions === "string" ? titleOrOptions : void 0;
3333
- const options = typeof titleOrOptions === "string" ? maybeOptions : titleOrOptions;
3334
- return { title, options };
3335
- };
3336
- var createWrappedMethod = (original, methodName, title, options) => function(...methodArgs) {
3337
- const rawClassName = this.constructor?.name ?? "";
3338
- const className = rawClassName && rawClassName !== "Object" ? rawClassName : "Anonymous";
3339
- const resolvedTitle = title ?? `${className}.${String(methodName)}`;
3340
- return test6.step(resolvedTitle, () => original.apply(this, methodArgs), options);
3341
- };
3342
- var createStepDecorator = ({ title, options }) => (valueOrTarget, contextOrKey, descriptor) => {
3343
- if (typeof valueOrTarget === "function" && isStage3MethodDecoratorArgs([valueOrTarget, contextOrKey])) {
3344
- const [original2, context] = [valueOrTarget, contextOrKey];
3345
- return createWrappedMethod(original2, context.name, title, options);
3346
- }
3347
- if (!descriptor || typeof descriptor.value !== "function") {
3348
- throw new Error("@step decorator can only be applied to methods.");
3349
- }
3350
- const original = descriptor.value;
3351
- descriptor.value = createWrappedMethod(original, contextOrKey, title, options);
3352
- return descriptor;
3353
- };
3354
- function step(...args) {
3355
- if (isStage3MethodDecoratorArgs(args)) {
3356
- return createStepDecorator(normalizeStepArguments([]))(...args);
3357
- }
3358
- if (isMethodDecoratorArgs(args)) {
3359
- return createStepDecorator(normalizeStepArguments([]))(...args);
3360
- }
3361
- return createStepDecorator(normalizeStepArguments(args));
3362
- }
3363
2113
  export {
3364
- BaseApi,
3365
- BasePage,
3366
- BasePageV1toV2,
3367
- GetByMethod,
3368
- GetLocatorBase,
3369
2114
  PageObject,
3370
2115
  PlaywrightReportLogger,
3371
- SessionStorage2 as SessionStorage,
2116
+ SessionStorage,
3372
2117
  createRegistryWithAccessors,
3373
2118
  step,
3374
- test5 as test
2119
+ test
3375
2120
  };