UNPKG

testplane

Version:

Tests framework based on mocha and wdio

259 lines 10.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sendFilteredEvents = exports.filterEvents = exports.cleanupRrweb = exports.installRrwebAndCollectEvents = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const debug_1 = __importDefault(require("debug")); const events_1 = require("../../events"); const index_1 = require("./index"); const debug = (0, debug_1.default)("testplane:time-travel:rrweb"); // Built from branch https://github.com/gemini-testing/rrweb/tree/TESTPLANE-712.syntax_err // PR: https://github.com/rrweb-io/rrweb/pull/1735 // Issue: https://github.com/rrweb-io/rrweb/issues/1734 const rrwebCode = fs_1.default.readFileSync(path_1.default.join(__dirname, "../client-scripts/rrweb-record.min.js"), "utf-8"); const sessionsWithRrwebSent = new WeakSet(); const sessionsWithUnsupportedRrweb = new WeakSet(); /* eslint-disable @typescript-eslint/ban-ts-comment */ async function installRrwebAndCollectEvents(session, callstack) { return (0, index_1.runWithoutHistory)({ callstack }, async () => { if (sessionsWithUnsupportedRrweb.has(session)) { return []; } const shouldSendRrwebCode = !sessionsWithRrwebSent.has(session); if (shouldSendRrwebCode) { sessionsWithRrwebSent.add(session); } let result = await collectRrwebEvents(session, shouldSendRrwebCode ? rrwebCode : undefined); let debugBrowserId = ""; if (debug.enabled) { debugBrowserId = `${session?.capabilities?.browserName} ${session?.capabilities?.browserVersion}:${session?.sessionId}`; } if (result.isRrwebSupported === false) { debug("rrweb is not supported in browser %s, error: %s", debugBrowserId, result.evalError); sessionsWithUnsupportedRrweb.add(session); return []; } // If rrweb is installed (success) or we already provided the code (no point in trying again) if (result.isRrwebInstalled || shouldSendRrwebCode) { return result.rrwebEvents; } debug("collectRrwebEvents, rrweb was not installed, sending code again"); result = await collectRrwebEvents(session, rrwebCode); if (result.isRrwebSupported === false) { debug("rrweb is not supported in browser %s, error: %s", debugBrowserId, result.evalError); sessionsWithUnsupportedRrweb.add(session); return []; } return result.rrwebEvents; }); } exports.installRrwebAndCollectEvents = installRrwebAndCollectEvents; async function cleanupRrweb(session, callstack) { try { await (0, index_1.runWithoutHistory)({ callstack }, () => session.execute(() => { try { // @ts-expect-error const rrwebEvents = window.rrwebEvents; const rrwebData = rrwebEvents && rrwebEvents.testplane; if (rrwebData && rrwebData.stopRecording) { try { rrwebData.stopRecording(); } catch (e) { /**/ } } try { const colorSchemeMedia = rrwebData && rrwebData.colorSchemeMedia; const colorSchemeListener = rrwebData && rrwebData.colorSchemeListener; if (colorSchemeMedia && colorSchemeListener) { colorSchemeMedia.removeEventListener("change", colorSchemeListener); } } catch (e) { /**/ } if (rrwebData && rrwebData.isInstalledByTestplane) { // @ts-expect-error delete window.rrweb; // @ts-expect-error delete window.lastProcessedRrwebEvent; // @ts-expect-error delete window.rrwebEvents; } else if (rrwebEvents) { delete rrwebEvents.testplane; } } catch (e) { /**/ } })); } catch (e) { /**/ } finally { sessionsWithRrwebSent.delete(session); sessionsWithUnsupportedRrweb.delete(session); } } exports.cleanupRrweb = cleanupRrweb; function collectRrwebEvents(session, rrwebRecordFnCode) { return session.execute((rrwebRecordFnCode, serverTime) => { const isRrwebInstalled = () => { try { // @ts-expect-error return Boolean(window.rrweb); } catch (e) { return false; } }; const getRrwebEvents = () => { let result; try { // @ts-expect-error result = window.rrwebEvents.slice(window.lastProcessedRrwebEvent + 1); // @ts-expect-error window.lastProcessedRrwebEvent = window.rrwebEvents.length - 1; } catch (e) { result = []; } return result; }; const getRealTimestamp = (fallbackTime = 0) => { const nativeCode = "[native code]"; try { if (Date.now.toString().includes(nativeCode)) { return Date.now(); } } catch (e) { /**/ } try { if (new Date().getTime.toString().includes(nativeCode)) { return new Date().getTime(); } } catch (e) { /**/ } try { if (new Date().valueOf.toString().includes(nativeCode)) { return new Date().valueOf(); } } catch (e) { /**/ } try { if (performance.now.toString().includes(nativeCode)) { return Math.floor(performance.timeOrigin + performance.now()); } } catch (e) { /**/ } return fallbackTime; }; try { if (!isRrwebInstalled() && rrwebRecordFnCode) { try { window.eval(rrwebRecordFnCode); } catch (e) { return { isRrwebSupported: false, isRrwebInstalled: false, rrwebEvents: [], evalError: String(e), }; } // @ts-expect-error window.lastProcessedRrwebEvent = -1; // @ts-expect-error window.rrwebEvents = []; // @ts-expect-error Object.defineProperty(window.rrwebEvents, "testplane", { configurable: true, value: { isInstalledByTestplane: true, }, }); // @ts-expect-error window.rrwebEvents.testplane.stopRecording = window.rrweb.record({ // @ts-expect-error emit(event) { event.timestamp = getRealTimestamp(serverTime); // @ts-expect-error window.rrwebEvents.push(event); }, }); const colorSchemeMedia = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)"); // @ts-expect-error window.rrweb.record.addCustomEvent("color-scheme-change", { colorScheme: colorSchemeMedia && colorSchemeMedia.matches ? "dark" : "light", }); if (colorSchemeMedia) { const colorSchemeListener = (event) => { // @ts-expect-error window.rrweb.record.addCustomEvent("color-scheme-change", { colorScheme: event.matches ? "dark" : "light", }); }; colorSchemeMedia.addEventListener("change", colorSchemeListener); // @ts-expect-error window.rrwebEvents.testplane.colorSchemeMedia = colorSchemeMedia; // @ts-expect-error window.rrwebEvents.testplane.colorSchemeListener = colorSchemeListener; } } } catch (e) { /**/ } if (!isRrwebInstalled()) { return { isRrwebInstalled: false, rrwebEvents: [], }; } return { isRrwebInstalled: true, rrwebEvents: getRrwebEvents(), }; }, rrwebRecordFnCode, Date.now()); } /* eslint-enable @typescript-eslint/ban-ts-comment */ function filterEvents(rrwebEvents) { return rrwebEvents.filter(e => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const dataAny = e?.data; // cd_frame_id_ attribute is specific for chromedriver and in rare cases can be captured by rrweb // It doesn't hold any value, and we want to get rid of it here. return !dataAny?.attributes?.[0]?.attributes?.["cd_frame_id_"]; }); } exports.filterEvents = filterEvents; function sendFilteredEvents(currentTest, rrwebEvents) { if (rrwebEvents.length > 0 && process.send && currentTest) { process.send({ event: events_1.MasterEvents.DOM_SNAPSHOTS, context: { testPath: currentTest.titlePath(), browserId: currentTest.browserId, }, data: { rrwebSnapshots: rrwebEvents, }, }); } } exports.sendFilteredEvents = sendFilteredEvents; //# sourceMappingURL=rrweb.js.map