UNPKG

html-reporter

Version:

Html-reporter and GUI for viewing and managing results of a tests run. Currently supports Testplane and Hermione.

151 lines 7.81 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.finalizeSnapshotsForTest = exports.handleDomSnapshotsEvent = exports.createSnapshotFilePath = exports.getSnapshotHashWithoutAttempt = exports.snapshotsInProgress = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const debug_1 = __importDefault(require("debug")); const fs_extra_1 = __importDefault(require("fs-extra")); const lodash_1 = __importDefault(require("lodash")); const yazl_1 = __importDefault(require("yazl")); const constants_1 = require("../../../constants"); const types_1 = require("../../../types"); const constants_2 = require("../../../gui/constants"); const server_utils_1 = require("../../../server-utils"); const debug = (0, debug_1.default)('html-reporter:event-handling:snapshots'); const TimeTravelMode = (0, server_utils_1.getTimeTravelModeEnumSafe)(); exports.snapshotsInProgress = {}; const getSnapshotHashWithoutAttempt = (context) => { return `${context.testPath.join()}.${context.browserId}`; }; exports.getSnapshotHashWithoutAttempt = getSnapshotHashWithoutAttempt; function createSnapshotFilePath({ attempt: attemptInput, hash, browserId, timestamp }) { const attempt = attemptInput || 0; const snapshotDir = lodash_1.default.compact([constants_1.SNAPSHOTS_PATH, hash]); const components = snapshotDir.concat(`${browserId}_${timestamp}_${attempt}.zip`); return path_1.default.join(...components); } exports.createSnapshotFilePath = createSnapshotFilePath; const handleDomSnapshotsEvent = (client, context, data) => { try { const hash = (0, exports.getSnapshotHashWithoutAttempt)(context); if (!exports.snapshotsInProgress[hash]) { exports.snapshotsInProgress[hash] = []; } // We need to number snapshots during live streaming for a case when user switches in UI to some test while it's running // In this case we need to merge 2 parts: snapshots that were taken before user switched and ones that we receive live // Since they can overlap, we introduce sequence numbering to guarantee smooth experience let seqNo = exports.snapshotsInProgress[hash].length; const rrwebSnapshotsNumbered = data.rrwebSnapshots.map(snapshot => Object.assign({}, snapshot, { seqNo: seqNo++ })); exports.snapshotsInProgress[hash].push(...rrwebSnapshotsNumbered); if (client) { client.emit(constants_2.ClientEvents.DOM_SNAPSHOTS, { context, data: { rrwebSnapshots: rrwebSnapshotsNumbered } }); } } catch (e) { console.warn(`Failed to handle DOM_SNAPSHOTS event for test "${context?.testPath?.join(' ')}.${context?.browserId}" in html-reporter due to an error.`, e); } }; exports.handleDomSnapshotsEvent = handleDomSnapshotsEvent; const finalizeSnapshotsForTest = async ({ testResult, attempt, reportPath, timeTravelConfig, events, eventName, snapshotsSaver }) => { try { const hash = (0, exports.getSnapshotHashWithoutAttempt)(testResult); const snapshots = exports.snapshotsInProgress[hash]; delete exports.snapshotsInProgress[hash]; // Here we only check LastFailedRun, because in case of Off, we wouldn't even be here. LastFailedRun is the only case when we may want to not save snapshots. const shouldSave = TimeTravelMode && timeTravelConfig && (timeTravelConfig.mode !== TimeTravelMode.LastFailedRun || (eventName === events.TEST_FAIL)); if (!shouldSave || !snapshots || snapshots.length === 0) { debug('Not saving snapshots for test "%s"', hash); debug('shouldSave evaluated to: %s', shouldSave, ', timeTravelConfig: ', timeTravelConfig, ', eventName: ', eventName); debug('snapshots: ', snapshots); return []; } if (testResult.history && testResult.history.length > 0 && snapshots.length > 0) { const firstSnapshotTime = snapshots[0].timestamp; const lastSnapshotTime = snapshots[snapshots.length - 1].timestamp; const firstHistoryTime = testResult.history[0][types_1.TestStepKey.TimeStart]; const lastHistoryTime = Math.max(testResult.history[testResult.history.length - 1][types_1.TestStepKey.TimeStart], firstHistoryTime + testResult.duration); if (firstHistoryTime < firstSnapshotTime) { const fakeStartSnapshot = { data: { id: 1, source: 3, x: 0, y: 0 }, timestamp: firstHistoryTime, type: 3, seqNo: -1 }; snapshots.unshift(fakeStartSnapshot); } if (lastHistoryTime > lastSnapshotTime) { const fakeEndSnapshot = { data: { id: 1, source: 3, x: 0, y: 0 }, timestamp: lastHistoryTime, type: 3, seqNo: snapshots.length }; snapshots.push(fakeEndSnapshot); } snapshots.forEach((snapshot, index) => { snapshot.seqNo = index; }); } const snapshotsSerialized = snapshots.map(s => JSON.stringify(s)).join('\n'); let maxWidth = 0, maxHeight = 0; for (const snapshot of snapshots) { if (snapshot.type !== 4) { continue; } if (snapshot.data.width > maxWidth) { maxWidth = snapshot.data.width; } if (snapshot.data.height > maxHeight) { maxHeight = snapshot.data.height; } } const zipFilePath = createSnapshotFilePath({ attempt, hash: testResult.imageDir, browserId: testResult.browserId, timestamp: testResult.timestamp }); const absoluteZipFilePath = path_1.default.resolve(reportPath, zipFilePath); await fs_extra_1.default.ensureDir(path_1.default.dirname(absoluteZipFilePath)); // eslint-disable-next-line @typescript-eslint/no-unused-vars let done = (_attachments) => { }; const resultPromise = new Promise((resolve) => { done = resolve; }); const zipfile = new yazl_1.default.ZipFile(); const output = fs_1.default.createWriteStream(absoluteZipFilePath); zipfile.outputStream.pipe(output).on('close', async () => { let savedPath = zipFilePath; if (snapshotsSaver) { try { savedPath = await snapshotsSaver.saveSnapshot(absoluteZipFilePath, { destPath: zipFilePath, reportDir: reportPath }); } catch (e) { console.warn(`Failed to save snapshot using custom saver for test "${testResult?.testPath?.join(' ')}.${testResult?.browserId}" (local path will be used): ${e}`); } } done([{ type: types_1.AttachmentType.Snapshot, path: savedPath, maxWidth, maxHeight }]); }); zipfile.addBuffer(Buffer.from(snapshotsSerialized), 'snapshots.json'); zipfile.end(); return resultPromise; } catch (e) { console.warn(`Failed to finalize DOM snapshots for test "${testResult?.testPath?.join(' ')}.${testResult?.browserId}" in html-reporter due to an error.`, e); return []; } }; exports.finalizeSnapshotsForTest = finalizeSnapshotsForTest; //# sourceMappingURL=snapshots.js.map