@checksum-ai/runtime 1.1.31 → 1.1.32

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.
@@ -1,9 +1,15 @@
1
- import { ChecksumConfig, IChecksumPage } from "@checksum-ai/runtime";
1
+ import {
2
+ ChecksumConfig,
3
+ IChecksumPage,
4
+ ChecksumConfigEnvironment,
5
+ EnvironmentUser
6
+ } from "@checksum-ai/runtime";
2
7
  import { expect, request } from "@playwright/test";
3
8
 
4
9
  export default async function login(
5
10
  page: IChecksumPage,
6
- config: ChecksumConfig
11
+ config: ChecksumConfig,
12
+ environmentInfo: { environment: ChecksumConfigEnvironment; user: EnvironmentUser }
7
13
  ) {
8
14
  /**
9
15
  * This code provides examples of how to write functions for different login scenarios.
package/checksumlib.js CHANGED
@@ -9653,6 +9653,9 @@
9653
9653
  }
9654
9654
  getElementWindowPlaywright(node2) {
9655
9655
  const elementWindow = node2.ownerDocument.defaultView;
9656
+ if (!elementWindow) {
9657
+ return window.playwright;
9658
+ }
9656
9659
  if (elementWindow !== window && !elementWindow.playwright) {
9657
9660
  elementWindow.playwright = window.playwright;
9658
9661
  }
@@ -9664,13 +9667,6 @@
9664
9667
  node2
9665
9668
  ).generateSelectorAndLocator(node2);
9666
9669
  } catch (error) {
9667
- console.log(
9668
- "get selector and locator error",
9669
- node2.nodeType,
9670
- node2,
9671
- "\n",
9672
- error
9673
- );
9674
9670
  if (retriesLeft > 0) {
9675
9671
  await (0, import_await_sleep.default)(500);
9676
9672
  return this.safeGetSelectorAndLocator(node2, {
@@ -32646,6 +32642,7 @@
32646
32642
  this.MAX_TESTING_SELECTORS = 50;
32647
32643
  this.MAX_SINGLE_ELEMENT_SELECTORS = 5;
32648
32644
  this.MAX_PROCESSING_TIME = 15e3;
32645
+ this.MAX_MULTICANDIDATE_PROCESSING = 5;
32649
32646
  }
32650
32647
  static {
32651
32648
  __name(this, "PlaywrightCustomLocatorGenerator");
@@ -32714,7 +32711,7 @@
32714
32711
  selector,
32715
32712
  locator: this.getSelectorLocator(selector),
32716
32713
  elements: elements.filter(
32717
- (el) => isInstanceOfHTMLElement(el)
32714
+ (el) => isInstanceOfHTMLElement(el) || el.constructor.name === this.targetElement.constructor.name
32718
32715
  )
32719
32716
  });
32720
32717
  }
@@ -32767,12 +32764,9 @@
32767
32764
  try {
32768
32765
  for (const candidate of locatorsCandidates) {
32769
32766
  this.checkTimeout();
32770
- if (candidate.elements.length === 1) {
32771
- filteredCandidates.push(candidate);
32772
- continue;
32773
- }
32774
- await awaitSleep(100);
32775
- filteredCandidates.push(...this.reduceMultiCandidates(candidate));
32767
+ filteredCandidates.push(
32768
+ ...candidate.elements.length === 1 ? [candidate] : await this.reduceMultiCandidates(candidate)
32769
+ );
32776
32770
  }
32777
32771
  } catch (error) {
32778
32772
  if (error instanceof TimeoutError) {
@@ -32806,6 +32800,13 @@
32806
32800
  locator
32807
32801
  });
32808
32802
  }
32803
+ filteredCandidates = filteredCandidates.concat(
32804
+ await this.addOptionalParentSelector(
32805
+ useTextContent,
32806
+ addCSSSelectorGenerator,
32807
+ expandCSSKeyElements
32808
+ )
32809
+ );
32809
32810
  return filteredCandidates.map(({ selector, locator }) => ({
32810
32811
  selector,
32811
32812
  locator
@@ -32886,6 +32887,26 @@
32886
32887
  console.error("Error getting CSS selector", error);
32887
32888
  }
32888
32889
  }
32890
+ /**
32891
+ * If playwright selector for element points at a different element - generate selectors for that element as well
32892
+ * i.e - playwright can point at a parent button if element is a child of it
32893
+ */
32894
+ addOptionalParentSelector(useTextContent, addCSSSelectorGenerator, expandCSSKeyElements) {
32895
+ const playwright = getElementWindowPlaywright(this.targetElement);
32896
+ const playwrightTargetElement = playwright.locator(
32897
+ playwright.selector(this.targetElement)
32898
+ ).element;
32899
+ if (playwrightTargetElement !== this.targetElement && playwrightTargetElement?.contains(this.targetElement)) {
32900
+ return this.generate(playwrightTargetElement, [], {
32901
+ isPartOfListItem: false,
32902
+ isForContextElement: false,
32903
+ useTextContent,
32904
+ addCSSSelectorGenerator,
32905
+ expandCSSKeyElements
32906
+ });
32907
+ }
32908
+ return [];
32909
+ }
32889
32910
  /**
32890
32911
  * Add CSS key features to the element chain, based on attributes that are not covered by playwright selectors
32891
32912
  *
@@ -33086,22 +33107,23 @@
33086
33107
  *
33087
33108
  * @returns array of new candidates that return only one element
33088
33109
  */
33089
- reduceMultiCandidates(candidate) {
33110
+ async reduceMultiCandidates(candidate) {
33111
+ await awaitSleep(100);
33090
33112
  const { elements } = candidate;
33091
33113
  const parts = candidate.selector.split(" >> ");
33092
33114
  const newCandidates = [];
33115
+ const locatorBase = this.getLocatorBase(this.targetElement);
33093
33116
  const addCandidateWithSelector = /* @__PURE__ */ __name((selector) => {
33094
33117
  try {
33095
33118
  newCandidates.push({
33096
33119
  selector,
33097
33120
  locator: this.getSelectorLocator(selector),
33098
- elements: this.getLocatorBase(this.targetElement).locator(selector, candidate.options).elements.filter(
33099
- (el) => isInstanceOfHTMLElement(el)
33100
- ),
33101
33121
  options: candidate.options
33102
33122
  });
33123
+ return newCandidates.length >= this.MAX_MULTICANDIDATE_PROCESSING;
33103
33124
  } catch (error) {
33104
33125
  console.error(error);
33126
+ return false;
33105
33127
  }
33106
33128
  }, "addCandidateWithSelector");
33107
33129
  const addCSSFilterToLocator = /* @__PURE__ */ __name((filter) => candidate.selector + // if we used css selector with tag name - concatentate it with the filter
@@ -33111,6 +33133,12 @@
33111
33133
  this.targetElement.tagName.toLowerCase() + filter
33112
33134
  )}`
33113
33135
  )), "addCSSFilterToLocator");
33136
+ const addIfSingularAndCheckLimit = /* @__PURE__ */ __name((selector) => {
33137
+ if (locatorBase.locator(selector, candidate.options).elements.length === 1) {
33138
+ return addCandidateWithSelector(selector);
33139
+ }
33140
+ return false;
33141
+ }, "addIfSingularAndCheckLimit");
33114
33142
  if (elements.length < 5) {
33115
33143
  const index2 = elements.indexOf(this.targetElement);
33116
33144
  if (index2 !== -1) {
@@ -33123,41 +33151,38 @@
33123
33151
  )) {
33124
33152
  const index2 = Array.from(parent.children).indexOf(this.targetElement);
33125
33153
  if (index2 !== -1) {
33126
- addCandidateWithSelector(
33127
- addCSSFilterToLocator(`:nth-child(${index2 + 1})`)
33128
- );
33154
+ const selector = addCSSFilterToLocator(`:nth-child(${index2 + 1})`);
33155
+ if (addIfSingularAndCheckLimit(selector)) {
33156
+ addCandidateWithSelector(selector);
33157
+ }
33129
33158
  }
33130
33159
  }
33131
- Array.from(this.targetElement.classList).forEach((className) => {
33160
+ for (const className of Array.from(this.targetElement.classList).filter(
33161
+ (cls) => !CLASS_IGNORE_LIST.includes(cls)
33162
+ )) {
33132
33163
  const selector = addCSSFilterToLocator(`.${escapeSelector(className)}`);
33133
33164
  try {
33134
- if (this.getLocatorBase(this.targetElement).locator(
33135
- selector,
33136
- candidate.options
33137
- ).elements.length === 1) {
33138
- addCandidateWithSelector(selector);
33165
+ if (addIfSingularAndCheckLimit(selector)) {
33166
+ return newCandidates;
33139
33167
  }
33140
33168
  } catch (error) {
33141
33169
  console.error(error);
33142
33170
  }
33143
- });
33144
- Array.from(this.targetElement.attributes).filter(
33145
- (attr) => !["class", "style", "id", "href", "src"].includes(attr.name)
33146
- ).forEach((attr) => {
33171
+ }
33172
+ for (const attr of Array.from(this.targetElement.attributes).filter(
33173
+ (attr2) => !COVERED_ATTRIBUTES.includes(attr2.name)
33174
+ )) {
33147
33175
  const selector = addCSSFilterToLocator(
33148
33176
  `[${attr.name}` + (attr.value ? `="${attr.value}"]` : "]")
33149
33177
  );
33150
33178
  try {
33151
- if (this.getLocatorBase(this.targetElement).locator(
33152
- selector,
33153
- candidate.options
33154
- ).elements.length === 1) {
33155
- addCandidateWithSelector(selector);
33179
+ if (addIfSingularAndCheckLimit(selector)) {
33180
+ return newCandidates;
33156
33181
  }
33157
33182
  } catch (error) {
33158
33183
  console.error(error);
33159
33184
  }
33160
- });
33185
+ }
33161
33186
  return newCandidates;
33162
33187
  }
33163
33188
  getAllLocators(element, cssKeyElements, options = {}) {
@@ -33256,7 +33281,7 @@
33256
33281
  }
33257
33282
  return options.returnLocator ? `getByRole('${role}', { ${props.join(", ")} })` : `internal:role=${role}${props.map(([n2, v2]) => `[${n2}=${v2}]`).join("")}`;
33258
33283
  } catch (error) {
33259
- console.error("Error getting role locator", error);
33284
+ console.error("Error getting role locator", error.message);
33260
33285
  }
33261
33286
  }
33262
33287
  getByTextLocator(element, options = {}) {
@@ -33395,7 +33420,14 @@
33395
33420
  __name(isInstanceOfHTMLElement, "isInstanceOfHTMLElement");
33396
33421
 
33397
33422
  // src/lib/test-generator/selectors/compound-selector.ts
33398
- var CLASS_IGNORE_LIST = [":hover", ":focus", ":active"];
33423
+ var CLASS_IGNORE_LIST = [
33424
+ ":hover",
33425
+ ":focus",
33426
+ ":active",
33427
+ "\\:hover",
33428
+ "\\:focus",
33429
+ "\\:active"
33430
+ ];
33399
33431
  var CompoundSelector = class {
33400
33432
  constructor(htmlReducer) {
33401
33433
  this.htmlReducer = htmlReducer;
@@ -33818,7 +33850,7 @@
33818
33850
  return path.join(" ").trim();
33819
33851
  }
33820
33852
  getSelectorPart(element, { useId = false, useClasses = true, useTag = true }) {
33821
- if (useId && element.id) {
33853
+ if (useId && element.id && element.id.match(/^\D/)) {
33822
33854
  return `#${element.id}`;
33823
33855
  }
33824
33856
  let selector = useTag ? element.tagName.toLowerCase() : "";