pomwright 0.0.9 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20,12 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // index.ts
21
21
  var POMWright_exports = {};
22
22
  __export(POMWright_exports, {
23
+ BaseApi: () => BaseApi,
24
+ BasePage: () => BasePage2,
23
25
  GetByMethod: () => GetByMethod,
24
- POMWright: () => BasePage2,
25
- POMWrightApi: () => BaseApi,
26
- POMWrightGetLocatorBase: () => GetLocatorBase,
27
- POMWrightLogger: () => PlaywrightReportLogger,
28
- POMWrightTestFixture: () => test3
26
+ GetLocatorBase: () => GetLocatorBase,
27
+ PlaywrightReportLogger: () => PlaywrightReportLogger,
28
+ test: () => test3
29
29
  });
30
30
  module.exports = __toCommonJS(POMWright_exports);
31
31
 
@@ -106,6 +106,7 @@ function getLocatorSchemaDummy() {
106
106
 
107
107
  // src/helpers/playwrightReportLogger.ts
108
108
  var PlaywrightReportLogger = class _PlaywrightReportLogger {
109
+ // Initializes the logger with shared log level, log entries, and a context name.
109
110
  constructor(sharedLogLevel, sharedLogEntry, contextName) {
110
111
  this.sharedLogLevel = sharedLogLevel;
111
112
  this.sharedLogEntry = sharedLogEntry;
@@ -114,28 +115,16 @@ var PlaywrightReportLogger = class _PlaywrightReportLogger {
114
115
  contextName;
115
116
  logLevels = ["debug", "info", "warn", "error"];
116
117
  /**
117
- * Creates a new logger instance with a new contextual name which includes a reference to the parent logger.
118
+ * Creates a child logger with a new contextual name, sharing the same log level and log entries with the parent logger.
118
119
  *
119
120
  * The root loggers log "level" is referenced by all child loggers and their child loggers and so on...
120
121
  * Changing the log "level" of one, will change it for all.
121
- *
122
- * @param prefix - The prefix to add to the new logger instance.
123
- * @returns - A new logger instance with the updated prefix.
124
122
  */
125
123
  getNewChildLogger(prefix) {
126
- return new _PlaywrightReportLogger(
127
- this.sharedLogLevel,
128
- this.sharedLogEntry,
129
- `${this.contextName} -> ${prefix}`
130
- );
124
+ return new _PlaywrightReportLogger(this.sharedLogLevel, this.sharedLogEntry, `${this.contextName} -> ${prefix}`);
131
125
  }
132
126
  /**
133
- * Logs a message with the specified log level, prefix, and arguments.
134
- * The message will only be recorded if the current log level allows it.
135
- *
136
- * @param level - The log level for the message.
137
- * @param message - The log message.
138
- * @param args - Additional arguments to log.
127
+ * Logs a message with the specified log level, prefix, and additional arguments if the current log level permits.
139
128
  */
140
129
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
141
130
  log(level, message, ...args) {
@@ -154,9 +143,6 @@ ${args.join("\n\n")}`
154
143
  }
155
144
  /**
156
145
  * Logs a debug-level message with the specified message and arguments.
157
- *
158
- * @param message - The log message.
159
- * @param args - Additional arguments to log.
160
146
  */
161
147
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
162
148
  debug(message, ...args) {
@@ -164,9 +150,6 @@ ${args.join("\n\n")}`
164
150
  }
165
151
  /**
166
152
  * Logs a info-level message with the specified message and arguments.
167
- *
168
- * @param message - The log message.
169
- * @param args - Additional arguments to log.
170
153
  */
171
154
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
172
155
  info(message, ...args) {
@@ -174,9 +157,6 @@ ${args.join("\n\n")}`
174
157
  }
175
158
  /**
176
159
  * Logs a warn-level message with the specified message and arguments.
177
- *
178
- * @param message - The log message.
179
- * @param args - Additional arguments to log.
180
160
  */
181
161
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
182
162
  warn(message, ...args) {
@@ -184,54 +164,43 @@ ${args.join("\n\n")}`
184
164
  }
185
165
  /**
186
166
  * Logs a error-level message with the specified message and arguments.
187
- *
188
- * @param message - The log message.
189
- * @param args - Additional arguments to log.
190
167
  */
191
168
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
192
169
  error(message, ...args) {
193
170
  this.log("error", message, ...args);
194
171
  }
195
172
  /**
196
- * Set logLevel during runtime.
197
- *
198
- * @param level - The logLevel ("debug" | "info" | "warn" | "error").
173
+ * Sets the current log level to the specified level during runTime.
199
174
  */
200
175
  setLogLevel(level) {
201
176
  this.sharedLogLevel.current = level;
202
177
  }
203
178
  /**
204
- * Returns the current logLevel during runtime.
205
- *
206
- * @returns LogLevel ("debug" | "info" | "warn" | "error")
179
+ * Retrieves the current log level during runtime.
207
180
  */
208
181
  getCurrentLogLevel() {
209
182
  return this.sharedLogLevel.current;
210
183
  }
211
184
  /**
212
- * Returns the index of the current logLevel during runtime.
185
+ * Retrieves the index of the current log level in the logLevels array during runtime.
213
186
  */
214
187
  getCurrentLogLevelIndex() {
215
188
  return this.logLevels.indexOf(this.sharedLogLevel.current);
216
189
  }
217
190
  /**
218
- * Sets logLevel back to the initial logLevel during runtime.
191
+ * Resets the current log level to the initial level during runtime.
219
192
  */
220
193
  resetLogLevel() {
221
194
  this.sharedLogLevel.current = this.sharedLogLevel.initial;
222
195
  }
223
196
  /**
224
- * isCurrentLogLevel is a method that checks if the input log level is equal to the current log level of the PlaywrightReportLogger instance.
225
- * @param level The log level to check if it is equal to the current log level.
226
- * @returns A boolean indicating whether the input log level is equal to the current log level.
197
+ * Checks if the input log level is equal to the current log level of the PlaywrightReportLogger instance.
227
198
  */
228
199
  isCurrentLogLevel(level) {
229
200
  return this.sharedLogLevel.current === level;
230
201
  }
231
202
  /**
232
- * isLogLevelEnabled returns 'true' if the "level" parameter provided has an equal or greater index than the current logLevel.
233
- * @param level
234
- * @returns
203
+ * Returns 'true' if the "level" parameter provided has an equal or greater index than the current logLevel.
235
204
  */
236
205
  isLogLevelEnabled(level) {
237
206
  const logLevelIndex = this.logLevels.indexOf(level);
@@ -241,14 +210,10 @@ ${args.join("\n\n")}`
241
210
  return true;
242
211
  }
243
212
  /**
244
- * Attaches the recorded logs to the Playwright HTML report.
245
- *
246
- * @param testInfo - The test information object from Playwright.
213
+ * Attaches the recorded log entries to the Playwright HTML report in a sorted and formatted manner.
247
214
  */
248
215
  attachLogsToTest(testInfo) {
249
- this.sharedLogEntry.sort(
250
- (a, b) => a.timestamp.getTime() - b.timestamp.getTime()
251
- );
216
+ this.sharedLogEntry.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
252
217
  for (const log of this.sharedLogEntry) {
253
218
  const printTime = log.timestamp.toLocaleTimeString("nb-NO", {
254
219
  hour: "2-digit",
@@ -272,13 +237,10 @@ ${args.join("\n\n")}`
272
237
  messageContentType = "text/plain";
273
238
  messageBody = log.message;
274
239
  }
275
- testInfo.attach(
276
- `${printTime} ${printDate} - ${printLogLevel} ${printPrefix}`,
277
- {
278
- contentType: messageContentType,
279
- body: Buffer.from(messageBody)
280
- }
281
- );
240
+ testInfo.attach(`${printTime} ${printDate} - ${printLogLevel} ${printPrefix}`, {
241
+ contentType: messageContentType,
242
+ body: Buffer.from(messageBody)
243
+ });
282
244
  }
283
245
  }
284
246
  };
@@ -316,10 +278,9 @@ var GetBy = class {
316
278
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
317
279
  subMethodMap;
318
280
  /**
319
- * Retrieves a Playwright Locator based on the method specified in the LocatorSchema.
320
- *
321
- * @param locatorSchema The LocatorSchema object specifying the locator method and its parameters.
322
- * @returns A promise that resolves to the appropriate Playwright Locator.
281
+ * Retrieves a Locator based on the details provided in a LocatorSchema.
282
+ * The method identifies the appropriate locator creation function from methodMap and invokes it.
283
+ * Throws an error if the locator method is unsupported.
323
284
  */
324
285
  getLocator = (locatorSchema) => {
325
286
  const methodName = locatorSchema.locatorMethod;
@@ -329,6 +290,11 @@ var GetBy = class {
329
290
  }
330
291
  throw new Error(`Unsupported locator method: ${methodName}`);
331
292
  };
293
+ /**
294
+ * Internal method to retrieve a Locator using a specified GetByMethodSubset and LocatorSchema.
295
+ * It identifies the appropriate locator creation function from subMethodMap and invokes it.
296
+ * Throws an error if the caller is unknown or if the initial locator is not found.
297
+ */
332
298
  getBy = (caller, locator) => {
333
299
  const method = this.subMethodMap[caller];
334
300
  if (!method) {
@@ -345,70 +311,29 @@ var GetBy = class {
345
311
  return initialPWLocator;
346
312
  };
347
313
  /**
348
- * Creates a new method that returns a Playwright Locator using the specified method name.
349
- *
350
- * @param methodName The name of the method to use for getting the element.
351
- * @returns An async function that takes a locator and returns a Playwright Locator.
314
+ * Creates a method for generating a Locator using a specific GetByMethodSubset.
315
+ * Returns a function that takes a LocatorSchema and returns a Locator.
316
+ * The returned function is a locator creation function corresponding to the specified methodName.
352
317
  */
353
318
  createByMethod = (methodName) => {
354
319
  return (locator) => {
355
320
  return this.getBy(methodName, locator);
356
321
  };
357
322
  };
358
- /**
359
- * Returns a {@link Locator} using the selectors 'role' (required) and 'roleOptions' (optional), from a {@link LocatorSchema} Object.
360
- *
361
- * @param locator - The locator.
362
- * @returns - A promise that resolves to the {@link Locator}.
363
- */
323
+ // Methods for creating locators using different locator methods.
324
+ // These methods are generated using createByMethod and provide a unified way to create locators based on LocatorSchema.
325
+ // Each method is responsible for creating a Locator based on a specific attribute (role, text, label, etc.) provided in LocatorSchema.
326
+ // These methods return a Locator and throw an error if the necessary attribute is not defined in the LocatorSchema.
364
327
  role = this.createByMethod("role" /* role */);
365
- /**
366
- * Returns a {@link Locator} using the selectors 'text' (required) and 'textOptions' (optional), from a {@link LocatorSchema} Object.
367
- *
368
- * @param locator - The locator.
369
- * @returns - A promise that resolves to the {@link Locator}.
370
- */
371
328
  text = this.createByMethod("text" /* text */);
372
- /**
373
- * Returns a {@link Locator} using the selectors 'label' (required) and 'labelOptions' (optional), from a {@link LocatorSchema} Object.
374
- *
375
- * @param locator - The locator.
376
- * @returns - A promise that resolves to the {@link Locator}.
377
- */
378
329
  label = this.createByMethod("label" /* label */);
379
- /**
380
- * Returns a {@link Locator} using the selectors 'placeholder' (required) and 'placeholderOptions' (optional), from a {@link LocatorSchema} Object.
381
- *
382
- * @param locator - The locator.
383
- * @returns - A promise that resolves to the {@link Locator}.
384
- */
385
330
  placeholder = this.createByMethod("placeholder" /* placeholder */);
386
- /**
387
- * Returns a {@link Locator} using the selectors 'altText' (required) and 'altTextOptions' (optional), from a {@link LocatorSchema} Object.
388
- *
389
- * @param locator - The locator.
390
- * @returns - A promise that resolves to the {@link Locator}.
391
- */
392
331
  altText = this.createByMethod("altText" /* altText */);
393
- /**
394
- * Returns a {@link Locator} using the selectors 'title' (required) and 'titleOptions' (optional), from a {@link LocatorSchema} Object.
395
- *
396
- * @param locator - The locator.
397
- * @returns - A promise that resolves to the {@link Locator}.
398
- */
399
332
  title = this.createByMethod("title" /* title */);
400
- /**
401
- * Returns a {@link Locator} using the selectors 'locator' (required), from a {@link LocatorSchema} Object.
402
- *
403
- * @param locator - The locator.
404
- * @returns - A promise that resolves to the {@link Locator}.
405
- */
406
333
  locator = this.createByMethod("locator" /* locator */);
407
334
  /**
408
- * Returns a {@link FrameLocator} using the selector string 'frameLocator' (required), from a {@link LocatorSchema} Object.
409
- *
410
- * @param locatorSchema - Which contains the frameLocator selector.
411
- * @returns A promise that resolves to the {@link FrameLocator}.
335
+ * Returns a FrameLocator using the 'frameLocator' selector from a LocatorSchema.
336
+ * Throws an error if the frameLocator is not defined.
412
337
  */
413
338
  frameLocator = (locatorSchema) => {
414
339
  const initialFrameLocator = locatorSchema.frameLocator ? this.page.frameLocator(locatorSchema.frameLocator) : null;
@@ -420,27 +345,21 @@ var GetBy = class {
420
345
  return initialFrameLocator;
421
346
  };
422
347
  /**
423
- * Returns a {@link Locator} using the selectors 'testId' (required), from a {@link LocatorSchema} Object.
424
- *
425
- * @param locator - The locator.
426
- * @returns - A promise that resolves to the {@link Locator}.
348
+ * Returns a Locator using the 'testId' selector from a LocatorSchema.
349
+ * Throws an error if the testId is not defined.
427
350
  */
428
351
  testId = (locator) => {
429
352
  const initialPWLocator = locator.testId ? this.page.getByTestId(locator.testId) : null;
430
353
  if (!initialPWLocator) {
431
354
  const errorText = `Locator "${locator.locatorSchemaPath}" .testId is not defined.`;
432
- this.log.warn(
433
- `Locator "${locator.locatorSchemaPath}" .testId is not defined.`
434
- );
355
+ this.log.warn(`Locator "${locator.locatorSchemaPath}" .testId is not defined.`);
435
356
  throw new Error(errorText);
436
357
  }
437
358
  return initialPWLocator;
438
359
  };
439
360
  /**
440
- * Returns a {@link Locator} using the selectors 'dataCy' (required), from a {@link LocatorSchema} Object.
441
- *
442
- * @param locator - The locator.
443
- * @returns - A promise that resolves to the {@link Locator}.
361
+ * Returns a Locator using the 'dataCy' selector from a LocatorSchema.
362
+ * Throws an error if the dataCy is undefined.
444
363
  */
445
364
  dataCy = (locator) => {
446
365
  let initialPWLocator = null;
@@ -454,10 +373,8 @@ var GetBy = class {
454
373
  return initialPWLocator;
455
374
  };
456
375
  /**
457
- * Returns a {@link Locator} using the selectors 'id' (required), from a {@link LocatorSchema} Object.
458
- *
459
- * @param locator - The locator.
460
- * @returns - A promise that resolves to the {@link Locator}.
376
+ * Returns a Locator using the 'id' selector from a LocatorSchema.
377
+ * Throws an error if the id is not defined or the id type is unsupported.
461
378
  */
462
379
  id = (locator) => {
463
380
  let initialPWLocator = null;
@@ -490,38 +407,34 @@ var GetBy = class {
490
407
  };
491
408
 
492
409
  // src/helpers/getLocatorBase.ts
410
+ var REQUIRED_PROPERTIES_FOR_LOCATOR_SCHEMA_WITH_METHODS = [
411
+ "update",
412
+ "updates",
413
+ "getNestedLocator",
414
+ "getLocator",
415
+ "locatorSchemaPath",
416
+ "locatorMethod",
417
+ "schemasMap"
418
+ ];
493
419
  var GetLocatorBase = class {
494
420
  /**
495
- * Constructor for the GetLocatorBaseClass.
496
- *
497
- * @param {BasePage} pageObjectClass - The page object class to which the locator pertains.
498
- * @param {PlaywrightReportLogger} log - The PlaywrightReportLogger child of the page object class.
421
+ * Initializes the GetLocatorBase class with a page object class and a logger.
499
422
  */
500
423
  constructor(pageObjectClass, log) {
501
424
  this.pageObjectClass = pageObjectClass;
502
425
  this.log = log;
503
426
  this.locatorSchemas = /* @__PURE__ */ new Map();
504
- this.getBy = new GetBy(
505
- this.pageObjectClass.page,
506
- this.log.getNewChildLogger("GetBy")
507
- );
427
+ this.getBy = new GetBy(this.pageObjectClass.page, this.log.getNewChildLogger("GetBy"));
508
428
  }
509
429
  getBy;
510
430
  locatorSchemas;
511
431
  /**
512
- * test
513
- * @param locatorSchemaPath
514
- * @returns
432
+ * Retrieves a locator schema with additional methods for manipulation and retrieval of locators.
515
433
  */
516
434
  getLocatorSchema(locatorSchemaPath) {
517
435
  const pathIndexPairs = this.extractPathsFromSchema(locatorSchemaPath);
518
- const schemasMap = this.collectDeepCopies(
519
- locatorSchemaPath,
520
- pathIndexPairs
521
- );
522
- const locatorSchemaCopy = schemasMap.get(
523
- locatorSchemaPath
524
- );
436
+ const schemasMap = this.collectDeepCopies(locatorSchemaPath, pathIndexPairs);
437
+ const locatorSchemaCopy = schemasMap.get(locatorSchemaPath);
525
438
  locatorSchemaCopy.schemasMap = schemasMap;
526
439
  const self = this;
527
440
  locatorSchemaCopy.update = function(updates) {
@@ -533,17 +446,17 @@ var GetLocatorBase = class {
533
446
  return this;
534
447
  };
535
448
  locatorSchemaCopy.getNestedLocator = async (indices) => {
536
- return await this.buildNestedLocator(
537
- locatorSchemaPath,
538
- schemasMap,
539
- indices
540
- );
449
+ return await this.buildNestedLocator(locatorSchemaPath, schemasMap, indices);
541
450
  };
542
451
  locatorSchemaCopy.getLocator = async () => {
543
452
  return this.getBy.getLocator(locatorSchemaCopy);
544
453
  };
545
454
  return locatorSchemaCopy;
546
455
  }
456
+ /**
457
+ * Collects deep copies of locator schemas based on a given locator schema path and path-index pairs.
458
+ * It ensures that each locator schema and its sub-schemas are properly cloned and stored.
459
+ */
547
460
  collectDeepCopies(locatorSchemaPath, pathIndexPairs) {
548
461
  const schemasMap = /* @__PURE__ */ new Map();
549
462
  const fullSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
@@ -563,54 +476,81 @@ var GetLocatorBase = class {
563
476
  }
564
477
  return schemasMap;
565
478
  }
479
+ isLocatorSchemaWithMethods(schema) {
480
+ return REQUIRED_PROPERTIES_FOR_LOCATOR_SCHEMA_WITH_METHODS.every((p) => p in schema);
481
+ }
482
+ /**
483
+ * Applies an update to a specific locator schema within the provided map of schemas.
484
+ * This method ensures that the specified updates are merged into the targeted locator schema.
485
+ */
566
486
  applyUpdate(schemasMap, locatorSchemaPath, updateData) {
567
487
  const schema = schemasMap.get(locatorSchemaPath);
568
488
  if (schema) {
569
- schemasMap.set(locatorSchemaPath, this.deepMerge(schema, updateData));
489
+ const updatedSchema = this.deepMerge(schema, updateData);
490
+ if (this.isLocatorSchemaWithMethods(schema)) {
491
+ Object.assign(schema, updatedSchema);
492
+ } else {
493
+ throw new Error("Invalid LocatorSchema object provided for update method.");
494
+ }
570
495
  }
571
496
  }
497
+ /**
498
+ * Applies multiple updates to locator schemas based on provided path-index pairs and update data.
499
+ * This method facilitates batch updating of nested schemas within a complex locator structure.
500
+ */
572
501
  applyUpdates(schemasMap, pathIndexPairs, updatesData) {
573
502
  for (const [index, updateAtIndex] of Object.entries(updatesData)) {
574
503
  const path = pathIndexPairs[parseInt(index)]?.path;
575
504
  if (path && updateAtIndex) {
576
505
  const schema = schemasMap.get(path);
577
506
  if (schema) {
578
- schemasMap.set(path, this.deepMerge(schema, updateAtIndex));
507
+ const updatedSchema = this.deepMerge(schema, updateAtIndex);
508
+ if (this.isLocatorSchemaWithMethods(schema)) {
509
+ Object.assign(schema, updatedSchema);
510
+ } else {
511
+ schemasMap.set(path, updatedSchema);
512
+ }
579
513
  }
580
514
  }
581
515
  }
582
516
  }
517
+ /**
518
+ * Creates a new locator schema based on provided schema details and a schema path.
519
+ * This method structures a new locator schema ready for inclusion in the locator management system.
520
+ */
583
521
  createLocatorSchema(schemaDetails, locatorSchemaPath) {
584
522
  const schema = { ...schemaDetails, locatorSchemaPath };
585
523
  return schema;
586
524
  }
525
+ /**
526
+ * Adds a new locator schema to the internal map of locator schemas.
527
+ * This method ensures that the new schema is properly registered and can be referenced and used in locator generation.
528
+ */
587
529
  addSchema(locatorSchemaPath, schemaDetails) {
588
- const newLocatorSchema = this.createLocatorSchema(
589
- schemaDetails,
590
- locatorSchemaPath
591
- );
530
+ const newLocatorSchema = this.createLocatorSchema(schemaDetails, locatorSchemaPath);
592
531
  const existingSchemaFunc = this.safeGetLocatorSchema(locatorSchemaPath);
593
532
  if (existingSchemaFunc) {
594
533
  const existingLocatorSchema = existingSchemaFunc();
595
534
  throw new Error(
596
535
  `[${this.pageObjectClass.pocName}] A LocatorSchema with the path '${locatorSchemaPath}' already exists.
597
- Existing Schema: ${JSON.stringify(
598
- existingLocatorSchema,
599
- null,
600
- 2
601
- )}
602
- Attempted to Add Schema: ${JSON.stringify(
603
- newLocatorSchema,
604
- null,
605
- 2
606
- )}`
536
+ Existing Schema: ${JSON.stringify(existingLocatorSchema, null, 2)}
537
+ Attempted to Add Schema: ${JSON.stringify(newLocatorSchema, null, 2)}`
607
538
  );
608
539
  }
609
540
  this.locatorSchemas.set(locatorSchemaPath, () => newLocatorSchema);
610
541
  }
542
+ /**
543
+ * Safely retrieves a locator schema function based on a given path.
544
+ * This method provides a secure way to access locator schemas, ensuring that only valid paths are used.
545
+ */
611
546
  safeGetLocatorSchema(path) {
612
547
  return this.locatorSchemas.get(path);
613
548
  }
549
+ /**
550
+ * Extracts path-index pairs from a given schema path.
551
+ * This utility function breaks down a complex path into manageable parts,
552
+ * associating each part with its corresponding index when necessary.
553
+ */
614
554
  extractPathsFromSchema = (paths, indices = {}) => {
615
555
  const schemaParts = paths.split(".");
616
556
  let cumulativePath = "";
@@ -645,51 +585,59 @@ Attempted to Add Schema: ${JSON.stringify(
645
585
  );
646
586
  throw error;
647
587
  };
648
- // Merges 'source' into 'target', combining their properties into a new isolated object.
649
- deepMerge(target, source) {
588
+ /** Merges 'source' into 'target', combining their properties into a new isolated object. */
589
+ deepMerge(target, source, schema = getLocatorSchemaDummy()) {
650
590
  const merged = { ...target };
651
- const dummySchema = getLocatorSchemaDummy();
652
- if (typeof source === "object" && source !== null) {
653
- const filteredKeys = Object.keys(source).filter(
654
- (key) => key !== "locatorSchemaPath"
655
- );
656
- for (const key of filteredKeys) {
657
- const targetKey = key;
658
- const sourceKey = key;
659
- if (!(key in dummySchema)) {
660
- throw new Error(
661
- `Invalid property: '${key}' is not a valid property of LocatorSchema`
591
+ for (const key of Object.keys(source)) {
592
+ if (key === "locatorSchemaPath") {
593
+ throw new Error(
594
+ `[${this.pageObjectClass.pocName}] Invalid property: 'locatorSchemaPath' cannot be updated. Attempted to update LocatorSchemaPath from '${target[key]}' to '${source[key]}'.`
595
+ );
596
+ }
597
+ if (!(key in schema)) {
598
+ throw new Error(`Invalid property: '${key}' is not a valid property of LocatorSchema`);
599
+ }
600
+ const sourceValue = source[key];
601
+ const targetValue = target[key];
602
+ if (typeof sourceValue === "object" && sourceValue !== null && schema[key] && typeof schema[key] === "object") {
603
+ if (targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
604
+ merged[key] = this.deepMerge(
605
+ targetValue,
606
+ // Updated type here
607
+ sourceValue,
608
+ schema[key]
609
+ );
610
+ } else {
611
+ merged[key] = this.deepMerge(
612
+ {},
613
+ // Updated type here
614
+ sourceValue,
615
+ schema[key]
662
616
  );
663
617
  }
664
- const targetValue = merged[targetKey];
665
- const sourceValue = source[sourceKey];
666
- if (sourceValue !== void 0) {
667
- if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
668
- merged[targetKey] = [
669
- ...targetValue,
670
- ...sourceValue
671
- ];
672
- } else if (sourceValue instanceof RegExp) {
673
- merged[targetKey] = new RegExp(
674
- sourceValue.source,
675
- sourceValue.flags
676
- );
677
- } else if (typeof sourceValue === "object" && sourceValue !== null) {
678
- merged[targetKey] = targetValue ? this.deepMerge(targetValue, sourceValue) : structuredClone(sourceValue);
679
- } else {
680
- merged[targetKey] = sourceValue;
681
- }
618
+ } else {
619
+ if (Array.isArray(sourceValue)) {
620
+ merged[key] = Array.isArray(targetValue) ? targetValue.concat(sourceValue) : [...sourceValue];
621
+ } else if (typeof sourceValue === "object" && sourceValue !== null && Object.prototype.toString.call(sourceValue) === "[object RegExp]") {
622
+ merged[key] = new RegExp(
623
+ sourceValue.source,
624
+ sourceValue.flags
625
+ );
626
+ } else {
627
+ merged[key] = sourceValue;
682
628
  }
683
629
  }
684
630
  }
685
631
  return merged;
686
632
  }
633
+ /**
634
+ * Assembles nested locators based on a locator schema path and optional indices for locating specific elements.
635
+ * This method orchestrates the process of building a locator that can resolve to a specific element or set of
636
+ * elements in the DOM.
637
+ */
687
638
  buildNestedLocator = async (locatorSchemaPath, schemasMap, indices = {}) => {
688
639
  return await import_test2.test.step(`${this.pageObjectClass.pocName}: Build Nested Locator`, async () => {
689
- const pathIndexPairs = this.extractPathsFromSchema(
690
- locatorSchemaPath,
691
- indices
692
- );
640
+ const pathIndexPairs = this.extractPathsFromSchema(locatorSchemaPath, indices);
693
641
  let currentLocator = null;
694
642
  let currentIFrame = null;
695
643
  const nestedLocatorResults = {
@@ -732,36 +680,19 @@ Attempted to Add Schema: ${JSON.stringify(
732
680
  }
733
681
  }
734
682
  if (currentIFrame !== void 0) {
735
- await this.evaluateCurrentLocator(
736
- currentLocator,
737
- nestedLocatorResults.NestingSteps,
738
- currentIFrame
739
- );
683
+ await this.evaluateCurrentLocator(currentLocator, nestedLocatorResults.NestingSteps, currentIFrame);
740
684
  } else {
741
- await this.evaluateCurrentLocator(
742
- currentLocator,
743
- nestedLocatorResults.NestingSteps,
744
- null
745
- );
685
+ await this.evaluateCurrentLocator(currentLocator, nestedLocatorResults.NestingSteps, null);
746
686
  }
747
687
  }
748
688
  } catch (error) {
749
- this.logError(
750
- error,
751
- locatorSchemaPath,
752
- currentLocator,
753
- path,
754
- pathIndexPairs,
755
- nestedLocatorResults
756
- );
689
+ this.logError(error, locatorSchemaPath, currentLocator, path, pathIndexPairs, nestedLocatorResults);
757
690
  break;
758
691
  }
759
692
  }
760
693
  if (!currentLocator) {
761
694
  this.logError(
762
- new Error(
763
- `Failed to build nested locator for path: ${locatorSchemaPath}`
764
- ),
695
+ new Error(`Failed to build nested locator for path: ${locatorSchemaPath}`),
765
696
  locatorSchemaPath,
766
697
  currentLocator,
767
698
  locatorSchemaPath,
@@ -769,10 +700,7 @@ Attempted to Add Schema: ${JSON.stringify(
769
700
  );
770
701
  }
771
702
  if (this.log.isLogLevelEnabled("debug")) {
772
- this.log.debug(
773
- "Nested locator evaluation results:",
774
- JSON.stringify(nestedLocatorResults, null, 2)
775
- );
703
+ this.log.debug("Nested locator evaluation results:", JSON.stringify(nestedLocatorResults, null, 2));
776
704
  }
777
705
  if (currentLocator != null) {
778
706
  currentLocator.scrollIntoViewIfNeeded().catch(() => {
@@ -781,6 +709,9 @@ Attempted to Add Schema: ${JSON.stringify(
781
709
  }
782
710
  });
783
711
  };
712
+ /**
713
+ * Evaluates the current locator, capturing details about its resolution status and the elements it resolves to.
714
+ */
784
715
  evaluateCurrentLocator = async (currentLocator, resultsArray, currentIFrame) => {
785
716
  if (currentIFrame) {
786
717
  resultsArray.push({
@@ -799,17 +730,13 @@ Attempted to Add Schema: ${JSON.stringify(
799
730
  }
800
731
  };
801
732
  /**
802
- * Evaluates the Playwright locator, checking if it resolves to any elements, and retrieves element attributes.
803
- *
804
- * @param pwLocator - The Playwright locator to evaluate.
805
- * @returns - A promise that resolves to an object containing the Playwright locator and an array of element attributes for each element located, or null if no elements are found.
733
+ * Retrieves and compiles attributes of elements resolved by a Playwright locator per nesting step.
734
+ * This method provides insights into the elements targeted by the locator, aiding in debugging and verification.
806
735
  */
807
736
  evaluateAndGetAttributes = async (pwLocator) => {
808
737
  return await pwLocator.evaluateAll(
809
738
  (objects) => objects.map((el) => {
810
- const elementAttributes = el.hasAttributes() ? Object.fromEntries(
811
- Array.from(el.attributes).map(({ name, value }) => [name, value])
812
- ) : {};
739
+ const elementAttributes = el.hasAttributes() ? Object.fromEntries(Array.from(el.attributes).map(({ name, value }) => [name, value])) : {};
813
740
  return { tagName: el.tagName, attributes: elementAttributes };
814
741
  })
815
742
  );
@@ -819,18 +746,17 @@ Attempted to Add Schema: ${JSON.stringify(
819
746
  // src/helpers/sessionStorage.actions.ts
820
747
  var import_test3 = require("@playwright/test");
821
748
  var SessionStorage = class {
749
+ // Initializes the class with a Playwright Page object and a name for the Page Object Class.
822
750
  constructor(page, pocName) {
823
751
  this.page = page;
824
752
  this.pocName = pocName;
825
753
  }
754
+ // Defines an object to hold states to be set in session storage, allowing any value type.
826
755
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
827
756
  queuedStates = {};
757
+ // Indicates if the session storage manipulation has been initiated.
828
758
  isInitiated = false;
829
- /**
830
- * Writes states to the sessionStorage. Private utility function.
831
- *
832
- * @param states An object representing the states (key/value pairs) to set.
833
- */
759
+ /** Writes states to session storage. Accepts an object with key-value pairs representing the states. */
834
760
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
835
761
  async writeToSessionStorage(states) {
836
762
  await this.page.evaluate((storage) => {
@@ -839,11 +765,7 @@ var SessionStorage = class {
839
765
  }
840
766
  }, states);
841
767
  }
842
- /**
843
- * Reads all states from the sessionStorage. Private utility function.
844
- *
845
- * @returns An object containing all states from the sessionStorage.
846
- */
768
+ /** Reads all states from session storage and returns them as an object. */
847
769
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
848
770
  async readFromSessionStorage() {
849
771
  return await this.page.evaluate(() => {
@@ -863,13 +785,12 @@ var SessionStorage = class {
863
785
  });
864
786
  }
865
787
  /**
866
- * Sets the specified states in the sessionStorage.
867
- *
868
- * @param states An object representing the states (key/value pairs) to set in sessionStorage.
869
- * @param reload If true, reloads the page after setting the sessionStorage data.
788
+ * Sets the specified states in session storage.
789
+ * Optionally reloads the page after setting the data to ensure the new session storage state is active.
870
790
  *
871
- * Usage:
872
- * await set({ user: 'John Doe', token: 'abc123' }, true);
791
+ * Parameters:
792
+ * states: Object representing the states to set in session storage.
793
+ * reload: Boolean indicating whether to reload the page after setting the session storage data.
873
794
  */
874
795
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
875
796
  async set(states, reload) {
@@ -882,16 +803,14 @@ var SessionStorage = class {
882
803
  }
883
804
  /**
884
805
  * Queues states to be set in the sessionStorage before the next navigation occurs.
885
- * This handles multiple scenarios:
806
+ * Handles different scenarios based on whether the context exists or multiple calls are made.
886
807
  *
887
808
  * 1. No Context, Single Call: Queues and sets states upon the next navigation.
888
809
  * 2. No Context, Multiple Calls: Merges states from multiple calls and sets them upon the next navigation.
889
810
  * 3. With Context: Directly sets states in sessionStorage if the context already exists.
890
811
  *
891
- * @param states An object representing the states (key/value pairs) to set.
892
- *
893
- * Usage:
894
- * await setOnNextNavigation({ key: 'value' });
812
+ * Parameters:
813
+ * states: Object representing the states to queue for setting in session storage.
895
814
  */
896
815
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
897
816
  async setOnNextNavigation(states) {
@@ -922,14 +841,14 @@ var SessionStorage = class {
922
841
  }
923
842
  }
924
843
  /**
925
- * Fetches all or selected states from sessionStorage.
844
+ * Fetches states from session storage.
845
+ * If specific keys are provided, fetches only those states; otherwise, fetches all states.
926
846
  *
927
- * @param keys Optional array of keys to fetch from sessionStorage.
928
- * @returns An object containing the fetched states.
847
+ * Parameters:
848
+ * keys: Optional array of keys to specify which states to fetch from session storage.
929
849
  *
930
- * Usage:
931
- * 1. To fetch all states: await get();
932
- * 2. To fetch selected states: await get(['key1', 'key2']);
850
+ * Returns:
851
+ * Object containing the fetched states.
933
852
  */
934
853
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
935
854
  async get(keys) {
@@ -950,9 +869,6 @@ var SessionStorage = class {
950
869
  }
951
870
  /**
952
871
  * Clears all states in sessionStorage.
953
- *
954
- * Usage:
955
- * await clear();
956
872
  */
957
873
  async clear() {
958
874
  await import_test3.test.step(`${this.pocName}: clear SessionStorage`, async () => {
@@ -964,11 +880,32 @@ var SessionStorage = class {
964
880
  // src/utils/selectorEngines.ts
965
881
  function createCypressIdEngine() {
966
882
  return {
883
+ /**
884
+ * Uses the document's querySelector method to find the first element with a specific 'data-cy' attribute.
885
+ * Constructs a selector string for the 'data-cy' attribute and searches the DOM for the first match.
886
+ *
887
+ * Parameters:
888
+ * - document: An object that mimics the global document, having a querySelector method.
889
+ * - selector: A string representing the value of the 'data-cy' attribute to search for.
890
+ *
891
+ * Returns the first HTML element matching the 'data-cy' attribute, or null if no match is found.
892
+ */
967
893
  query(document, selector) {
968
894
  const attr = `[data-cy="${selector}"]`;
969
895
  const el = document.querySelector(attr);
970
896
  return el;
971
897
  },
898
+ /**
899
+ * Uses the document's querySelectorAll method to find all elements with a specific 'data-cy' attribute.
900
+ * Constructs a selector string for the 'data-cy' attribute and retrieves all matching elements in the DOM.
901
+ * Converts the NodeList from querySelectorAll into an array for easier handling and manipulation.
902
+ *
903
+ * Parameters:
904
+ * - document: An object that mimics the global document, having a querySelectorAll method.
905
+ * - selector: A string representing the value of the 'data-cy' attribute to search for.
906
+ *
907
+ * Returns an array of HTML elements matching the 'data-cy' attribute. Returns an empty array if no matches are found.
908
+ */
972
909
  queryAll(document, selector) {
973
910
  const attr = `[data-cy="${selector}"]`;
974
911
  const els = Array.from(document.querySelectorAll(attr));
@@ -1007,10 +944,7 @@ var BasePage2 = class {
1007
944
  this.fullUrl = `${this.baseUrl}${this.urlPath}`;
1008
945
  this.pocName = pocName;
1009
946
  this.log = pwrl.getNewChildLogger(pocName);
1010
- this.locators = new GetLocatorBase(
1011
- this,
1012
- this.log.getNewChildLogger("GetLocator")
1013
- );
947
+ this.locators = new GetLocatorBase(this, this.log.getNewChildLogger("GetLocator"));
1014
948
  this.initLocatorSchemas();
1015
949
  this.sessionStorage = new SessionStorage(this.page, this.pocName);
1016
950
  if (!selectorRegistered) {
@@ -1019,63 +953,84 @@ var BasePage2 = class {
1019
953
  }
1020
954
  }
1021
955
  /**
1022
- * Asynchronously retrieves a nested locator based on the provided LocatorSchemaPath and optional indices per nested locator.
1023
- * Useful for interacting with elements in a structured or hierarchical manner, reducing the number of possible elements we can resolve to.
1024
- *
1025
- * The update and updates methods cannot be used with this method. Use the getLocatorSchema method instead.
1026
- *
1027
- * @param LocatorSchemaPathType locatorSchemaPath - The unique path identifier for the locator schema.
1028
- * @param indices - An optional object to specify the nth occurrence of each nested locator.
1029
- * @returns Promise<Locator> - A promise that resolves to the nested locator.
956
+ * getNestedLocator(indices?: { [key: number]: number | null } | null)
957
+ * - Asynchronously retrieves a nested locator based on the LocatorSchemaPath provided by getLocatorSchema("...")
958
+ * - Can be chained after the update and updates methods, getNestedLocator will end the chain.
959
+ * - The optional parameter of the method takes an object with 0-based indices "{0: 0, 3: 1}" for one or more locators
960
+ * to be nested given by sub-paths (indices correspond to last "word" of a sub-path).
961
+ * - Returns a promise that resolves to the nested locator.
1030
962
  */
1031
963
  getNestedLocator = async (locatorSchemaPath, indices) => {
1032
- return await this.getLocatorSchema(locatorSchemaPath).getNestedLocator(
1033
- indices
1034
- );
964
+ return await this.getLocatorSchema(locatorSchemaPath).getNestedLocator(indices);
1035
965
  };
1036
966
  /**
1037
- * Asynchronously retrieves the locator based on the current LocatorSchemaPath. This method does not perform nesting.
1038
- * Useful for directly interacting with an element based on its LocatorSchema.
1039
- *
1040
- * The update and updates methods cannot be used with this method. Use the getLocatorSchema method instead.
1041
- *
1042
- * @param LocatorSchemaPathType locatorSchemaPath - The unique path identifier for the locator schema.
1043
- * @returns Promise<Locator> - A promise that resolves to the nested locator.
967
+ * getLocator()
968
+ * - Asynchronously retrieves a locator based on the current LocatorSchema. This method does not perform nesting,
969
+ * and will return the locator for which the full LocatorSchemaPath resolves to, provided by getLocatorSchema("...")
970
+ * - Can be chained after the update and updates methods, getLocator will end the chain.
971
+ * - Returns a promise that resolves to the locator.
1044
972
  */
1045
973
  getLocator = async (locatorSchemaPath) => {
1046
974
  return await this.getLocatorSchema(locatorSchemaPath).getLocator();
1047
975
  };
1048
976
  /**
1049
- * The "getLocatorSchema" method is used to retrieve a deep copy of a locator schema defined in the GetLocatorBase class.
1050
- * It enriches the returned schema with additional methods to handle updates and retrieval of deep copy locators.
977
+ * The "getLocatorSchema" method is used to retrieve an updatable deep copy of a LocatorSchema defined in the
978
+ * GetLocatorBase class. It enriches the returned schema with additional methods to handle updates and retrieval of
979
+ * deep copy locators.
1051
980
  *
1052
- * @param LocatorSchemaPathType locatorSchemaPath - The unique path identifier for the locator schema.
1053
- * @returns LocatorSchemaWithMethods - A deep copy of the locator schema with additional methods.
981
+ * Providing a precise and powerful solution for interacting with elements through locators in a structured
982
+ * or hierarchical manner:
983
+ * - Effortless validation of any element's expected location in the DOM.
984
+ * - Improved readability and maintainability of tests.
985
+ * - Improved readability and maintainability of Page Object Classes (POCs), through the use of a single source of
986
+ * truth and flat locator (LocatorSchema) structure.
987
+ * - Improved rebustness of tests in the face of DOM changes.
988
+ * - Simpler debugging and maintenance as a result of limitin/scoping the number of possible resolvable elements
989
+ * - Highly veratile usage
1054
990
  *
1055
- * Methods added to the returned LocatorSchemaWithMethods object:
991
+ * getLocatorSchema adds the following chainable methods to the returned LocatorSchemaWithMethods object:
1056
992
  *
1057
- * - update(updates: Partial<UpdatableLocatorSchemaProperties>):
1058
- * Allows updating properties of the locator schema.
1059
- * This method is used for modifying the current schema without affecting the original schema.
1060
- * @param updates - An object with properties to be updated in the locator schema, omits the locatorSchemaPath parameter.
1061
- * @returns LocatorSchemaWithMethods - The updated locator schema object.
993
+ * update(updates: Partial< UpdatableLocatorSchemaProperties >)
994
+ * - Allows updating the properties of the LocatorSchema which the full LocatorSchemaPath resolves to.
995
+ * - This method is used for modifying the current schema without affecting the original schema.
996
+ * - Takes a "LocatorSchema" object which omits the locatorSchemaPath parameter as input, the parameters provided
997
+ * will overwrite the corresponding property in the current schema.
998
+ * - Returns the updated deep copy of the "LocatorSchema" with methods.
999
+ * - Can be chained with the update and updates methods, and the getLocator or getNestedLocator method.
1062
1000
  *
1063
- * - updates(indexedUpdates: { [index: number]: Partial<UpdatableLocatorSchemaProperties> | null }):
1064
- * Similar to update, but allows for indexed updates of any locator to be nested within the path.
1065
- * This method is used for modifying the current schema without affecting the original schema
1066
- * @param indexedUpdates - An object where keys represent index levels, and values are the updates at each level.
1067
- * @returns LocatorSchemaWithMethods - The locator schema object with indexed updates.
1001
+ * updates(indexedUpdates: { [index: number]: Partial< UpdatableLocatorSchemaProperties > | null }):
1002
+ * - Similar to update, but allows updating any locator in the nested chain (all sub-paths of the LocatorSchemaPath).
1003
+ * - This method can modify the current deep copy of each LocatorSchema that each sub-path resolves to without
1004
+ * affecting the original schemas
1005
+ * - Takes an object where keys represent the index of the last "word" of a sub-path, where the value per key is a
1006
+ * "LocatorSchema" object which omits the locatorSchemaPath parameter as input, the parameters provided will overwrite
1007
+ * the corresponding property in the given schema.
1008
+ * - Returns the updated deep copy of the LocatorSchema object with methods and its own updated deep copies for all
1009
+ * LocatorSchema each sub-path resolved to.
1010
+ * - Can be chained with the update and updates methods, and the getLocator or getNestedLocator method.
1068
1011
  *
1069
- * - getNestedLocator(indices?: { [key: number]: number | null }):
1070
- * Asynchronously retrieves a nested locator based on the current schema and optional indices per nested locator.
1071
- * Useful for interacting with elements in a structured or hierarchical manner.
1072
- * @param indices - An optional object to specify the nth occurrence of each nested locator.
1073
- * @returns Promise<Locator> - A promise that resolves to the nested locator.
1012
+ * getNestedLocator(indices?: { [key: number]: number | null } | null)
1013
+ * - Asynchronously retrieves a nested locator based on the LocatorSchemaPath provided by getLocatorSchema("...")
1014
+ * - Can be chained after the update and updates methods, getNestedLocator will end the chain.
1015
+ * - The optional parameter of the method takes an object with 0-based indices "{0: 0, 3: 1}" for one or more locators
1016
+ * to be nested given by sub-paths (indices correspond to last "word" of a sub-path).
1017
+ * - Returns a promise that resolves to the nested locator.
1074
1018
  *
1075
- * - getLocator():
1076
- * Asynchronously retrieves the locator based on the current schema. This method does not consider nesting.
1077
- * Useful for directly interacting with an element based on its schema.
1078
- * @returns Promise<Locator> - A promise that resolves to the locator.
1019
+ * getLocator()
1020
+ * - Asynchronously retrieves a locator based on the current LocatorSchema. This method does not perform nesting,
1021
+ * and will return the locator for which the full LocatorSchemaPath resolves to, provided by getLocatorSchema("...")
1022
+ * - Can be chained after the update and updates methods, getLocator will end the chain.
1023
+ * - Returns a promise that resolves to the locator.
1024
+ *
1025
+ * Note: Calling getLocator() and getNestedLocator() on the same LocatorSchemaPath will return a Locator for the same
1026
+ * element, but the Locator returned by getNestedLocator() will be a locator resolving to said same element through
1027
+ * a chain of locators. While the Locator returned by getLocator() will be a single locator which resolves directly
1028
+ * to said element. Thus getLocator() is rarely used, while getNestedLocator() is used extensively.
1029
+ *
1030
+ * That said, for certain use cases, getLocator() can be useful, and you could use it to manually chain locators
1031
+ * yourself if some edge case required it. Though, it would be likely be more prudent to expand your LocatorSchemaPath
1032
+ * type and initLocatorSchemas() method to include the additional locators you need for the given POC, and then use
1033
+ * getNestedLocator() instead.
1079
1034
  */
1080
1035
  getLocatorSchema(locatorSchemaPath) {
1081
1036
  return this.locators.getLocatorSchema(locatorSchemaPath);
@@ -1090,11 +1045,7 @@ var test3 = import_test5.test.extend({
1090
1045
  const contextName = "TestCase";
1091
1046
  const sharedLogEntry = [];
1092
1047
  const sharedLogLevel = testInfo.retry === 0 ? { current: "warn", initial: "warn" } : { current: "debug", initial: "debug" };
1093
- const log = new PlaywrightReportLogger(
1094
- sharedLogLevel,
1095
- sharedLogEntry,
1096
- contextName
1097
- );
1048
+ const log = new PlaywrightReportLogger(sharedLogLevel, sharedLogEntry, contextName);
1098
1049
  await use(log);
1099
1050
  log.attachLogsToTest(testInfo);
1100
1051
  }
@@ -1115,10 +1066,10 @@ var BaseApi = class {
1115
1066
  };
1116
1067
  // Annotate the CommonJS export names for ESM import in node:
1117
1068
  0 && (module.exports = {
1069
+ BaseApi,
1070
+ BasePage,
1118
1071
  GetByMethod,
1119
- POMWright,
1120
- POMWrightApi,
1121
- POMWrightGetLocatorBase,
1122
- POMWrightLogger,
1123
- POMWrightTestFixture
1072
+ GetLocatorBase,
1073
+ PlaywrightReportLogger,
1074
+ test
1124
1075
  });