@mablhq/mabl-cli 1.12.33 → 1.13.19

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.
@@ -162,6 +162,18 @@ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
162
162
  PERFORMANCE OF THIS SOFTWARE.
163
163
  ***************************************************************************** */
164
164
 
165
+ /*! axe v4.3.3
166
+ * Copyright (c) 2021 Deque Systems, Inc.
167
+ *
168
+ * Your use of this Source Code Form is subject to the terms of the Mozilla Public
169
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
170
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
171
+ *
172
+ * This entire copyright notice must appear in every copy of this file you
173
+ * distribute or in any file that contains substantial portions of this source
174
+ * code.
175
+ */
176
+
165
177
  /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
166
178
 
167
179
  /**
package/index.d.ts CHANGED
@@ -26,6 +26,9 @@ declare module '@mablhq/mabl-cli' {
26
26
  Playwright = 'playwright',
27
27
  Puppeteer = 'puppeteer',
28
28
  }
29
+ export interface HttpHeadersType {
30
+ [key: string]: string;
31
+ }
29
32
  export interface TestRunConfig {
30
33
  authToken?: string;
31
34
  basicAuthCredentialsId?: string;
@@ -33,6 +36,10 @@ declare module '@mablhq/mabl-cli' {
33
36
  branchChangesOnly?: boolean;
34
37
  credentialsId?: string;
35
38
  environmentId?: string;
39
+ /**
40
+ * An object containing additional HTTP headers to be sent with every request.
41
+ */
42
+ extraHttpHeaders?: HttpHeadersType;
36
43
  filterHttpRequests: boolean;
37
44
  fromPlanId?: string;
38
45
  headless?: boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpResponseAssertion = exports.SendHttpRequestStep = void 0;
3
+ exports.VariableSource = exports.HttpResponseAssertion = exports.SendHttpRequestStep = void 0;
4
4
  const MablStep_1 = require("../MablStep");
5
5
  const AssertStep_1 = require("./AssertStep");
6
6
  const ConditionDescriptor_1 = require("../types/ConditionDescriptor");
@@ -55,3 +55,11 @@ var HttpResponseAssertion;
55
55
  }
56
56
  HttpResponseAssertion.toComparisonDescriptor = toComparisonDescriptor;
57
57
  })(HttpResponseAssertion = exports.HttpResponseAssertion || (exports.HttpResponseAssertion = {}));
58
+ var VariableSource;
59
+ (function (VariableSource) {
60
+ VariableSource["Body"] = "body";
61
+ VariableSource["Header"] = "header";
62
+ VariableSource["Json"] = "json";
63
+ VariableSource["Response"] = "response";
64
+ VariableSource["Status"] = "status";
65
+ })(VariableSource = exports.VariableSource || (exports.VariableSource = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mablhq/mabl-cli",
3
- "version": "1.12.33",
3
+ "version": "1.13.19",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "The official mabl command line interface tool",
6
6
  "main": "index.js",
@@ -25,7 +25,8 @@
25
25
  "postinstall": "node ./util/postInstallMessage.js"
26
26
  },
27
27
  "dependencies": {
28
- "@playwright/test": "1.15.2",
28
+ "@playwright/test": "1.17.1",
29
+ "playwright-core": "1.17.1",
29
30
  "@types/fs-extra": "^8.1.0",
30
31
  "@types/serve-handler": "^6.1.0",
31
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,29 +182,25 @@ 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 {
181
- zIndex: 0,
182
189
  elementsInFront: 0,
183
190
  dismissedStatus: false,
184
- domCovering: [],
185
- actionableElements: [],
186
191
  };
187
192
  }
188
193
  const clickCandidates = async function (candidates, leftEdgeClick) {
189
194
  for (const candidate of candidates) {
190
195
  fireClickEvent(candidate, leftEdgeClick);
191
196
  await sleep(DISMISSAL_WAIT_TIME_MS);
192
- if (elementsInFront(element, elementBoundingBox.x, elementBoundingBox.y)
193
- .length < elementsInFrontCount) {
197
+ if (elementsAtCoordinate(element, elementBoundingBox.x, elementBoundingBox.y).length < elementsInFrontCount) {
194
198
  return true;
195
199
  }
196
200
  }
197
201
  return false;
198
202
  };
199
- let allElements = getAllElementsAbove(higherElements);
203
+ let allElements = getAllElementsAbove(element, higherElements);
200
204
  const candidatesByZIndex = developCloseCandidates(allElements);
201
205
  for (const candidate of candidatesByZIndex) {
202
206
  let matched = await clickCandidates(candidate.domCovering, true);
@@ -204,12 +208,14 @@ async function detectAndDismissPopupCandidates(element) {
204
208
  matched = await clickCandidates(candidate.actionableElements, false);
205
209
  }
206
210
  if (matched) {
207
- candidate.dismissedStatus = true;
208
- return candidate;
211
+ return {
212
+ dismissedStatus: true,
213
+ elementsInFront: 0,
214
+ };
209
215
  }
210
216
  }
211
- higherElements = elementsInFront(element, elementBoundingBox.x, elementBoundingBox.y);
212
- allElements = getAllElementsAbove(higherElements);
217
+ higherElements = elementsAtCoordinate(element, elementBoundingBox.x, elementBoundingBox.y);
218
+ allElements = getAllElementsAbove(element, higherElements);
213
219
  const candidates = developCloseCandidates(allElements);
214
220
  const result = candidates.length
215
221
  ? candidates[0]
@@ -222,21 +228,21 @@ async function detectAndDismissPopupCandidates(element) {
222
228
  };
223
229
  result.elementsInFront = higherElements.length;
224
230
  result.dismissedStatus = false;
225
- return result;
231
+ return {
232
+ dismissedStatus: result.dismissedStatus,
233
+ elementsInFront: result.elementsInFront,
234
+ };
226
235
  }
227
236
  catch (error) {
228
237
  return {
229
- zIndex: 0,
230
238
  elementsInFront: 0,
231
239
  dismissedStatus: false,
232
- domCovering: [],
233
- actionableElements: [],
234
- errorInDetection: error.toString(),
240
+ error: error.toString(),
235
241
  };
236
242
  }
237
243
  }
