UNPKG

html-reporter

Version:

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

279 lines 13.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTimeTravelModeEnumSafe = exports.getImagesInfoByStateName = exports.getExpectedCacheKey = exports.saveErrorDetails = exports.formatTestResult = exports.mapPlugins = exports.forEachPlugin = exports.isUnexpectedPlugin = exports.getPluginMiddleware = exports.getPluginClientScriptPath = exports.getDataForStaticFile = exports.getConfigForStaticFile = exports.copyToReportDir = exports.writeDatabaseUrlsFile = exports.isDbFile = exports.isJsonUrl = exports.urlPathNameEndsWith = exports.copyPlugin = exports.copyPlugins = exports.saveStaticFilesToReportDir = exports.shouldUpdateAttempt = exports.prepareCommonJSData = exports.logError = exports.logPathToHtmlReport = exports.fileExists = exports.makeDirFor = exports.deleteFile = exports.copyFileAsync = exports.createHash = exports.getTempPath = exports.createPath = exports.getDiffAbsolutePath = exports.getCurrentAbsolutePath = exports.getReferenceAbsolutePath = exports.getDiffPath = exports.getCurrentPath = exports.getReferencePath = void 0; const crypto_1 = __importDefault(require("crypto")); const path_1 = __importDefault(require("path")); const url_1 = __importDefault(require("url")); const chalk_1 = __importDefault(require("chalk")); const fs_extra_1 = __importDefault(require("fs-extra")); const lodash_1 = __importDefault(require("lodash")); const tmp_1 = __importDefault(require("tmp")); const common_utils_1 = require("./common-utils"); const constants_1 = require("./constants"); const testplane_1 = require("./adapters/test-result/testplane"); const DATA_FILE_NAME = 'data.js'; const getReferencePath = (options, stateName) => createPath({ kind: 'ref', stateName, ...lodash_1.default.pick(options, ['attempt', 'browserId', 'imageDir', 'timestamp']) }); exports.getReferencePath = getReferencePath; const getCurrentPath = (options, stateName) => createPath({ kind: 'current', stateName, ...lodash_1.default.pick(options, ['attempt', 'browserId', 'imageDir', 'timestamp']) }); exports.getCurrentPath = getCurrentPath; const getDiffPath = (options, stateName) => createPath({ kind: 'diff', stateName, ...lodash_1.default.pick(options, ['attempt', 'browserId', 'imageDir', 'timestamp']) }); exports.getDiffPath = getDiffPath; const getReferenceAbsolutePath = (testResult, reportDir, stateName) => { const referenceImagePath = (0, exports.getReferencePath)({ attempt: testResult.attempt, imageDir: testResult.imageDir, browserId: testResult.browserId, timestamp: testResult.timestamp }, stateName); return path_1.default.resolve(reportDir, referenceImagePath); }; exports.getReferenceAbsolutePath = getReferenceAbsolutePath; const getCurrentAbsolutePath = (testResult, reportDir, stateName) => { const currentImagePath = (0, exports.getCurrentPath)({ attempt: testResult.attempt, imageDir: testResult.imageDir, browserId: testResult.browserId, timestamp: testResult.timestamp }, stateName); return path_1.default.resolve(reportDir, currentImagePath); }; exports.getCurrentAbsolutePath = getCurrentAbsolutePath; const getDiffAbsolutePath = (testResult, reportDir, stateName) => { const diffImagePath = (0, exports.getDiffPath)({ attempt: testResult.attempt, imageDir: testResult.imageDir, browserId: testResult.browserId, timestamp: testResult.timestamp }, stateName); return path_1.default.resolve(reportDir, diffImagePath); }; exports.getDiffAbsolutePath = getDiffAbsolutePath; function createPath({ attempt: attemptInput, imageDir: imageDirInput, timestamp, browserId, kind, stateName }) { const attempt = attemptInput || 0; const imageDir = lodash_1.default.compact([constants_1.IMAGES_PATH, imageDirInput, stateName]); const components = imageDir.concat(`${browserId}~${kind}_${timestamp}_${attempt}.png`); return path_1.default.join(...components); } exports.createPath = createPath; const getTempPath = (destPath) => path_1.default.resolve(tmp_1.default.tmpdir, destPath); exports.getTempPath = getTempPath; function createHash(buffer) { return crypto_1.default .createHash('sha1') .update(buffer) .digest('base64'); } exports.createHash = createHash; function copyFileAsync(srcPath, destPath, { reportDir = '', overwrite = true } = {}) { const resolvedDestPath = path_1.default.resolve(reportDir, destPath); return makeDirFor(resolvedDestPath).then(() => fs_extra_1.default.copy(srcPath, resolvedDestPath, { overwrite })); } exports.copyFileAsync = copyFileAsync; function deleteFile(filePath) { return fs_extra_1.default.remove(filePath); } exports.deleteFile = deleteFile; function makeDirFor(destPath) { return fs_extra_1.default.mkdirs(path_1.default.dirname(destPath)); } exports.makeDirFor = makeDirFor; function fileExists(path) { return fs_extra_1.default.existsSync(path); } exports.fileExists = fileExists; function logPathToHtmlReport(pluginConfig) { const reportPath = `file://${path_1.default.resolve(pluginConfig.path, 'index.html')}`; common_utils_1.logger.log(`Your HTML report is here: ${chalk_1.default.yellow(reportPath)}`); common_utils_1.logger.log(`To open it use: ${chalk_1.default.yellow('npx testplane gui')} or ${chalk_1.default.yellow(`npx http-server ${pluginConfig.path}`)}`); } exports.logPathToHtmlReport = logPathToHtmlReport; function logError(e) { common_utils_1.logger.error(`Html-reporter runtime error: ${e.stack}`); } exports.logError = logError; function prepareCommonJSData(data) { const stringifiedData = JSON.stringify(data, (_key, val) => { return typeof val === 'function' ? val.toString() : val; }); return [ `var data = ${stringifiedData};`, 'try { module.exports = data; } catch(e) {}' ].join('\n'); } exports.prepareCommonJSData = prepareCommonJSData; function shouldUpdateAttempt(status) { return ![constants_1.SKIPPED, constants_1.UPDATED, constants_1.RUNNING, constants_1.IDLE].includes(status); } exports.shouldUpdateAttempt = shouldUpdateAttempt; async function saveStaticFilesToReportDir(htmlReporter, pluginConfig, destPath) { const staticFolder = path_1.default.resolve(__dirname, './static'); await fs_extra_1.default.ensureDir(destPath); await Promise.all([ fs_extra_1.default.writeFile(path_1.default.resolve(destPath, DATA_FILE_NAME), prepareCommonJSData(getDataForStaticFile(htmlReporter, pluginConfig)), 'utf8'), copyToReportDir(destPath, ['report.min.js', 'report.min.css', 'newReport.min.js', 'newReport.min.css'], staticFolder), fs_extra_1.default.copy(path_1.default.resolve(staticFolder, 'index.html'), path_1.default.resolve(destPath, 'index.html')), fs_extra_1.default.copy(path_1.default.resolve(staticFolder, 'new-ui-report.html'), path_1.default.resolve(destPath, 'new-ui.html')), fs_extra_1.default.copy(path_1.default.resolve(staticFolder, 'icons'), path_1.default.resolve(destPath, 'icons')), fs_extra_1.default.copy(require.resolve('@gemini-testing/sql.js/dist/sql-wasm.js'), path_1.default.resolve(destPath, 'sql-wasm.js')), fs_extra_1.default.copy(require.resolve('@gemini-testing/sql.js/dist/sql-wasm.wasm'), path_1.default.resolve(destPath, 'sql-wasm.wasm')), copyPlugins(pluginConfig, destPath) ]); } exports.saveStaticFilesToReportDir = saveStaticFilesToReportDir; async function copyPlugins({ plugins, pluginsEnabled }, destPath) { if (!pluginsEnabled || !plugins?.length) { return; } try { const pluginsPath = path_1.default.resolve(destPath, 'plugins'); await fs_extra_1.default.ensureDir(pluginsPath); await Promise.all(mapPlugins(plugins, pluginName => copyPlugin(pluginName, pluginsPath))); } catch (e) { // eslint-disable-line @typescript-eslint/no-explicit-any logError(e); } } exports.copyPlugins = copyPlugins; async function copyPlugin(pluginName, pluginsPath) { const pluginPath = getPluginClientScriptPath(pluginName); if (!pluginPath) { return; } const destPluginPath = path_1.default.resolve(pluginsPath, pluginName, 'plugin.js'); await fs_extra_1.default.ensureDir(path_1.default.dirname(destPluginPath)); await fs_extra_1.default.copy(pluginPath, destPluginPath); } exports.copyPlugin = copyPlugin; function urlPathNameEndsWith(currentUrl, searchString) { try { return url_1.default.parse(currentUrl).pathname?.endsWith(searchString) || false; } catch (e) { return false; } } exports.urlPathNameEndsWith = urlPathNameEndsWith; function isJsonUrl(url) { return urlPathNameEndsWith(url, '.json'); } exports.isJsonUrl = isJsonUrl; function isDbFile(filePath) { return (0, common_utils_1.isUrl)(filePath) ? urlPathNameEndsWith(filePath, constants_1.DB_FILE_EXTENSION) : filePath.endsWith(constants_1.DB_FILE_EXTENSION); } exports.isDbFile = isDbFile; async function writeDatabaseUrlsFile(destPath, srcPaths) { const jsonUrls = srcPaths.filter(isJsonUrl); const dbUrls = srcPaths.filter(isDbFile); const data = { dbUrls, jsonUrls }; await fs_extra_1.default.writeJson(path_1.default.resolve(destPath, 'databaseUrls.json'), data); } exports.writeDatabaseUrlsFile = writeDatabaseUrlsFile; function copyToReportDir(destPath, files, sourceDirectory) { return Promise.all(files.map(fileName => { const from = path_1.default.resolve(sourceDirectory, fileName); const to = path_1.default.resolve(destPath, fileName); return fs_extra_1.default.copy(from, to); })); } exports.copyToReportDir = copyToReportDir; function getConfigForStaticFile(pluginConfig) { return lodash_1.default.pick(pluginConfig, [ 'defaultView', 'diffMode', 'baseHost', 'errorPatterns', 'metaInfoBaseUrls', 'customScripts', 'yandexMetrika', 'pluginsEnabled', 'plugins', 'staticImageAccepter', 'uiMode' ]); } exports.getConfigForStaticFile = getConfigForStaticFile; function getDataForStaticFile(htmlReporter, pluginConfig) { const timestamp = Date.now(); return { skips: [], config: getConfigForStaticFile(pluginConfig), apiValues: htmlReporter.values, timestamp, // TODO: remove in next major (should use timestamp instead) date: new Date(timestamp).toString() }; } exports.getDataForStaticFile = getDataForStaticFile; function getPluginClientScriptPath(pluginName) { try { return require.resolve(`${pluginName}/plugin.js`); } catch (e) { // eslint-disable-line @typescript-eslint/no-explicit-any logError(e); return null; } } exports.getPluginClientScriptPath = getPluginClientScriptPath; function getPluginMiddleware(pluginName) { try { return require(`${pluginName}/middleware.js`); } catch (e) { // eslint-disable-line @typescript-eslint/no-explicit-any if (e.code !== 'MODULE_NOT_FOUND') { logError(e); } return null; } } exports.getPluginMiddleware = getPluginMiddleware; function isUnexpectedPlugin(plugins, pluginName) { for (const { name } of plugins) { if (name === pluginName) { return false; } } return true; } exports.isUnexpectedPlugin = isUnexpectedPlugin; function forEachPlugin(plugins, callback) { const seen = new Set(); for (const plugin of plugins) { if (!seen.has(plugin.name)) { seen.add(plugin.name); callback(plugin.name); } } } exports.forEachPlugin = forEachPlugin; function mapPlugins(plugins, callback) { const result = []; forEachPlugin(plugins, pluginName => result.push(callback(pluginName))); return result; } exports.mapPlugins = mapPlugins; const formatTestResult = (rawResult, status, attempt = constants_1.UNKNOWN_ATTEMPT) => { return new testplane_1.TestplaneTestResultAdapter(rawResult, { attempt, status, duration: rawResult.duration }); }; exports.formatTestResult = formatTestResult; const saveErrorDetails = async (testResult, reportPath) => { if (!testResult.errorDetails) { return; } const detailsFilePath = path_1.default.resolve(reportPath, testResult.errorDetails.filePath); const detailsData = lodash_1.default.isObject(testResult.errorDetails.data) ? JSON.stringify(testResult.errorDetails.data, null, 2) : testResult.errorDetails.data; await makeDirFor(detailsFilePath); await fs_extra_1.default.writeFile(detailsFilePath, detailsData); }; exports.saveErrorDetails = saveErrorDetails; const getExpectedCacheKey = ([testResult, stateName]) => { const shortTestId = (0, common_utils_1.getShortMD5)((0, common_utils_1.mkTestId)(testResult.testPath.join(' '), testResult.browserId)); return shortTestId + '#' + stateName; }; exports.getExpectedCacheKey = getExpectedCacheKey; const getImagesInfoByStateName = (imagesInfo, stateName) => { return imagesInfo.find(imagesInfo => imagesInfo.stateName === stateName); }; exports.getImagesInfoByStateName = getImagesInfoByStateName; const getTimeTravelModeEnumSafe = () => { try { // eslint-disable-next-line @typescript-eslint/no-var-requires return require('testplane').TimeTravelMode; } catch { /* */ } return null; }; exports.getTimeTravelModeEnumSafe = getTimeTravelModeEnumSafe; //# sourceMappingURL=server-utils.js.map