@mablhq/mabl-cli 1.13.14 → 1.13.21

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": "@mablhq/mabl-cli",
3
- "version": "1.13.14",
3
+ "version": "1.13.21",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "The official mabl command line interface tool",
6
6
  "main": "index.js",
@@ -25,8 +25,8 @@
25
25
  "postinstall": "node ./util/postInstallMessage.js"
26
26
  },
27
27
  "dependencies": {
28
- "@playwright/test": "1.17.1",
29
- "playwright-core": "1.17.1",
28
+ "@playwright/test": "1.17.2",
29
+ "playwright-core": "1.17.2",
30
30
  "@types/fs-extra": "^8.1.0",
31
31
  "@types/serve-handler": "^6.1.0",
32
32
  "@types/tmp": "^0.2.0",
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.elementsInFrontCount = exports.detectAndDismissPopupCandidates = exports.getAllElementsAbove = exports.elementsByHigherZIndex = void 0;
3
+ exports.elementsInFrontCount = exports.detectAndDismissPopupCandidates = exports.getAllElementsAbove = exports.elementsAtCoordinate = exports.elementsByHigherZIndex = void 0;
4
4
  const DISMISSAL_WAIT_TIME_MS = 750;
5
5
  const ZINDEX_AUTO = 'auto';
6
6
  const MINIMUM_POPUP_DISPLAY_COVERAGE_PX = 0.95;
@@ -40,9 +40,9 @@ function getEffectiveZIndex(element) {
40
40
  const isRootElement = (element) => element === undefined || element.tagName.toLowerCase() === 'html';
41
41
  let current = element;
42
42
  while (!isRootElement(current)) {
43
- const zIndex = window.getComputedStyle(element).zIndex;
43
+ const zIndex = window.getComputedStyle(current).zIndex;
44
44
  if (zIndex && zIndex !== ZINDEX_AUTO) {
45
- return zIndex;
45
+ return parseInt(zIndex, 10);
46
46
  }
47
47
  current = (current === null || current === void 0 ? void 0 : current.parentElement) ? current.parentElement : undefined;
48
48
  }
@@ -135,13 +135,14 @@ function fireClickEvent(targetElement, leftEdgeClick) {
135
135
  });
136
136
  targetElement.dispatchEvent(mouseEvent);
137
137
  }
138
- function elementsInFront(element, pointX, pointY) {
138
+ function elementsAtCoordinate(element, pointX, pointY) {
139
139
  const x = pointX !== undefined ? pointX : getBoundingClientRectWithXY(element).x;
140
140
  const y = pointY !== undefined ? pointY : getBoundingClientRectWithXY(element).y;
141
141
  const elementsAtPoint = document.elementsFromPoint(x, y);
142
142
  const targetIndex = elementsAtPoint.findIndex((iterElement) => iterElement === element);
143
143
  return targetIndex ? elementsAtPoint.slice(0, targetIndex) : [];
144
144
  }
145
+ exports.elementsAtCoordinate = elementsAtCoordinate;
145
146
  function sleep(time) {
146
147
  return new Promise((resolve) => setTimeout(resolve, time));
147
148
  }
@@ -158,8 +159,15 @@ function getBoundingClientRectWithXY(element) {
158
159
  width: Math.floor(rect.right) - Math.ceil(rect.left),
159
160
  };
160
161
  }