238
244
  exports.detectAndDismissPopupCandidates = detectAndDismissPopupCandidates;
239
245
  function elementsInFrontCount(element) {
240
- return elementsInFront(element).length;
246
+ return elementsAtCoordinate(element).length;
241
247
  }
242
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: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){let e=[t];return Array.from(t.children).forEach(t=>{e=e.concat(u(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 s(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{zIndex:0,elementsInFront:0,dismissedStatus:!1,domCovering:[],actionableElements:[]};const r=async function(n,r){for(const i of n)if(s(i,r),await d(750),l(t,e.x,e.y).length<o)return!0;return!1};let i=m(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 t.dismissedStatus=!0,t}n=l(t,e.x,e.y),i=m(n);const a=c(i),f=a.length?a[0]:{zIndex:0,elementsInFront:0,dismissedStatus:!1,domCovering:[],actionableElements:[]};return f.elementsInFront=n.length,f.dismissedStatus=!1,f}catch(t){return{zIndex:0,elementsInFront:0,dismissedStatus:!1,domCovering:[],actionableElements:[],errorInDetection: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}}]);
@@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
19
19
  return result;
20
20
  };
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.maybeAddPopupLogic = exports.checkActionabilityAt = exports.checkActionabilityAtWithRetries = void 0;
22
+ exports.maybeAddPopupLogic = exports.attemptPopupDismissal = exports.checkActionabilityAt = exports.checkActionabilityAtWithRetries = exports.checkPopupDismissalOnAction = void 0;
23
23
  const fs = __importStar(require("fs"));
24
24
  const resourceUtil_1 = require("./resourceUtil");
25
25
  const messaging_1 = require("../core/messaging/messaging");
@@ -29,17 +29,47 @@ 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;
35
+ async function checkPopupDismissalOnAction(elementHandle, action, executionContext, recheckOnFail = true) {
36
+ try {
37
+ await action();
38
+ }
39
+ catch (error) {
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);
46
+ if (recheckOnFail) {
47
+ return checkPopupDismissalOnAction(elementHandle, action, executionContext, false);
48
+ }
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
+ }
55
+ }
56
+ }
57
+ }
58
+ exports.checkPopupDismissalOnAction = checkPopupDismissalOnAction;
34
59
  async function checkActionabilityAtWithRetries(elementHandle, executionContext, failIfClickablePointWasNotFound = true) {
35
60
  var _a, _b, _c, _d;
36
61
  let actionabilityResult;
37
62
  try {
38
- actionabilityResult = await ExecutorUtils_1.runWithRetries(() => checkActionabilityAt(elementHandle, executionContext), 10, ['Element not at point', 'Element not clickable at point'], executionContext);
63
+ actionabilityResult = await ExecutorUtils_1.runWithRetries(() => checkActionabilityAt(elementHandle, executionContext), 10, [
64
+ 'Element not at point',
65
+ 'Element not clickable at point',
66
+ NO_CLICKABLE_POINT_ERROR,
67
+ ], executionContext);
39
68
  }
40
69
  catch (error) {
41
- if (failIfClickablePointWasNotFound && error === NO_CLICKABLE_POINT_ERROR) {
42
- throw new Error('Unable to find a clickable point for the element');
70
+ if (failIfClickablePointWasNotFound &&
71
+ error.message === NO_CLICKABLE_POINT_ERROR) {
72
+ throw new Error(NO_CLICKABLE_POINT_ERROR);
43
73
  }
44
74
  logUtils_1.logWebUIAndCliOutput(`Found element may not be actionable`, loggingProvider_1.LogLevel.Warn, executionContext, {
45
75
  executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
@@ -69,7 +99,14 @@ async function checkActionabilityAt(elementHandle, executionContext, recheckOnFa
69
99
  if (result !== 'done') {
70
100
  if (typeof result === 'object' && 'actionabilityDescription' in result) {
71
101
  logUtils_1.logInternal(`${result.actionabilityDescription} intercepts pointer events. Trying to auto-dismiss popups.`);
72
- 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);
73
110
  if (recheckOnFail) {
74
111
  return checkActionabilityAt(elementHandle, executionContext, false);
75
112
  }
@@ -80,13 +117,16 @@ async function checkActionabilityAt(elementHandle, executionContext, recheckOnFa
80
117
  return { result, clickablePoint: point };
81
118
  }
82
119
  exports.checkActionabilityAt = checkActionabilityAt;
83
- async function attemptPopupDismissal(element) {
120
+ async function attemptPopupDismissal(element, executionContext) {
84
121
  const frame = await element.frame();
85
122
  if (frame === undefined) {
86
123
  return false;
87
124
  }
88
125
  await maybeAddPopupLogic(element);
89
- const { dismissedStatus, elementsInFront } = await element.evaluate((element) => window.popupDismissal.detectAndDismissPopupCandidates(element));
126
+ const { dismissedStatus, elementsInFront, error } = await element.evaluate((element) => window.popupDismissal.detectAndDismissPopupCandidates(element));
127
+ if (error) {
128
+ logUtils_1.logInternal(`Error while trying to dismiss popups: ${error}`);
129
+ }
90
130
  if (!dismissedStatus) {
91
131
  if (elementsInFront) {
92
132
  logUtils_1.logInternal('Failed to auto dismiss and there are still elements in front. Sending escape key to body.');
@@ -105,8 +145,12 @@ async function attemptPopupDismissal(element) {
105
145
  return false;
106
146
  }
107
147
  }
148
+ logUtils_1.logWebUIAndCliOutput(`A popup was detected and dismissed`, loggingProvider_1.LogLevel.Info, executionContext, {
149
+ executionPhase: messaging_1.ExecutionPhase.DURING_ACTION,
150
+ });
108
151
  return true;
109
152
  }
153
+ exports.attemptPopupDismissal = attemptPopupDismissal;
110
154
  async function maybeAddPopupLogic(element) {
111
155
  const hasPopupDismissalLogic = await isPopupDismissalInTarget(element);
112
156
  if (!hasPopupDismissalLogic) {
@@ -132,3 +176,7 @@ function isActionabilityLogicInTarget(element) {
132
176
  function isPopupDismissalInTarget(element) {
133
177
  return element.evaluate(() => !!window.popupDismissal);
134
178
  }
179
+ function isElementWithPopup(element) {
180
+ return element.evaluate((element) => element.getAttribute('aria-expanded') === 'true' &&
181
+ element.getAttribute('aria-haspopup') === 'true');
182
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimeoutError = exports.promiseWithTimeout = void 0;
4
+ const loggingProvider_1 = require("../providers/logging/loggingProvider");
5
+ async function promiseWithTimeout(promise, timeoutMillis, description) {
6
+ const startTimeMillis = new Date().getTime();
7
+ const { timer, cancelTimer } = startTimer(timeoutMillis, description);
8
+ try {
9
+ const result = await Promise.race([timer, promise]);
10
+ if (loggingProvider_1.logger.isDebugEnabled()) {
11
+ loggingProvider_1.logger.debug(`"${description}" completed in ${new Date().getTime() - startTimeMillis}ms`);
12
+ }
13
+ return result;
14
+ }
15
+ catch (error) {
16
+ if (error instanceof TimeoutError) {
17
+ loggingProvider_1.logger.warn(error.message);
18
+ }
19
+ throw error;
20
+ }
21
+ finally {
22
+ cancelTimer();
23
+ }
24
+ }
25
+ exports.promiseWithTimeout = promiseWithTimeout;
26
+ class TimeoutError extends Error {
27
+ constructor(timeoutMillis, description) {
28
+ super(`[mabl promise timeout] "${description}" timed out after ${timeoutMillis}ms`);
29
+ this.timeoutMillis = timeoutMillis;
30
+ this.description = description;
31
+ Object.setPrototypeOf(this, TimeoutError.prototype);
32
+ }
33
+ }
34
+ exports.TimeoutError = TimeoutError;
35
+ const startTimer = (timeoutMillis, description) => {
36
+ let timeout;
37
+ const promise = new Promise((_resolve, reject) => {
38
+ timeout = global.setTimeout(() => reject(new TimeoutError(timeoutMillis, description)), timeoutMillis);
39
+ timeout.unref();
40
+ });
41
+ return {
42
+ timer: promise,
43
+ cancelTimer: () => global.clearTimeout(timeout),
44
+ };
45
+ };
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) {
@@ -49,6 +49,10 @@ function findNodeModulesDirectory() {
49
49
  if (fs.existsSync(packedAsMabltronDependency)) {
50
50
  return packedAsMabltronDependency;
51
51
  }
52
+ const packedAsExecutionEngineDependency = path.normalize(path.resolve(`${__dirname}/../../mabl-cli-internal-unpacked/node_modules/`));
53
+ if (fs.existsSync(packedAsExecutionEngineDependency)) {
54
+ return packedAsExecutionEngineDependency;
55
+ }
52
56
  const packedPath = path.normalize(path.resolve(`${__dirname}/../../node_modules`));
53
57
  return packedPath;
54
58
  }