ftmocks-utils 1.4.5 → 1.4.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ftmocks-utils",
3
- "version": "1.4.5",
3
+ "version": "1.4.6",
4
4
  "description": "Util functions for FtMocks",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -8,18 +8,21 @@ const getLocator = async (page, event) => {
8
8
  if (event && event.target && typeof page !== "undefined" && page.locator) {
9
9
  let locator = null;
10
10
  while (!locator) {
11
- const selector = event.target.startsWith("/")
12
- ? `xpath=${event.target}`
13
- : event.target;
11
+ const selector =
12
+ event.target.startsWith("/") || event.target.startsWith("(/")
13
+ ? `xpath=${event.target}`
14
+ : event.target;
14
15
  try {
15
16
  const count = await page.locator(selector).count();
16
17
  if (count === 1) {
17
18
  locator = selector;
18
19
  } else {
19
20
  for (let i = 0; i < event.selectors.length; i++) {
20
- const selector = event.selectors[i].value.startsWith("/")
21
- ? `xpath=${event.selectors[i].value}`
22
- : event.selectors[i].value;
21
+ const selector =
22
+ event.selectors[i].value.startsWith("/") ||
23
+ event.selectors[i].value.startsWith("(/")
24
+ ? `xpath=${event.selectors[i].value}`
25
+ : event.selectors[i].value;
23
26
  const count = await page.locator(selector).count();
24
27
  if (count === 1) {
25
28
  locator = selector;
@@ -37,6 +40,51 @@ const getLocator = async (page, event) => {
37
40
  return event.target;
38
41
  };
39
42
 
43
+ const healSelector = async (page, event, selector, position) => {
44
+ console.log("➡ Healing selector for event", event);
45
+ let locator = selector;
46
+ if (locator.startsWith("/") || locator.startsWith("(/")) {
47
+ locator = `xpath=${locator}`;
48
+ try {
49
+ // INSERT_YOUR_CODE
50
+ // Get all elements that match the given locator
51
+ const elements = await page.locator(locator).elementHandles();
52
+ if (elements.length > 1) {
53
+ let index = 0;
54
+ for (let i = 0; i < elements.length; i++) {
55
+ const element = elements[i];
56
+ const currPosition = await element.boundingBox();
57
+ if (
58
+ currPosition.x >= position.x &&
59
+ currPosition.y >= position.y &&
60
+ currPosition.x + currPosition.width <=
61
+ position.x + position.width &&
62
+ currPosition.y + currPosition.height <= position.y + position.height
63
+ ) {
64
+ index = i;
65
+ break;
66
+ }
67
+ }
68
+ return {
69
+ value: `(${selector})[${index + 1}]`,
70
+ count: 1,
71
+ };
72
+ } else {
73
+ return {
74
+ value: selector,
75
+ count: elements.length,
76
+ };
77
+ }
78
+ } catch (error) {
79
+ console.error("Error getting locator", error, selector);
80
+ }
81
+ }
82
+ return {
83
+ value: selector,
84
+ count: 1,
85
+ };
86
+ };
87
+
40
88
  const getSelectorPosition = async (page, selector) => {
41
89
  const element = await page.locator(selector).elementHandle();
42
90
  const position = await element.boundingBox();
@@ -50,6 +98,7 @@ const runEvent = async ({
50
98
  delay = 0,
51
99
  screenshots = false,
52
100
  screenshotsDir = null,
101
+ healSelectors = false,
53
102
  }) => {
54
103
  try {
55
104
  console.log("➡ Running event", event);
@@ -67,6 +116,38 @@ const runEvent = async ({
67
116
  fullPage: false,
68
117
  });
69
118
  }
119
+ if (healSelectors) {
120
+ const locator = await getLocator(page, event);
121
+ const position = await getSelectorPosition(page, locator);
122
+ const healedTarget = await healSelector(
123
+ page,
124
+ event,
125
+ event.target,
126
+ position
127
+ );
128
+ event.target = healedTarget.value;
129
+ const selectors = [];
130
+ const laterToBeAdded = [];
131
+ for (let i = 0; i < event.selectors.length; i++) {
132
+ const healedSelector = await healSelector(
133
+ page,
134
+ event,
135
+ event.selectors[i].value,
136
+ position
137
+ );
138
+ event.selectors[i].value = healedSelector.value;
139
+ if (healedSelector.count !== 1) {
140
+ laterToBeAdded.push(event.selectors[i]);
141
+ } else {
142
+ selectors.push(event.selectors[i]);
143
+ }
144
+ }
145
+ selectors.push(...laterToBeAdded);
146
+ if (healedTarget.count !== 1) {
147
+ event.target = selectors[0].value;
148
+ }
149
+ event.selectors = selectors;
150
+ }
70
151
  };
71
152
  switch (event.type) {
72
153
  case "url":
@@ -163,9 +244,17 @@ const runEvents = async ({
163
244
  delay = 1000,
164
245
  screenshots = false,
165
246
  screenshotsDir = null,
247
+ healSelectors = false,
166
248
  }) => {
167
249
  for (const event of events) {
168
- await runEvent({ page, event, delay, screenshots, screenshotsDir });
250
+ await runEvent({
251
+ page,
252
+ event,
253
+ delay,
254
+ screenshots,
255
+ screenshotsDir,
256
+ healSelectors,
257
+ });
169
258
  }
170
259
  };
171
260
 
@@ -504,11 +593,30 @@ const runEventsForScreenshots = async (page, ftmocksConifg, testName) => {
504
593
  await page.close();
505
594
  };
506
595
 
596
+ const runEventsForHealingSelectors = async (page, ftmocksConifg, testName) => {
597
+ const eventsFile = path.join(
598
+ getMockDir(ftmocksConifg),
599
+ `test_${nameToFolder(testName)}`,
600
+ `_events.json`
601
+ );
602
+ const events = JSON.parse(fs.readFileSync(eventsFile, "utf8"));
603
+ await runEvents({
604
+ page,
605
+ events,
606
+ delay: ftmocksConifg.delay || 1000,
607
+ healSelectors: true,
608
+ });
609
+ fs.writeFileSync(eventsFile, JSON.stringify(events, null, 2));
610
+ await page.waitForTimeout(1000);
611
+ await page.close();
612
+ };
613
+
507
614
  module.exports = {
508
615
  runEvents,
509
616
  runEventsForTest,
510
617
  runEventsInPresentationMode,
511
618
  runEventsInTrainingMode,
512
619
  runEventsForScreenshots,
620
+ runEventsForHealingSelectors,
513
621
  runEvent,
514
622
  };
package/src/index.js CHANGED
@@ -28,6 +28,7 @@ const {
28
28
  runEventsInPresentationMode,
29
29
  runEventsInTrainingMode,
30
30
  runEventsForScreenshots,
31
+ runEventsForHealingSelectors,
31
32
  } = require("./event-run-utils");
32
33
 
33
34
  // Export functions as a module
@@ -56,4 +57,5 @@ module.exports = {
56
57
  runEventsInPresentationMode,
57
58
  runEventsInTrainingMode,
58
59
  runEventsForScreenshots,
60
+ runEventsForHealingSelectors,
59
61
  };