161
- function getAllElementsAbove(elements) {
162
- const zIndexAboveTarget = getEffectiveZIndex(elements[elements.length - 1]);
162
+ function getAllElementsAbove(targetElement, elements) {
163
+ if (elements.length === 0) {
164
+ return [];
165
+ }
166
+ const targetZindex = getEffectiveZIndex(targetElement);
167
+ const zIndexAboveTarget = Math.min(...elements === null || elements === void 0 ? void 0 : elements.map((el) => getEffectiveZIndex(el)));
168
+ if (zIndexAboveTarget <= targetZindex) {
169
+ return [];
170
+ }
163
171
  const higherElementsByZIndex = elementsByHigherZIndex(zIndexAboveTarget);
164
172
  const allElementsByZIndex = Array.from(higherElementsByZIndex).map(([item, higherElements]) => {
165
173
  const allElements = higherElements
@@ -174,7 +182,7 @@ exports.getAllElementsAbove = getAllElementsAbove;
174
182
  async function detectAndDismissPopupCandidates(element) {
175
183
  const elementBoundingBox = getBoundingClientRectWithXY(element);
176
184
  try {
177
- let higherElements = elementsInFront(element, elementBoundingBox.x, elementBoundingBox.y);
185
+ let higherElements = elementsAtCoordinate(element, elementBoundingBox.x, elementBoundingBox.y);
178
186
  const elementsInFrontCount = higherElements.length;
179
187
  if (elementsInFrontCount === 0) {
180
188
  return {
@@ -186,14 +194,13 @@ async function detectAndDismissPopupCandidates(element) {
186
194
  for (const candidate of candidates) {
187
195
  fireClickEvent(candidate, leftEdgeClick);
188
196
  await sleep(DISMISSAL_WAIT_TIME_MS);
189
- if (elementsInFront(element, elementBoundingBox.x, elementBoundingBox.y)
190
- .length < elementsInFrontCount) {
197
+ if (elementsAtCoordinate(element, elementBoundingBox.x, elementBoundingBox.y).length < elementsInFrontCount) {
191
198
  return true;
192
199
  }
193
200
  }
194
201
  return false;
195
202
  };
196
- let allElements = getAllElementsAbove(higherElements);
203
+ let allElements = getAllElementsAbove(element, higherElements);
197
204
  const candidatesByZIndex = developCloseCandidates(allElements);
198
205
  for (const candidate of candidatesByZIndex) {
199
206
  let matched = await clickCandidates(candidate.domCovering, true);
@@ -207,8 +214,8 @@ async function detectAndDismissPopupCandidates(element) {
207
214
  };
208
215
  }
209
216
  }
210
- higherElements = elementsInFront(element, elementBoundingBox.x, elementBoundingBox.y);
211
- allElements = getAllElementsAbove(higherElements);
217
+ higherElements = elementsAtCoordinate(element, elementBoundingBox.x, elementBoundingBox.y);
218
+ allElements = getAllElementsAbove(element, higherElements);
212
219
  const candidates = developCloseCandidates(allElements);
213
220
  const result = candidates.length
214
221
  ? candidates[0]
@@ -236,6 +243,6 @@ async function detectAndDismissPopupCandidates(element) {
236
243
  }
237
244
  exports.detectAndDismissPopupCandidates = detectAndDismissPopupCandidates;
238
245
  function elementsInFrontCount(element) {
239
- return elementsInFront(element).length;
246
+ return elementsAtCoordinate(element).length;
240
247
  }
241
248
  exports.elementsInFrontCount = elementsInFrontCount;
@@ -1 +1 @@
1
- window.popupDismissal=function(t){var e={};function n(o){if(e[o])return e[o].exports;var r=e[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(o,r,function(e){return t[e]}.bind(null,r));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e,n){"use strict";n.r(e),n.d(e,"elementsByHigherZIndex",(function(){return i})),n.d(e,"getAllElementsAbove",(function(){return m})),n.d(e,"detectAndDismissPopupCandidates",(function(){return h})),n.d(e,"elementsInFrontCount",(function(){return g}));const o=["close","dismiss","exit","not at this time","no thanks","no, thanks","i, agree","i agree"],r=[{attributeName:"className",matchFunction:s},{attributeName:"name",matchFunction:s},{attributeName:"id",matchFunction:s},{attributeName:"href",matchFunction:s},{attributeName:"innerText",matchFunction:function(t,e){const n=new RegExp(`\\b${e}\\b`);return!!t.toLowerCase().match(n)}}];function i(t){return Array.from(document.querySelectorAll("body *")).reduce((e,n)=>{const o=parseFloat(window.getComputedStyle(n).zIndex);return!Number.isNaN(o)&&o>=t&&(e.has(o)?e.get(o).push(n):e.set(o,[n])),e},new Map)}function u(t){let e=[t];return Array.from(t.children).forEach(t=>{e=e.concat(u(t))}),e}function s(t,e){return t.toLowerCase().includes(e)}function a(t){const e=[];return t.forEach(t=>{const n=[],i=[];t.elements.forEach(t=>{var e,u;(null===(e=t)||void 0===e?void 0:e.offsetParent)&&(["BUTTON","A","DIV"].includes(null===(u=t.tagName)||void 0===u?void 0:u.toUpperCase())&&function(t){let e=0;return r.forEach(n=>{o.forEach(o=>{t.getAttribute(n.attributeName)&&n.matchFunction(t.getAttribute(n.attributeName),o)&&(e+=1)})}),e}(t)&&!i.includes(t)?i.push(t):function(t){if(t.getBoundingClientRect){const e=t.getBoundingClientRect(),n=e.width/window.innerWidth,o=e.height/window.innerHeight;return n>.95&&o>.95}return!1}(t)&&n.push(t))}),e.push({zIndex:t.zIndex,actionableElements:i,domCovering:n,dismissedStatus:!1,elementsInFront:0})}),e}function c(t,e){const n=t.getBoundingClientRect(),o=n.height/2,r=e?1:n.width/2,i=new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window,detail:0,screenX:n.left+r,screenY:n.top+o,clientX:t.clientLeft+r,clientY:t.clientTop+o,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:void 0});t.dispatchEvent(i)}function l(t,e,n){const o=void 0!==e?e:f(t).x,r=void 0!==n?n:f(t).y,i=document.elementsFromPoint(o,r),u=i.findIndex(e=>e===t);return u?i.slice(0,u):[]}function d(t){return new Promise(e=>setTimeout(e,t))}function f(t){const e=t.getBoundingClientRect();return{x:Math.floor(e.x),y:Math.floor(e.y),top:Math.floor(e.top),bottom:Math.ceil(e.bottom),left:Math.floor(e.left),right:Math.ceil(e.right),height:Math.floor(e.bottom)-Math.ceil(e.top),width:Math.floor(e.right)-Math.ceil(e.left)}}function m(t){const e=i(function(t){const e=t=>void 0===t||"html"===t.tagName.toLowerCase();let n=t;for(;!e(n);){const e=window.getComputedStyle(t).zIndex;if(e&&"auto"!==e)return e;n=(null==n?void 0:n.parentElement)?n.parentElement:void 0}return 0}(t[t.length-1])),n=Array.from(e).map(([t,e])=>({zIndex:t,elements:e.flatMap(u).reverse()}));return n.sort((t,e)=>e.zIndex-t.zIndex),n}async function h(t){const e=f(t);try{let n=l(t,e.x,e.y);const o=n.length;if(0===o)return{elementsInFront:0,dismissedStatus:!1};const r=async function(n,r){for(const i of n)if(c(i,r),await d(750),l(t,e.x,e.y).length<o)return!0;return!1};let i=m(n);const u=a(i);for(const t of u){let e=await r(t.domCovering,!0);if(e||(e=await r(t.actionableElements,!1)),e)return{dismissedStatus:!0,elementsInFront:0}}n=l(t,e.x,e.y),i=m(n);const s=a(i),f=s.length?s[0]:{zIndex:0,elementsInFront:0,dismissedStatus:!1,domCovering:[],actionableElements:[]};return f.elementsInFront=n.length,f.dismissedStatus=!1,{dismissedStatus:f.dismissedStatus,elementsInFront:f.elementsInFront}}catch(t){return{elementsInFront:0,dismissedStatus:!1,error:t.toString()}}}function g(t){return l(t).length}}]);
1
+ window.popupDismissal=function(t){var e={};function n(o){if(e[o])return e[o].exports;var r=e[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(o,r,function(e){return t[e]}.bind(null,r));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e,n){"use strict";n.r(e),n.d(e,"elementsByHigherZIndex",(function(){return i})),n.d(e,"elementsAtCoordinate",(function(){return d})),n.d(e,"getAllElementsAbove",(function(){return h})),n.d(e,"detectAndDismissPopupCandidates",(function(){return g})),n.d(e,"elementsInFrontCount",(function(){return p}));const o=["close","dismiss","exit","not at this time","no thanks","no, thanks","i, agree","i agree"],r=[{attributeName:"className",matchFunction:a},{attributeName:"name",matchFunction:a},{attributeName:"id",matchFunction:a},{attributeName:"href",matchFunction:a},{attributeName:"innerText",matchFunction:function(t,e){const n=new RegExp(`\\b${e}\\b`);return!!t.toLowerCase().match(n)}}];function i(t){return Array.from(document.querySelectorAll("body *")).reduce((e,n)=>{const o=parseFloat(window.getComputedStyle(n).zIndex);return!Number.isNaN(o)&&o>=t&&(e.has(o)?e.get(o).push(n):e.set(o,[n])),e},new Map)}function u(t){const e=t=>void 0===t||"html"===t.tagName.toLowerCase();let n=t;for(;!e(n);){const t=window.getComputedStyle(n).zIndex;if(t&&"auto"!==t)return parseInt(t,10);n=(null==n?void 0:n.parentElement)?n.parentElement:void 0}return 0}function s(t){let e=[t];return Array.from(t.children).forEach(t=>{e=e.concat(s(t))}),e}function a(t,e){return t.toLowerCase().includes(e)}function c(t){const e=[];return t.forEach(t=>{const n=[],i=[];t.elements.forEach(t=>{var e,u;(null===(e=t)||void 0===e?void 0:e.offsetParent)&&(["BUTTON","A","DIV"].includes(null===(u=t.tagName)||void 0===u?void 0:u.toUpperCase())&&function(t){let e=0;return r.forEach(n=>{o.forEach(o=>{t.getAttribute(n.attributeName)&&n.matchFunction(t.getAttribute(n.attributeName),o)&&(e+=1)})}),e}(t)&&!i.includes(t)?i.push(t):function(t){if(t.getBoundingClientRect){const e=t.getBoundingClientRect(),n=e.width/window.innerWidth,o=e.height/window.innerHeight;return n>.95&&o>.95}return!1}(t)&&n.push(t))}),e.push({zIndex:t.zIndex,actionableElements:i,domCovering:n,dismissedStatus:!1,elementsInFront:0})}),e}function l(t,e){const n=t.getBoundingClientRect(),o=n.height/2,r=e?1:n.width/2,i=new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window,detail:0,screenX:n.left+r,screenY:n.top+o,clientX:t.clientLeft+r,clientY:t.clientTop+o,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:void 0});t.dispatchEvent(i)}function d(t,e,n){const o=void 0!==e?e:m(t).x,r=void 0!==n?n:m(t).y,i=document.elementsFromPoint(o,r),u=i.findIndex(e=>e===t);return u?i.slice(0,u):[]}function f(t){return new Promise(e=>setTimeout(e,t))}function m(t){const e=t.getBoundingClientRect();return{x:Math.floor(e.x),y:Math.floor(e.y),top:Math.floor(e.top),bottom:Math.ceil(e.bottom),left:Math.floor(e.left),right:Math.ceil(e.right),height:Math.floor(e.bottom)-Math.ceil(e.top),width:Math.floor(e.right)-Math.ceil(e.left)}}function h(t,e){if(0===e.length)return[];const n=u(t),o=Math.min(...null==e?void 0:e.map(t=>u(t)));if(o<=n)return[];const r=i(o),a=Array.from(r).map(([t,e])=>({zIndex:t,elements:e.flatMap(s).reverse()}));return a.sort((t,e)=>e.zIndex-t.zIndex),a}async function g(t){const e=m(t);try{let n=d(t,e.x,e.y);const o=n.length;if(0===o)return{elementsInFront:0,dismissedStatus:!1};const r=async function(n,r){for(const i of n)if(l(i,r),await f(750),d(t,e.x,e.y).length<o)return!0;return!1};let i=h(t,n);const u=c(i);for(const t of u){let e=await r(t.domCovering,!0);if(e||(e=await r(t.actionableElements,!1)),e)return{dismissedStatus:!0,elementsInFront:0}}n=d(t,e.x,e.y),i=h(t,n);const s=c(i),a=s.length?s[0]:{zIndex:0,elementsInFront:0,dismissedStatus:!1,domCovering:[],actionableElements:[]};return a.elementsInFront=n.length,a.dismissedStatus=!1,{dismissedStatus:a.dismissedStatus,elementsInFront:a.elementsInFront}}catch(t){return{elementsInFront:0,dismissedStatus:!1,error:t.toString()}}}function p(t){return d(t).length}}]);
@@ -29,6 +29,7 @@ const loggingProvider_1 = require("../providers/logging/loggingProvider");
29
29
  const ACTIONABILITY_CHECK_SCRIPT_LOCATION = resourceUtil_1.findResource('actionabilityCheck.js');
30
30
  const EMBEDDED_POPUP_SCRIPT_LOCATION = resourceUtil_1.findResource('popupDismissal.js');
31
31
  const NO_CLICKABLE_POINT_ERROR = 'Unable to find a clickable point for the element';
32
+ const POPUP_ERROR_MESSAGE_HINT = 'intercepts pointer events';
32
33
  let embeddedPopupScript;
33
34
  let embeddedActionabilityLogic;
34
35
  async function checkPopupDismissalOnAction(elementHandle, action, executionContext, recheckOnFail = true) {
@@ -36,15 +37,21 @@ async function checkPopupDismissalOnAction(elementHandle, action, executionConte
36
37
  await action();
37
38
  }
38
39
  catch (error) {
39
- if (error.message.includes('intercepts pointer events')) {
40
- await attemptPopupDismissal(elementHandle);
40
+ if (error.message.includes(POPUP_ERROR_MESSAGE_HINT)) {
41
+ const hasPopup = await isElementWithPopup(elementHandle);
42
+ if (hasPopup) {
43
+ return;
44
+ }
45
+ const dismissalResult = await attemptPopupDismissal(elementHandle, executionContext);
41
46
  if (recheckOnFail) {
42
47
  return checkPopupDismissalOnAction(elementHandle, action, executionContext, false);
43
48
  }
44
- logUtils_1.logWebUIAndCliOutput(`Found element may not be actionable`, loggingProvider_1.LogLevel.Warn, executionContext, {
45
- executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
46
- });
47
- logUtils_1.logInternal(`Found element might not be actionable. ${error.toString()}`);
49
+ if (!dismissalResult) {
50
+ logUtils_1.logWebUIAndCliOutput(`Found element may not be actionable`, loggingProvider_1.LogLevel.Warn, executionContext, {
51
+ executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
52
+ });
53
+ logUtils_1.logInternal(`Found element might not be actionable. ${error.toString()}`);
54
+ }
48
55
  }
49
56
  }
50
57
  }
@@ -92,7 +99,14 @@ async function checkActionabilityAt(elementHandle, executionContext, recheckOnFa
92
99
  if (result !== 'done') {
93
100
  if (typeof result === 'object' && 'actionabilityDescription' in result) {
94
101
  logUtils_1.logInternal(`${result.actionabilityDescription} intercepts pointer events. Trying to auto-dismiss popups.`);
95
- await attemptPopupDismissal(elementHandle);
102
+ const hasPopup = await isElementWithPopup(elementHandle);
103
+ if (hasPopup) {
104
+ return {
105
+ result: 'done',
106
+ clickablePoint: point,
107
+ };
108
+ }
109
+ await attemptPopupDismissal(elementHandle, executionContext);
96
110
  if (recheckOnFail) {
97
111
  return checkActionabilityAt(elementHandle, executionContext, false);
98
112
  }
@@ -103,7 +117,7 @@ async function checkActionabilityAt(elementHandle, executionContext, recheckOnFa
103
117
  return { result, clickablePoint: point };
104
118
  }
105
119
  exports.checkActionabilityAt = checkActionabilityAt;
106
- async function attemptPopupDismissal(element) {
120
+ async function attemptPopupDismissal(element, executionContext) {
107
121
  const frame = await element.frame();
108
122
  if (frame === undefined) {
109
123
  return false;
@@ -131,6 +145,9 @@ async function attemptPopupDismissal(element) {
131
145
  return false;
132
146
  }
133
147
  }
148
+ logUtils_1.logWebUIAndCliOutput(`A popup was detected and dismissed`, loggingProvider_1.LogLevel.Info, executionContext, {
149
+ executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
150
+ });
134
151
  return true;
135
152
  }
136
153
  exports.attemptPopupDismissal = attemptPopupDismissal;
@@ -159,3 +176,7 @@ function isActionabilityLogicInTarget(element) {
159
176
  function isPopupDismissalInTarget(element) {
160
177
  return element.evaluate(() => !!window.popupDismissal);
161
178
  }
179
+ function isElementWithPopup(element) {
180
+ return element.evaluate((element) => element.getAttribute('aria-expanded') === 'true' &&
181
+ element.getAttribute('aria-haspopup') === 'true');
182
+ }
package/util/logUtils.js CHANGED
@@ -8,8 +8,8 @@ const mablscriptFind_1 = require("../mablscriptFind");
8
8
  const loggingProvider_1 = require("../providers/logging/loggingProvider");
9
9
  const moment_1 = __importDefault(require("moment"));
10
10
  const constants_1 = require("../commands/constants");
11
- function logInternal(logLine) {
12
- loggingProvider_1.logger.debug(logLine);
11
+ function logInternal(logLine, ...meta) {
12
+ loggingProvider_1.logger.debug(logLine, meta);
13
13
  }
14
14
  exports.logInternal = logInternal;
15
15
  function logCliOutput(logLevel, logLine) {