@applitools/eyes-playwright 1.40.7 → 1.41.0
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.
- package/CHANGELOG.md +38 -0
- package/dist/fixture/report-plugin/core/log.js +44 -0
- package/dist/fixture/report-plugin/core/types.js +5 -0
- package/dist/fixture/report-plugin/data/dataParser.js +126 -0
- package/dist/fixture/report-plugin/data/uiUtils.js +10 -0
- package/dist/fixture/report-plugin/data/urlManager.js +53 -0
- package/dist/fixture/report-plugin/handlers/domChangesHandler.js +58 -0
- package/dist/fixture/report-plugin/handlers/statusUpdateHandler.js +52 -0
- package/dist/fixture/report-plugin/handlers/urlChangeHandler.js +52 -0
- package/dist/fixture/report-plugin/management/playwrightStatusUpdater.js +73 -0
- package/dist/fixture/report-plugin/management/pollingManager.js +235 -0
- package/dist/fixture/report-plugin/management/reportDataManager.js +32 -0
- package/dist/fixture/report-plugin/management/statusUtils.js +102 -0
- package/dist/fixture/report-plugin/reportRenderer.js +107 -0
- package/dist/fixture/report-plugin/state/navigationState.js +24 -0
- package/dist/fixture/report-plugin/ui/eyesResultsBatchLinkUI.js +51 -0
- package/dist/fixture/report-plugin/ui/filterManager.js +60 -0
- package/dist/fixture/report-plugin/ui/mockIframeRenderer.js +39 -0
- package/dist/fixture/report-plugin/ui/navigationUI.js +98 -0
- package/dist/fixture/report-plugin/ui/testDetailUI.js +265 -0
- package/dist/fixture/report-plugin/ui/testListUI.js +43 -0
- package/dist/fixture/report-plugin/utils/scrollPreserver.js +33 -0
- package/dist/fixture/reportRenderer.js +1 -834
- package/dist/fixture/reportRenderer.js.map +1 -0
- package/package.json +6 -5
- package/dist/fixture/build/rollup.config.js +0 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.41.0](https://github.com/Applitools-Dev/sdk/compare/js/eyes-playwright@1.40.7...js/eyes-playwright@1.41.0) (2025-11-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* new plugin to support legacy playwright and pw 1-55 and above html reporter ([#3302](https://github.com/Applitools-Dev/sdk/issues/3302)) ([946d971](https://github.com/Applitools-Dev/sdk/commit/946d971abd0c7b86c1254bd5a7759eb1729fc7cb))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* @applitools/dom-snapshot bumped to 4.14.0
|
|
14
|
+
#### Features
|
|
15
|
+
|
|
16
|
+
* logging errors from dom snapshot to the backend | AD-11641 ([#3291](https://github.com/Applitools-Dev/sdk/issues/3291)) ([7f5b487](https://github.com/Applitools-Dev/sdk/commit/7f5b48701ff93bf980924c9346a8241ed87f5a56))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
#### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* sandbox prototype pollution | FLD-3738 ([#3310](https://github.com/Applitools-Dev/sdk/issues/3310)) ([3185558](https://github.com/Applitools-Dev/sdk/commit/31855586851d5372169aae7bf0268cec139abc59))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
#### Code Refactoring
|
|
25
|
+
|
|
26
|
+
* blob generation error handling ([#2501](https://github.com/Applitools-Dev/sdk/issues/2501)) ([94bc14f](https://github.com/Applitools-Dev/sdk/commit/94bc14faf3de0fd9a8ca24af4870f839756a8aad))
|
|
27
|
+
* @applitools/ufg-client bumped to 1.18.0
|
|
28
|
+
#### Features
|
|
29
|
+
|
|
30
|
+
* logging errors from dom snapshot to the backend | AD-11641 ([#3291](https://github.com/Applitools-Dev/sdk/issues/3291)) ([7f5b487](https://github.com/Applitools-Dev/sdk/commit/7f5b48701ff93bf980924c9346a8241ed87f5a56))
|
|
31
|
+
* @applitools/core bumped to 4.51.0
|
|
32
|
+
#### Features
|
|
33
|
+
|
|
34
|
+
* logging errors from dom snapshot to the backend | AD-11641 ([#3291](https://github.com/Applitools-Dev/sdk/issues/3291)) ([7f5b487](https://github.com/Applitools-Dev/sdk/commit/7f5b48701ff93bf980924c9346a8241ed87f5a56))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
* @applitools/eyes bumped to 1.36.14
|
|
39
|
+
|
|
40
|
+
|
|
3
41
|
## [1.40.7](https://github.com/Applitools-Dev/sdk/compare/js/eyes-playwright@1.40.6...js/eyes-playwright@1.40.7) (2025-10-22)
|
|
4
42
|
|
|
5
43
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/* eslint no-console: off */
|
|
4
|
+
function isDebugEnabled() {
|
|
5
|
+
try {
|
|
6
|
+
// Get query string from the topmost window (parent frame)
|
|
7
|
+
const topWindow = window.top || window;
|
|
8
|
+
const urlParams = new URLSearchParams(topWindow.location.search);
|
|
9
|
+
return urlParams.get('debug') === 'true';
|
|
10
|
+
}
|
|
11
|
+
catch (e) {
|
|
12
|
+
// Cross-origin access may throw an error, fallback to current window
|
|
13
|
+
try {
|
|
14
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
15
|
+
return urlParams.get('debug') === 'true';
|
|
16
|
+
}
|
|
17
|
+
catch (e2) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function makeLog(prefix = '') {
|
|
23
|
+
const debugEnabled = isDebugEnabled();
|
|
24
|
+
return {
|
|
25
|
+
log: (...args) => {
|
|
26
|
+
if (!debugEnabled)
|
|
27
|
+
return;
|
|
28
|
+
const logArgs = prefix ? [prefix, ...args] : args;
|
|
29
|
+
console.log(...logArgs);
|
|
30
|
+
},
|
|
31
|
+
warn: (...args) => {
|
|
32
|
+
if (!debugEnabled)
|
|
33
|
+
return;
|
|
34
|
+
const logArgs = prefix ? [prefix, ...args] : args;
|
|
35
|
+
console.warn(...logArgs);
|
|
36
|
+
},
|
|
37
|
+
error: (...args) => {
|
|
38
|
+
// Always show errors regardless of debug mode
|
|
39
|
+
const logArgs = prefix ? [prefix, ...args] : args;
|
|
40
|
+
console.error(...logArgs);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
exports.default = makeLog;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getTestResults = void 0;
|
|
7
|
+
const jszip_1 = __importDefault(require("jszip"));
|
|
8
|
+
const statusUtils_js_1 = require("../management/statusUtils.js");
|
|
9
|
+
const playwrightStatusUpdater_js_1 = require("../management/playwrightStatusUpdater.js");
|
|
10
|
+
const reportDataManager_js_1 = require("../management/reportDataManager.js");
|
|
11
|
+
const log_js_1 = __importDefault(require("../core/log.js"));
|
|
12
|
+
const logger = (0, log_js_1.default)('[Eyes Data Parser]');
|
|
13
|
+
async function getTestResults() {
|
|
14
|
+
var _a;
|
|
15
|
+
// Step 1: Get Playwright report data from window object
|
|
16
|
+
const reportData = window.playwrightReportBase64;
|
|
17
|
+
const playwrightReportBase64 = typeof reportData === 'string' ? reportData : (_a = reportData === null || reportData === void 0 ? void 0 : reportData.textContent) !== null && _a !== void 0 ? _a : '';
|
|
18
|
+
if (!playwrightReportBase64) {
|
|
19
|
+
logger.error('[Eyes Data Parser] No playwrightReportBase64 found in window');
|
|
20
|
+
return {
|
|
21
|
+
testsFiles: {},
|
|
22
|
+
report: { files: [], stats: { expected: 0, unexpected: 0, flaky: 0, skipped: 0 } },
|
|
23
|
+
eyesTestResult: {},
|
|
24
|
+
sessionsByBatchId: {},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const base64Data = playwrightReportBase64.replace('data:application/zip;base64,', '');
|
|
28
|
+
// Step 2: Unzip the report data
|
|
29
|
+
const zip = new jszip_1.default();
|
|
30
|
+
await zip.loadAsync(base64Data, { base64: true });
|
|
31
|
+
// Step 3: Extract all test files (except report.json)
|
|
32
|
+
const resultsByTestFile = await Promise.all(Object.keys(zip.files)
|
|
33
|
+
.filter(fileName => fileName !== 'report.json')
|
|
34
|
+
.map(async (fileName) => {
|
|
35
|
+
const file = zip.files[fileName];
|
|
36
|
+
const content = await file.async('text');
|
|
37
|
+
return { [fileName]: JSON.parse(content) };
|
|
38
|
+
}));
|
|
39
|
+
const testsFiles = Object.assign({}, ...resultsByTestFile);
|
|
40
|
+
// Step 4: Extract report.json
|
|
41
|
+
const reportFileObj = zip.file('report.json');
|
|
42
|
+
if (!reportFileObj) {
|
|
43
|
+
throw new Error('[Eyes Data Parser] report.json not found in ZIP');
|
|
44
|
+
}
|
|
45
|
+
const reportFile = await reportFileObj.async('text');
|
|
46
|
+
const report = JSON.parse(reportFile);
|
|
47
|
+
// Step 5: Merge Eyes data from window.__testResultsMap
|
|
48
|
+
const { eyesTestResult, sessionsByBatchId } = mergeEyesData(testsFiles, report);
|
|
49
|
+
// Step 6: Re-zip and update window.playwrightReportBase64 with modified test statuses
|
|
50
|
+
// This is critical! The test statuses have been modified in memory by updatePlaywrightTestStatus
|
|
51
|
+
// We need to re-zip the data so Playwright's UI sees the updated statuses
|
|
52
|
+
await (0, reportDataManager_js_1.refreshReportData)(testsFiles, report);
|
|
53
|
+
return {
|
|
54
|
+
testsFiles,
|
|
55
|
+
report,
|
|
56
|
+
eyesTestResult,
|
|
57
|
+
sessionsByBatchId,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
exports.getTestResults = getTestResults;
|
|
61
|
+
/**
|
|
62
|
+
* Merge Eyes data from window.__testResultsMap with Playwright tests
|
|
63
|
+
*/
|
|
64
|
+
function mergeEyesData(testsFiles, report) {
|
|
65
|
+
const sessionsByBatchId = {};
|
|
66
|
+
const eyesTestResult = {};
|
|
67
|
+
// Check if Eyes data exists
|
|
68
|
+
if (!window.__testResultsMap) {
|
|
69
|
+
logger.warn('[Eyes Data Parser] No window.__testResultsMap found - no Eyes data to merge');
|
|
70
|
+
return { eyesTestResult, sessionsByBatchId };
|
|
71
|
+
}
|
|
72
|
+
// Iterate through all test files
|
|
73
|
+
Object.values(testsFiles).forEach(testFile => {
|
|
74
|
+
// Find file in report for status updates
|
|
75
|
+
const fileInReport = report.files.find(file => file.fileId === testFile.fileId);
|
|
76
|
+
if (!fileInReport)
|
|
77
|
+
return;
|
|
78
|
+
testFile.tests.forEach(test => {
|
|
79
|
+
const eyesResults = [];
|
|
80
|
+
const eyesStatuses = [];
|
|
81
|
+
// Look up Eyes results for each test retry
|
|
82
|
+
test.results.forEach((_result, index) => {
|
|
83
|
+
var _a;
|
|
84
|
+
const lookupKey = `${test.testId}--${index}`;
|
|
85
|
+
const eyesResultsForRetry = (_a = window.__testResultsMap) === null || _a === void 0 ? void 0 : _a[lookupKey];
|
|
86
|
+
if (eyesResultsForRetry) {
|
|
87
|
+
// Get status for this retry
|
|
88
|
+
const status = (0, statusUtils_js_1.getStatus)(eyesResultsForRetry);
|
|
89
|
+
eyesStatuses.push(status.status);
|
|
90
|
+
eyesResultsForRetry.forEach(eyesResult => {
|
|
91
|
+
// Attach retry number to Eyes result
|
|
92
|
+
eyesResult.playwrightRetry = _result.retry || 0;
|
|
93
|
+
// Add to results array
|
|
94
|
+
eyesResults.push(eyesResult);
|
|
95
|
+
// Build sessionsByBatchId for polling
|
|
96
|
+
if (!sessionsByBatchId[eyesResult.batchId]) {
|
|
97
|
+
sessionsByBatchId[eyesResult.batchId] = {
|
|
98
|
+
sessions: [],
|
|
99
|
+
apiKey: eyesResult.eyesServer.apiKey,
|
|
100
|
+
eyesServerUrl: eyesResult.eyesServer.eyesServerUrl,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
sessionsByBatchId[eyesResult.batchId].sessions.push({
|
|
104
|
+
id: eyesResult.id,
|
|
105
|
+
accessToken: eyesResult.secretToken,
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// No Eyes results for this retry
|
|
111
|
+
eyesStatuses.push(null);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// If test has Eyes results, add to eyesTestResult
|
|
115
|
+
if (eyesResults.length > 0) {
|
|
116
|
+
// Update Playwright test status based on Eyes results
|
|
117
|
+
(0, playwrightStatusUpdater_js_1.updatePlaywrightTestStatus)(test, fileInReport, report.stats, eyesStatuses, true);
|
|
118
|
+
eyesTestResult[test.testId] = {
|
|
119
|
+
...test,
|
|
120
|
+
eyesResults,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
return { eyesTestResult, sessionsByBatchId };
|
|
126
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEyesInfo = void 0;
|
|
4
|
+
function createEyesInfo(statusInfo, addVisualIcon = true) {
|
|
5
|
+
const visualIcon = addVisualIcon ? `<span class="visual-test-icon">${window.__icons.visualTest}</span>` : '';
|
|
6
|
+
const statusBar = `<div class="status-bar ${statusInfo.status.toLowerCase()}"></div>`;
|
|
7
|
+
const statusText = `<span class="status-text">${statusInfo.statusText}</span>`;
|
|
8
|
+
return `${visualIcon}${statusBar}${statusText}`;
|
|
9
|
+
}
|
|
10
|
+
exports.createEyesInfo = createEyesInfo;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fixEyesUrl = exports.isTestDetailMode = exports.isListMode = exports.getTestIdFromUrl = exports.getHashValueFromUrl = exports.getHashFromUrl = exports.getHashFromUrlString = exports.getHashFromCurrentUrl = void 0;
|
|
7
|
+
const log_1 = __importDefault(require("../core/log"));
|
|
8
|
+
const logger = (0, log_1.default)();
|
|
9
|
+
function getHashFromCurrentUrl() {
|
|
10
|
+
return getHashFromUrl(window.location);
|
|
11
|
+
}
|
|
12
|
+
exports.getHashFromCurrentUrl = getHashFromCurrentUrl;
|
|
13
|
+
function getHashFromUrlString(urlString) {
|
|
14
|
+
const url = new URL(urlString);
|
|
15
|
+
return getHashFromUrl(url);
|
|
16
|
+
}
|
|
17
|
+
exports.getHashFromUrlString = getHashFromUrlString;
|
|
18
|
+
function getHashFromUrl(url) {
|
|
19
|
+
const hash = new URLSearchParams(url.hash.replace('#', '').replace('?', ''));
|
|
20
|
+
return hash;
|
|
21
|
+
}
|
|
22
|
+
exports.getHashFromUrl = getHashFromUrl;
|
|
23
|
+
function getHashValueFromUrl(urlString, key) {
|
|
24
|
+
const hash = getHashFromUrlString(urlString);
|
|
25
|
+
return hash.get(key);
|
|
26
|
+
}
|
|
27
|
+
exports.getHashValueFromUrl = getHashValueFromUrl;
|
|
28
|
+
function getTestIdFromUrl(urlString) {
|
|
29
|
+
return getHashValueFromUrl(urlString, 'testId');
|
|
30
|
+
}
|
|
31
|
+
exports.getTestIdFromUrl = getTestIdFromUrl;
|
|
32
|
+
function isListMode() {
|
|
33
|
+
const hash = getHashFromCurrentUrl();
|
|
34
|
+
return !hash.get('testId');
|
|
35
|
+
}
|
|
36
|
+
exports.isListMode = isListMode;
|
|
37
|
+
function isTestDetailMode() {
|
|
38
|
+
return !isListMode();
|
|
39
|
+
}
|
|
40
|
+
exports.isTestDetailMode = isTestDetailMode;
|
|
41
|
+
function fixEyesUrl(url) {
|
|
42
|
+
try {
|
|
43
|
+
const urlObj = new URL(url);
|
|
44
|
+
urlObj.hostname = urlObj.hostname.replace('eyesapi', 'eyes');
|
|
45
|
+
const fixedUrl = urlObj.href;
|
|
46
|
+
return fixedUrl.endsWith('/') ? fixedUrl : `${fixedUrl}/`;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger.warn('[URL Manager] Invalid URL:', url);
|
|
50
|
+
return url;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.fixEyesUrl = fixEyesUrl;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DomChangesHandler = void 0;
|
|
4
|
+
const urlManager_js_1 = require("../data/urlManager.js");
|
|
5
|
+
class DomChangesHandler {
|
|
6
|
+
constructor(waitForResults, filterManager, eyesResultsBatchLinkUI, navigationUI, testListUI) {
|
|
7
|
+
this._navigationReadyCalled = false;
|
|
8
|
+
this.handleDomChanges = (mutations) => {
|
|
9
|
+
mutations.forEach(mutation => {
|
|
10
|
+
mutation.addedNodes.forEach(node => {
|
|
11
|
+
if (!(node instanceof HTMLElement))
|
|
12
|
+
return;
|
|
13
|
+
if (node.classList.contains('eyes-batch-link')) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (node.classList.contains('htmlreport')) {
|
|
17
|
+
const hash = (0, urlManager_js_1.getHashFromCurrentUrl)();
|
|
18
|
+
this.filterManager.applyFiltersFromUrl(hash);
|
|
19
|
+
}
|
|
20
|
+
if (node.classList.contains('chip')) {
|
|
21
|
+
this.waitForResults.then(testResults => {
|
|
22
|
+
this.eyesResultsBatchLinkUI.createLinkToBatch(testResults);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const isHeaderElement = node.classList.contains('header-view-status-container') ||
|
|
26
|
+
node.getElementsByClassName('header-view-status-container').length > 0;
|
|
27
|
+
if (isHeaderElement) {
|
|
28
|
+
this.onNavigationReady();
|
|
29
|
+
}
|
|
30
|
+
const hasTestRows = node.getElementsByClassName('test-file-details-row').length > 0;
|
|
31
|
+
if (hasTestRows) {
|
|
32
|
+
this.waitForResults.then(testResults => {
|
|
33
|
+
this.testListUI.addEyesDetailsToTests(node, testResults);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
this.waitForResults = waitForResults;
|
|
40
|
+
this.filterManager = filterManager;
|
|
41
|
+
this.eyesResultsBatchLinkUI = eyesResultsBatchLinkUI;
|
|
42
|
+
this.navigationUI = navigationUI;
|
|
43
|
+
this.testListUI = testListUI;
|
|
44
|
+
}
|
|
45
|
+
onNavigationReady() {
|
|
46
|
+
if (this._navigationReadyCalled) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this._navigationReadyCalled = true;
|
|
50
|
+
this.waitForResults.then(testResults => {
|
|
51
|
+
setTimeout(() => {
|
|
52
|
+
this.navigationUI.createFilters(testResults);
|
|
53
|
+
this.navigationUI.updateActiveStates();
|
|
54
|
+
}, 200);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.DomChangesHandler = DomChangesHandler;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StatusUpdateHandler = void 0;
|
|
7
|
+
const urlManager_js_1 = require("../data/urlManager.js");
|
|
8
|
+
const log_1 = __importDefault(require("../core/log"));
|
|
9
|
+
const logger = (0, log_1.default)();
|
|
10
|
+
class StatusUpdateHandler {
|
|
11
|
+
constructor(scrollPreserver, eyesResultsBatchLinkUI, navigationUI, testListUI, testDetailUI) {
|
|
12
|
+
this.handleStatusUpdate = async (testResults) => {
|
|
13
|
+
// Capture scroll position before triggering window.onload
|
|
14
|
+
this.scrollPreserver.captureScrollPosition();
|
|
15
|
+
if (typeof window.onload === 'function') {
|
|
16
|
+
const onloadHandler = window.onload;
|
|
17
|
+
onloadHandler(new Event('load'));
|
|
18
|
+
}
|
|
19
|
+
setTimeout(() => {
|
|
20
|
+
const hash = (0, urlManager_js_1.getHashFromCurrentUrl)();
|
|
21
|
+
const testId = hash.get('testId');
|
|
22
|
+
if (!testId) {
|
|
23
|
+
this.eyesResultsBatchLinkUI.createLinkToBatch(testResults);
|
|
24
|
+
}
|
|
25
|
+
this.navigationUI.resetFilters();
|
|
26
|
+
this.navigationUI.createFilters(testResults);
|
|
27
|
+
this.navigationUI.updateActiveStates();
|
|
28
|
+
if (!testId) {
|
|
29
|
+
const rootElement = document.getElementById('root');
|
|
30
|
+
if (rootElement) {
|
|
31
|
+
this.testListUI.addEyesDetailsToTests(rootElement, testResults);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (testId) {
|
|
35
|
+
logger.log('[Status Update Handler] Updating Eyes test result UI for testId:', testId);
|
|
36
|
+
const test = testResults.eyesTestResult[testId];
|
|
37
|
+
if (test) {
|
|
38
|
+
this.testDetailUI.createEyesTestResults(test);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Restore scroll position after React has re-rendered
|
|
42
|
+
this.scrollPreserver.restoreScrollPosition();
|
|
43
|
+
}, 200);
|
|
44
|
+
};
|
|
45
|
+
this.scrollPreserver = scrollPreserver;
|
|
46
|
+
this.eyesResultsBatchLinkUI = eyesResultsBatchLinkUI;
|
|
47
|
+
this.navigationUI = navigationUI;
|
|
48
|
+
this.testListUI = testListUI;
|
|
49
|
+
this.testDetailUI = testDetailUI;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.StatusUpdateHandler = StatusUpdateHandler;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.UrlChangeHandler = void 0;
|
|
7
|
+
const urlManager_js_1 = require("../data/urlManager.js");
|
|
8
|
+
const log_1 = __importDefault(require("../core/log"));
|
|
9
|
+
const logger = (0, log_1.default)();
|
|
10
|
+
class UrlChangeHandler {
|
|
11
|
+
constructor(waitForResults, navigationState, filterManager, eyesResultsBatchLinkUI, navigationUI, testDetailUI) {
|
|
12
|
+
this.handleUrlChange = () => {
|
|
13
|
+
const hash = (0, urlManager_js_1.getHashFromCurrentUrl)();
|
|
14
|
+
const testId = hash.get('testId');
|
|
15
|
+
const previousTestId = this.navigationState.activeTestId;
|
|
16
|
+
const fromTestToMain = !testId && previousTestId;
|
|
17
|
+
if (!testId) {
|
|
18
|
+
this.filterManager.applyFiltersFromUrl(hash);
|
|
19
|
+
this.navigationUI.updateActiveStates();
|
|
20
|
+
}
|
|
21
|
+
this.waitForResults.then(testResults => {
|
|
22
|
+
logger.log('[URL Change Handler] Handling URL change. testId:', testId);
|
|
23
|
+
this.eyesResultsBatchLinkUI.createLinkToBatch(testResults);
|
|
24
|
+
if (testId) {
|
|
25
|
+
const test = testResults.eyesTestResult[testId];
|
|
26
|
+
if (test) {
|
|
27
|
+
// Don't set activeTestId here - let TestDetailUI own the state setting
|
|
28
|
+
this.testDetailUI.createEyesTestResults(test);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
this.testDetailUI.cleanupExistingChips();
|
|
32
|
+
this.navigationState.clearActiveTestId();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else if (fromTestToMain) {
|
|
36
|
+
this.testDetailUI.cleanupExistingChips();
|
|
37
|
+
this.testDetailUI.cancelPendingOperations();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
this.waitForResults = waitForResults;
|
|
42
|
+
this.navigationState = navigationState;
|
|
43
|
+
this.filterManager = filterManager;
|
|
44
|
+
this.eyesResultsBatchLinkUI = eyesResultsBatchLinkUI;
|
|
45
|
+
this.navigationUI = navigationUI;
|
|
46
|
+
this.testDetailUI = testDetailUI;
|
|
47
|
+
}
|
|
48
|
+
get activeTestId() {
|
|
49
|
+
return this.navigationState.activeTestId;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.UrlChangeHandler = UrlChangeHandler;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateAllPlaywrightTestStatuses = exports.updatePlaywrightTestStatus = exports.getRunStatusFromEyesStatuses = exports.getOutcomeFromEyesStatuses = void 0;
|
|
4
|
+
const statusUtils_js_1 = require("./statusUtils.js");
|
|
5
|
+
function getOutcomeFromEyesStatuses(eyesStatuses, testOutcome) {
|
|
6
|
+
return eyesStatuses.every(status => status === 'unresolved' || status === 'failed')
|
|
7
|
+
? 'unexpected'
|
|
8
|
+
: eyesStatuses.some(status => status === 'unresolved' || status === 'failed')
|
|
9
|
+
? 'flaky'
|
|
10
|
+
: testOutcome;
|
|
11
|
+
}
|
|
12
|
+
exports.getOutcomeFromEyesStatuses = getOutcomeFromEyesStatuses;
|
|
13
|
+
function getRunStatusFromEyesStatuses(eyesStatus, runStatus) {
|
|
14
|
+
return eyesStatus === 'unresolved' || eyesStatus === 'failed' ? 'failed' : runStatus;
|
|
15
|
+
}
|
|
16
|
+
exports.getRunStatusFromEyesStatuses = getRunStatusFromEyesStatuses;
|
|
17
|
+
function updatePlaywrightTestStatus(test, fileInReport, reportStats, eyesStatuses, updateOriginalOutcome = false) {
|
|
18
|
+
var _a, _b;
|
|
19
|
+
if (eyesStatuses.filter(status => status !== null).length > 0 &&
|
|
20
|
+
// test outcome: 'skipped' | 'expected' | 'unexpected' | 'flaky'
|
|
21
|
+
['expected', 'flaky'].includes((_a = test.originalOutcome) !== null && _a !== void 0 ? _a : test.outcome)) {
|
|
22
|
+
test.results.forEach((_result, index) => {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
const eyesStatus = eyesStatuses[index];
|
|
25
|
+
// run status: 'passed' | 'failed' | 'timedOut' | 'skipped' | 'interrupted'
|
|
26
|
+
if (((_a = _result.originalStatus) !== null && _a !== void 0 ? _a : _result.status) === 'passed' && eyesStatus !== null) {
|
|
27
|
+
if (updateOriginalOutcome)
|
|
28
|
+
_result.originalStatus = _result.status;
|
|
29
|
+
_result.status = getRunStatusFromEyesStatuses(eyesStatus, (_b = _result.originalStatus) !== null && _b !== void 0 ? _b : _result.status);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const testInReport = fileInReport.tests.find(t => t.testId === test.testId);
|
|
33
|
+
if (!testInReport)
|
|
34
|
+
return;
|
|
35
|
+
if (updateOriginalOutcome) {
|
|
36
|
+
testInReport.originalOutcome = test.originalOutcome = test.outcome;
|
|
37
|
+
}
|
|
38
|
+
const newOutcome = getOutcomeFromEyesStatuses(eyesStatuses.filter((status) => status !== null), (_b = test.originalOutcome) !== null && _b !== void 0 ? _b : test.outcome);
|
|
39
|
+
if (testInReport.outcome !== newOutcome) {
|
|
40
|
+
reportStats[testInReport.outcome]--;
|
|
41
|
+
reportStats[newOutcome]++;
|
|
42
|
+
}
|
|
43
|
+
testInReport.outcome = test.outcome = newOutcome;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.updatePlaywrightTestStatus = updatePlaywrightTestStatus;
|
|
47
|
+
function updateAllPlaywrightTestStatuses(testResults) {
|
|
48
|
+
Object.values(testResults.testsFiles).forEach(testFile => {
|
|
49
|
+
const fileInReport = testResults.report.files.find(file => file.fileId === testFile.fileId);
|
|
50
|
+
const reportStats = testResults.report.stats;
|
|
51
|
+
testFile.tests.forEach(test => {
|
|
52
|
+
var _a;
|
|
53
|
+
const eyesResultsForTest = (_a = testResults.eyesTestResult[test.testId]) === null || _a === void 0 ? void 0 : _a.eyesResults;
|
|
54
|
+
if (!eyesResultsForTest)
|
|
55
|
+
return;
|
|
56
|
+
if (!fileInReport)
|
|
57
|
+
return;
|
|
58
|
+
// Get Eyes status for each retry
|
|
59
|
+
const eyesStatuses = test.results.reduce((results, _result) => {
|
|
60
|
+
const eyesResultsForRun = eyesResultsForTest.filter(result => result.playwrightRetry === _result.retry);
|
|
61
|
+
if (eyesResultsForRun.length > 0) {
|
|
62
|
+
results.push((0, statusUtils_js_1.getStatus)(eyesResultsForRun).status);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
results.push(null);
|
|
66
|
+
}
|
|
67
|
+
return results;
|
|
68
|
+
}, []);
|
|
69
|
+
updatePlaywrightTestStatus(test, fileInReport, reportStats, eyesStatuses);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
exports.updateAllPlaywrightTestStatuses = updateAllPlaywrightTestStatuses;
|