@applitools/eyes-playwright
Version:
Applitools Eyes SDK for Playwright
111 lines (110 loc) • 6.08 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Report Renderer - Orchestrates Eyes integration into Playwright HTML reports
*
* Initial Flow:
* 1. Waits for test results, calls window.onload() to refresh Playwright UI with Eyes data
* 2. After 200ms delay (for React render), creates Eyes UI elements via DOM observer
* 3. Renders batch link (list mode), navigation filters, test badges (list mode), iframes (detail mode)
* 4. Starts polling Eyes server every 5s for status updates
*
* Polling & Update Flow:
* - Detects changes by comparing status fields before updating
* - Continues indefinitely unless all tests reach `aborted` status
* - On changes: merges updates, recalculates Playwright statuses, updates window.playwrightReportBase64
* - Triggers window.onload() for React re-render (removes all Eyes elements from DOM)
* - After 200ms delay, recreates Eyes elements in order: batch link, filters, badges, iframes
*/
const dataParser_js_1 = require("./data/dataParser.js");
const navigationState_js_1 = require("./state/navigationState.js");
const scrollPreserver_js_1 = require("./utils/scrollPreserver.js");
const scriptTagRestorer_js_1 = require("./utils/scriptTagRestorer.js");
const eyesResultsBatchLinkUI_js_1 = require("./ui/eyesResultsBatchLinkUI.js");
const navigationUI_js_1 = require("./ui/navigationUI.js");
const filterManager_js_1 = require("./ui/filterManager.js");
const testListUI_js_1 = require("./ui/testListUI.js");
const testDetailUI_js_1 = require("./ui/testDetailUI.js");
const pollingManager_js_1 = require("./management/pollingManager.js");
const urlChangeHandler_js_1 = require("./handlers/urlChangeHandler.js");
const domChangesHandler_js_1 = require("./handlers/domChangesHandler.js");
const statusUpdateHandler_js_1 = require("./handlers/statusUpdateHandler.js");
const log_1 = __importDefault(require("./core/log"));
const logger = (0, log_1.default)();
class ReportRenderer {
constructor(waitForResults, options = {}) {
this.updatePlaywrightWithEyesResults = () => {
// Capture scroll position before triggering window.onload
this.scrollPreserver.captureScrollPosition();
// Ensure the script tag exists before calling window.onload (Playwright 1.57+ compatibility)
(0, scriptTagRestorer_js_1.ensureScriptTagExists)();
if (typeof window.onload === 'function') {
const onloadHandler = window.onload;
onloadHandler(new Event('load'));
}
setTimeout(() => {
this.urlChangeHandler.handleUrlChange();
// Restore scroll position after React has re-rendered
this.scrollPreserver.restoreScrollPosition();
}, 200);
};
this.handleStatusUpdate = async (testResults) => {
this.waitForResults = Promise.resolve(testResults);
await this.statusUpdateHandler.handleStatusUpdate(testResults);
};
this.waitForResults = waitForResults;
this.useTestMode = options.useTestMode || false;
// Create shared navigation state
this.navigationState = new navigationState_js_1.NavigationState();
this.scrollPreserver = new scrollPreserver_js_1.ScrollPreserver();
this.filterManager = new filterManager_js_1.FilterManager();
this.eyesResultsBatchLinkUI = new eyesResultsBatchLinkUI_js_1.EyesResultsBatchLinkUI();
this.navigationUI = new navigationUI_js_1.NavigationUI(this.filterManager);
this.testListUI = new testListUI_js_1.TestListUI();
this.testDetailUI = new testDetailUI_js_1.TestDetailUI(this.navigationState, { useTestMode: this.useTestMode });
this.urlChangeHandler = new urlChangeHandler_js_1.UrlChangeHandler(this.waitForResults, this.navigationState, this.filterManager, this.eyesResultsBatchLinkUI, this.navigationUI, this.testDetailUI);
this.domChangesHandler = new domChangesHandler_js_1.DomChangesHandler(this.waitForResults, this.filterManager, this.eyesResultsBatchLinkUI, this.navigationUI, this.testListUI);
this.statusUpdateHandler = new statusUpdateHandler_js_1.StatusUpdateHandler(this.scrollPreserver, this.eyesResultsBatchLinkUI, this.navigationUI, this.testListUI, this.testDetailUI);
this.pollingManager = new pollingManager_js_1.PollingManager();
this.pollingManager.onStatusUpdate = this.handleStatusUpdate;
this.waitForResults.then(this.updatePlaywrightWithEyesResults);
}
render() {
window.addEventListener('hashchange', this.urlChangeHandler.handleUrlChange);
window.addEventListener('popstate', this.urlChangeHandler.handleUrlChange);
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', this.urlChangeHandler.handleUrlChange);
}
else {
this.urlChangeHandler.handleUrlChange();
}
this.observeDomChanges();
this.pollingManager.startPolling(this.waitForResults);
}
observeDomChanges() {
const mutationObserver = new MutationObserver(this.domChangesHandler.handleDomChanges);
const rootElement = document.getElementById('root');
if (!rootElement) {
logger.warn('No root element found for observation');
return;
}
mutationObserver.observe(rootElement, {
childList: true,
subtree: true,
});
}
updateFilterCounts(testResults) {
this.navigationUI.updateFilterCounts(testResults);
}
}
window.__initEyesReport = (options = {}) => {
const useTestMode = options.useTestMode || false;
logger.log('Before Initialized');
const waitForResults = (0, dataParser_js_1.getTestResults)();
const reportRenderer = new ReportRenderer(waitForResults, { useTestMode });
reportRenderer.render();
logger.log('Initialized');
};