UNPKG

testplane

Version:

Tests framework based on mocha and wdio

234 lines 11 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SelectivityRunner = void 0; const lodash_1 = __importDefault(require("lodash")); const fs_extra_1 = __importDefault(require("fs-extra")); const p_limit_1 = __importDefault(require("p-limit")); const logger = __importStar(require("../../../utils/logger")); const debug_1 = require("./debug"); const hash_reader_1 = require("./hash-reader"); const events_1 = require("../../../events"); const hash_writer_1 = require("./hash-writer"); const test_dependencies_reader_1 = require("./test-dependencies-reader"); const modes_1 = require("./modes"); const used_dumps_tracker_1 = require("./used-dumps-tracker"); const utils_1 = require("./utils"); /** Called at the start of testplane run per each browser */ const shouldDisableBrowserSelectivity = lodash_1.default.memoize(async (config, browserId) => { if (!(0, modes_1.selectivityShouldRead)(config.selectivity.enabled)) { return true; } if (config.lastFailed.only) { if (!config.selectivity.saveIncompleteDumpOnFail) { logger.warn(`Disabling selectivity for ${browserId}: lastFailedOnly mode is enabled`); } else { (0, debug_1.debugSelectivity)(`Not skipping tests for ${browserId}: lastFailedOnly mode controls it`); } return true; } if (!config.selectivity.disableSelectivityPatterns.length) { return false; } const hashReader = (0, hash_reader_1.getHashReader)(config.selectivity.testDependenciesPath, config.selectivity.compression); return new Promise(resolve => { let isSettled = false; Promise.all(config.selectivity.disableSelectivityPatterns.map(pattern => { return hashReader .patternHasChanged(pattern) .then(hasChanged => { if (hasChanged && !isSettled) { isSettled = true; (0, debug_1.debugSelectivity)(`Disabling selectivity for ${browserId}: file change by pattern "${pattern}" is detected`); resolve(true); } }) .catch(err => { if (!isSettled) { isSettled = true; (0, debug_1.debugSelectivity)(`Disabling selectivity for ${browserId}: got an error while checking 'disableSelectivityPatterns': %O`, err); resolve(true); } }); })).then(() => { if (!isSettled) { (0, debug_1.debugSelectivity)(`None of 'disableSelectivityPatterns' is changed for ${browserId}`); resolve(false); } }); }); }, config => { const { enabled, testDependenciesPath, compression, disableSelectivityPatterns } = config.selectivity; const lastFailed = config.lastFailed.only; return (0, modes_1.selectivityShouldRead)(enabled) ? lastFailed + "#" + testDependenciesPath + "#" + compression + "#" + disableSelectivityPatterns.join("#") : ""; }); const shouldDisableTestBySelectivity = lodash_1.default.memoize(async (config, test) => { const { enabled, testDependenciesPath, compression } = config.selectivity; if (!(0, modes_1.selectivityShouldRead)(enabled)) { return false; } const testDepsReader = (0, test_dependencies_reader_1.getTestDependenciesReader)(testDependenciesPath, compression); const hashReader = (0, hash_reader_1.getHashReader)(testDependenciesPath, compression); const testDeps = await testDepsReader.getFor(test); if (!testDeps.js.length) { (0, debug_1.debugSelectivity)(`Not disabling "${test.fullTitle()}" as it has no js deps and therefore it was considered as new`); return false; } const changedDeps = await hashReader.getTestChangedDeps(testDeps); if (changedDeps) { (0, debug_1.debugSelectivity)(`Not disabling "${test.fullTitle()}" as its dependencies were changed: %O`, changedDeps); } else { (0, debug_1.debugSelectivity)(`Disabling "${test.fullTitle()}" as its dependencies were not changed`); } return !changedDeps; }, (config, test) => { const { enabled, testDependenciesPath, compression } = config.selectivity; return (0, modes_1.selectivityShouldRead)(enabled) ? testDependenciesPath + "#" + compression + "#" + test.id : ""; }); const onTestDependencies = (context, data) => { const hashWriter = (0, hash_writer_1.getHashWriter)(context.testDependenciesPath, context.compression); hashWriter.addTestDependencyHashes(data); }; class SelectivityRunner { static create(...args) { return new this(...args); } constructor(mainRunner, config, runTestFn, opts) { this._browserSelectivityDisabledCache = {}; this._testsToRun = []; this._processingTestLimit = (0, p_limit_1.default)(16); this._processingTestPromises = []; this._stats = {}; this._usedDumpsTracker = (0, used_dumps_tracker_1.getUsedDumpsTracker)(); this._config = config; this._runTestFn = runTestFn; this._opts = opts; if (this._opts?.shouldDisableSelectivity) { (0, debug_1.debugSelectivity)("Test filter is specified, disabling selectivity"); } else { mainRunner.on(events_1.MasterEvents.TEST_DEPENDENCIES, onTestDependencies); } } _shouldDisableSelectivityForBrowser(browserId) { if (this._browserSelectivityDisabledCache[browserId]) { return this._browserSelectivityDisabledCache[browserId]; } const browserConfig = this._config.forBrowser(browserId); this._browserSelectivityDisabledCache[browserId] = shouldDisableBrowserSelectivity(browserConfig, browserId); return this._browserSelectivityDisabledCache[browserId]; } startTestCheckToRun(test, browserId) { const browserConfig = this._config.forBrowser(browserId); const shouldSelectivelySkipTests = (0, modes_1.selectivityShouldRead)(browserConfig.selectivity.enabled); const shouldUpdateSelectivityState = (0, modes_1.selectivityShouldWrite)(browserConfig.selectivity.enabled); if (this._opts?.shouldDisableSelectivity || test.disabled) { this._testsToRun.push([test, browserId]); return; } if (shouldUpdateSelectivityState) { this._usedDumpsTracker.trackUsed((0, utils_1.getTestSelectivityDumpId)(test), browserConfig.selectivity.testDependenciesPath); } if (!shouldSelectivelySkipTests) { this._testsToRun.push([test, browserId]); return; } this._processingTestPromises.push(this._processingTestLimit(async () => { const shouldDisableBrowserSelectivity = await this._shouldDisableSelectivityForBrowser(browserId); if (shouldDisableBrowserSelectivity) { this._testsToRun.push([test, browserId]); return; } this._stats[browserId] ||= { processedCount: 0, skippedCount: 0, }; this._stats[browserId].processedCount++; const shouldDisableTest = await shouldDisableTestBySelectivity(browserConfig, test); if (!shouldDisableTest) { this._testsToRun.push([test, browserId]); } else { this._stats[browserId].skippedCount++; } })); } async runNecessaryTests() { await Promise.all(this._processingTestPromises); const saveReportPromise = this._saveSelectivityReport().catch(reason => { logger.error("Couldn't save selectivity report. Reason:", reason); }); this._testsToRun.forEach(([test, browserId]) => { this._runTestFn(test, browserId); }); // Free used memory this._processingTestPromises.length = 0; this._testsToRun.length = 0; shouldDisableBrowserSelectivity.cache.clear?.(); shouldDisableTestBySelectivity.cache.clear?.(); this._config.getBrowserIds().forEach(browserId => { const { selectivity } = this._config.forBrowser(browserId); (0, hash_reader_1.getHashReader)(selectivity.testDependenciesPath, selectivity.compression).clearCache(); }); await saveReportPromise; } async _saveSelectivityReport() { const browserReportPaths = Object.keys(this._stats).reduce((acc, browserId) => { const reportPath = process.env.TESTPLANE_SELECTIVITY_REPORT_PATH || this._config.forBrowser(browserId).selectivity.reportPath; if (reportPath) { acc[reportPath] ||= []; acc[reportPath].push(browserId); } return acc; }, {}); const promises = await Promise.allSettled(Object.keys(browserReportPaths).map(async (reportPath) => { const report = { totalProcessedCount: 0, totalSkippedCount: 0, perBrowserStats: {}, }; for (const browserId of browserReportPaths[reportPath]) { report.totalProcessedCount += this._stats[browserId].processedCount; report.totalSkippedCount += this._stats[browserId].skippedCount; report.perBrowserStats[browserId] = this._stats[browserId]; } await fs_extra_1.default.outputJson(reportPath, report, { spaces: 4 }); })); const failedPromise = promises.find(promise => promise.status === "rejected"); if (failedPromise && "reason" in failedPromise) { throw failedPromise.reason; } } } exports.SelectivityRunner = SelectivityRunner; //# sourceMappingURL=runner.js.map