e2ed
Version:
E2E testing framework over Playwright
113 lines (112 loc) • 5.95 kB
JavaScript
;
/* eslint-disable no-labels */
Object.defineProperty(exports, "__esModule", { value: true });
exports.waitForInterfaceStabilization = void 0;
const createClientFunction_1 = require("../../createClientFunction");
const config_1 = require("../../utils/config");
const getDurationWithUnits_1 = require("../../utils/getDurationWithUnits");
const log_1 = require("../../utils/log");
/**
* This function in a universal way waits for the end of the movements and redrawing
* of the page interface. The function takes on the duration of an interval during
* which the interface must not change to be considered stable.
* Then, every 250ms, a snapshot of the state of the interface is taken.
* If the state does not change within the specified period, the function successfully
* resolves the returned promise.
* The state of the interface is the size of the window, scrolling in the entire window,
* as well as the classes, sizes and positions of some DOM elements on the page.
* Elements from different points on the page are taken as checked elements.
*/
const clientWaitForInterfaceStabilization = (0, createClientFunction_1.createClientFunction)((stabilizationInterval, timeout) => {
const isPointInsideRectangle = (x, y, { left, top, width, height }) => x >= left && x <= left + width && y >= top && y <= top + height;
const keyOfIgnoredElements = Symbol.for('e2ed:PageElementsIgnoredOnInterfaceStabilization');
const global = globalThis;
const ignoredElementsSelectors = global[keyOfIgnoredElements] ?? [];
const CHECK_INTERVAL_IN_MS = 250;
const COUNT_OF_POINTED_NODES = 8;
const startTimeInMs = Date.now();
const getInterfaceState = () => {
const ignoredElements = [];
for (const selector of ignoredElementsSelectors) {
for (const element of document.querySelectorAll(selector)) {
if (!ignoredElements.includes(element)) {
ignoredElements.push(element);
}
}
}
const ignoredRectangles = ignoredElements.map((element) => element.getBoundingClientRect());
const { innerWidth, innerHeight } = window;
const elements = [document.documentElement];
const deltaX = innerWidth / (COUNT_OF_POINTED_NODES + 1);
const deltaY = innerHeight / (COUNT_OF_POINTED_NODES + 1);
for (let xIndex = 1; xIndex <= COUNT_OF_POINTED_NODES; xIndex += 1) {
Points: for (let yIndex = 1; yIndex <= COUNT_OF_POINTED_NODES; yIndex += 1) {
const x = deltaX * xIndex;
const y = deltaY * yIndex;
for (const rectangle of ignoredRectangles) {
// eslint-disable-next-line max-depth
if (isPointInsideRectangle(x, y, rectangle)) {
continue Points;
}
}
const element = document.elementFromPoint(x, y);
if (element && !elements.includes(element)) {
elements.push(element);
}
}
}
const attributes = elements.map((element) => [
element.className,
element.getBoundingClientRect(),
element.scrollLeft,
element.scrollTop,
]);
return JSON.stringify([attributes, innerHeight, innerWidth]);
};
let interfaceState = getInterfaceState();
let stabilizationIntervalStart = startTimeInMs;
const promise = new Promise((resolve) => {
const intervalId = setInterval(() => {
const newInterfaceState = getInterfaceState();
if (newInterfaceState !== interfaceState) {
stabilizationIntervalStart = Date.now();
}
interfaceState = newInterfaceState;
if (Date.now() - stabilizationIntervalStart >= stabilizationInterval) {
clearInterval(intervalId);
resolve(undefined);
return;
}
if (Date.now() - startTimeInMs > timeout) {
clearInterval(intervalId);
resolve(`Time was out in waitForInterfaceStabilization (${timeout}ms)`);
}
}, CHECK_INTERVAL_IN_MS);
});
return promise;
}, { name: 'waitForInterfaceStabilization' });
/**
* Waits until the page interface stabilizes (in particular, the page will stop scrolling).
*/
const waitForInterfaceStabilization = async (stabilizationInterval, timeout) => {
if (stabilizationInterval === undefined || timeout === undefined) {
const { waitForInterfaceStabilization: config } = (0, config_1.getFullPackConfig)();
const { stabilizationInterval: stabilizationIntervalFromConfig, timeout: timeoutFromConfig } = config;
// eslint-disable-next-line no-param-reassign
stabilizationInterval ??= stabilizationIntervalFromConfig;
// eslint-disable-next-line no-param-reassign
timeout ??= timeoutFromConfig;
}
if (!(stabilizationInterval > 0) || !(timeout > 0)) {
return;
}
const startTimeInMs = Date.now();
const maybeErrorReason = await clientWaitForInterfaceStabilization(stabilizationInterval, timeout);
const waitInMs = Date.now() - startTimeInMs;
const startDateTimeInIso = new Date(startTimeInMs).toISOString();
const stabilizationIntervalWithUnits = (0, getDurationWithUnits_1.getDurationWithUnits)(stabilizationInterval);
const timeoutWithUnits = (0, getDurationWithUnits_1.getDurationWithUnits)(timeout);
const waitWithUnits = (0, getDurationWithUnits_1.getDurationWithUnits)(waitInMs);
(0, log_1.log)(`Have waited for interface stabilization for ${waitWithUnits} with stabilization interval ${stabilizationIntervalWithUnits}`, { error: maybeErrorReason, startDateTimeInIso, timeout: timeoutWithUnits }, 7 /* LogEventType.InternalCore */);
};
exports.waitForInterfaceStabilization = waitForInterfaceStabilization;