UNPKG

testplane

Version:

Tests framework based on mocha and wdio

147 lines 6.46 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.waitForSelectorsToSettle = void 0; const node_timers_1 = require("node:timers"); const debug_1 = __importDefault(require("debug")); const debug = (0, debug_1.default)("testplane:screenshots:selectors-settle"); const SELECTORS_SETTLE_BROWSER_TIMEOUT_MS = 3000; const SELECTORS_SETTLE_FALLBACK_INTERVAL_MS = 50; const SELECTORS_SETTLE_FALLBACK_ATTEMPTS = 5; async function waitForSelectorsToSettle(browser, selectors, options = {}) { try { const settleResult = await waitForSelectorsToSettleInBrowser(browser, selectors, options); if (settleResult.success) { return; } debug("Browser-side waitForSelectorsToSettle cannot run, using Node-side polling"); } catch (err) { const scriptTimeoutError = err; const scriptTimeoutErrorText = err && typeof err === "object" ? [scriptTimeoutError.name, scriptTimeoutError.message, scriptTimeoutError.error].join(" ") : ""; if (!/script timeout/i.test(scriptTimeoutErrorText)) { throw err; } debug("Browser-side waitForSelectorsToSettle hit script timeout, using Node-side polling"); } await waitForSelectorsToSettleInNode(browser, selectors); } exports.waitForSelectorsToSettle = waitForSelectorsToSettle; async function waitForSelectorsToSettleInBrowser(browser, selectors, options) { if (options.needsCompatLib) { return { success: false }; } const originalScriptTimeout = typeof browser.getTimeouts === "function" ? (await browser.getTimeouts())?.script : undefined; const shouldRestoreScriptTimeout = typeof originalScriptTimeout === "number"; let executionError = null; let result; if (shouldRestoreScriptTimeout) { await browser.setTimeout({ script: SELECTORS_SETTLE_BROWSER_TIMEOUT_MS }); } else { debug("Browser does not report script timeout, running browser-side polling without timeout override"); } try { result = await browser.execute(async (selectors) => { let setTimeoutSource = ""; try { setTimeoutSource = typeof setTimeout === "function" ? Function.prototype.toString.call(setTimeout) : ""; } catch { return { success: false }; } if (!setTimeoutSource.includes("[native code]")) { return { success: false }; } const PAGE_SETTLE_MAX_WAIT_MS = 50; const PAGE_SETTLE_MAX_ITERATIONS = 500; const PAGE_SETTLE_MATCHES_THRESHOLD = 3; const startedAt = performance.now(); let iterations = 0; let matches = 0; let lastBoundingClientRects = selectors.map(selector => { const element = document.querySelector(selector); return element ? element.getBoundingClientRect() : null; }); while (performance.now() - startedAt < PAGE_SETTLE_MAX_WAIT_MS && iterations < PAGE_SETTLE_MAX_ITERATIONS && matches < PAGE_SETTLE_MATCHES_THRESHOLD) { const currentBoundingClientRects = selectors.map(selector => { const element = document.querySelector(selector); return element ? element.getBoundingClientRect() : null; }); if (currentBoundingClientRects.every((rect, index) => { const lastRect = lastBoundingClientRects[index]; if (!rect || !lastRect) { return rect === lastRect; } return rect.top === lastRect.top && rect.height === lastRect.height; })) { matches++; } else { matches = 0; } lastBoundingClientRects = currentBoundingClientRects; iterations++; await new Promise(resolve => setTimeout(resolve, 5)); } return { success: true }; }, selectors); } catch (err) { executionError = err; } if (shouldRestoreScriptTimeout) { try { await browser.setTimeout({ script: originalScriptTimeout }); } catch (restoreError) { if (executionError) { debug("Failed to restore original script timeout after selectors settle error: %s", restoreError instanceof Error ? restoreError.message : String(restoreError)); } else { throw restoreError; } } } if (executionError) { throw executionError; } return result ?? { success: true }; } async function waitForSelectorsToSettleInNode(browser, selectors) { const PAGE_SETTLE_MATCHES_THRESHOLD = 3; let matches = 0; let lastBoundingClientRects; for (let attempt = 0; attempt <= SELECTORS_SETTLE_FALLBACK_ATTEMPTS && matches < PAGE_SETTLE_MATCHES_THRESHOLD; attempt++) { if (lastBoundingClientRects) { await new Promise(resolve => { const timeoutId = (0, node_timers_1.setTimeout)(resolve, SELECTORS_SETTLE_FALLBACK_INTERVAL_MS); timeoutId.unref(); }); } const previousBoundingClientRects = lastBoundingClientRects; const currentBoundingClientRects = await browser.execute(function (selectors) { return selectors.map(function (selector) { const element = document.querySelector(selector); const rect = element ? element.getBoundingClientRect() : null; return rect ? { top: rect.top, height: rect.height } : null; }); }, selectors); if (previousBoundingClientRects) { matches = currentBoundingClientRects.every((rect, index) => { const previousRect = previousBoundingClientRects[index]; return rect?.top === previousRect?.top && rect?.height === previousRect?.height; }) ? matches + 1 : 0; } lastBoundingClientRects = currentBoundingClientRects; } } //# sourceMappingURL=wait-for-selectors-to-settle.js.map