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
JavaScript
;
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