UNPKG

stryker

Version:
184 lines 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var os_1 = require("os"); var test_runner_1 = require("stryker-api/test_runner"); var Sandbox_1 = require("../Sandbox"); var CoverageInstrumenterTranspiler_1 = require("../transpiler/CoverageInstrumenterTranspiler"); var SourceMapper_1 = require("../transpiler/SourceMapper"); var coverageHooks_1 = require("../transpiler/coverageHooks"); var plugin_1 = require("stryker-api/plugin"); var di_1 = require("../di"); // The initial run might take a while. // For example: angular-bootstrap takes up to 45 seconds. // Lets take 5 minutes just to be sure var INITIAL_RUN_TIMEOUT = 60 * 1000 * 5; var INITIAL_TEST_RUN_MARKER = 'Initial test run'; var InitialTestExecutor = /** @class */ (function () { function InitialTestExecutor(options, log, inputFiles, testFramework, timer, loggingContext, transpiler) { this.options = options; this.log = log; this.inputFiles = inputFiles; this.testFramework = testFramework; this.timer = timer; this.loggingContext = loggingContext; this.transpiler = transpiler; } InitialTestExecutor.prototype.run = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var transpiledFiles, sourceMapper, _a, coverageMaps, instrumentedFiles, _b, runResult, grossTimeMS, timing; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: this.log.info('Starting initial test run. This may take a while.'); return [4 /*yield*/, this.transpiler.transpile(this.inputFiles.files)]; case 1: transpiledFiles = _c.sent(); sourceMapper = SourceMapper_1.default.create(transpiledFiles, this.options); return [4 /*yield*/, this.annotateForCodeCoverage(transpiledFiles, sourceMapper)]; case 2: _a = _c.sent(), coverageMaps = _a.coverageMaps, instrumentedFiles = _a.instrumentedFiles; this.logTranspileResult(instrumentedFiles); return [4 /*yield*/, this.runInSandbox(instrumentedFiles)]; case 3: _b = _c.sent(), runResult = _b.runResult, grossTimeMS = _b.grossTimeMS; timing = this.calculateTiming(grossTimeMS, runResult.tests); this.validateResult(runResult, timing); return [2 /*return*/, { coverageMaps: coverageMaps, overheadTimeMS: timing.overhead, runResult: runResult, sourceMapper: sourceMapper }]; } }); }); }; InitialTestExecutor.prototype.runInSandbox = function (files) { return tslib_1.__awaiter(this, void 0, void 0, function () { var sandbox, runResult, grossTimeMS; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Sandbox_1.default.create(this.options, 0, files, this.testFramework, 0, this.loggingContext)]; case 1: sandbox = _a.sent(); this.timer.mark(INITIAL_TEST_RUN_MARKER); return [4 /*yield*/, sandbox.run(INITIAL_RUN_TIMEOUT, this.getCollectCoverageHooksIfNeeded())]; case 2: runResult = _a.sent(); grossTimeMS = this.timer.elapsedMs(INITIAL_TEST_RUN_MARKER); return [4 /*yield*/, sandbox.dispose()]; case 3: _a.sent(); return [2 /*return*/, { runResult: runResult, grossTimeMS: grossTimeMS }]; } }); }); }; InitialTestExecutor.prototype.annotateForCodeCoverage = function (files, sourceMapper) { return tslib_1.__awaiter(this, void 0, void 0, function () { var filesToInstrument, coverageInstrumenterTranspiler, instrumentedFiles; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: filesToInstrument = this.inputFiles.filesToMutate.map(function (mutateFile) { return sourceMapper.transpiledFileNameFor(mutateFile.name); }); coverageInstrumenterTranspiler = new CoverageInstrumenterTranspiler_1.default(this.options, filesToInstrument); return [4 /*yield*/, coverageInstrumenterTranspiler.transpile(files)]; case 1: instrumentedFiles = _a.sent(); return [2 /*return*/, { coverageMaps: coverageInstrumenterTranspiler.fileCoverageMaps, instrumentedFiles: instrumentedFiles }]; } }); }); }; InitialTestExecutor.prototype.validateResult = function (runResult, timing) { switch (runResult.status) { case test_runner_1.RunStatus.Complete: var failedTests = this.filterOutFailedTests(runResult); if (failedTests.length) { this.logFailedTestsInInitialRun(failedTests); throw new Error('There were failed tests in the initial test run.'); } if (runResult.tests.length === 0) { this.log.warn('No tests were executed. Stryker will exit prematurely. Please check your configuration.'); return; } else { this.logInitialTestRunSucceeded(runResult.tests, timing); return; } case test_runner_1.RunStatus.Error: this.logErrorsInInitialRun(runResult); break; case test_runner_1.RunStatus.Timeout: this.logTimeoutInitialRun(runResult); break; } throw new Error('Something went wrong in the initial test run'); }; /** * Calculates the timing variables for the test run. * grossTime = NetTime + overheadTime * * The overhead time is used to calculate exact timeout values during mutation testing. * See timeoutMS setting in README for more information on this calculation */ InitialTestExecutor.prototype.calculateTiming = function (grossTimeMS, tests) { var netTimeMS = tests.reduce(function (total, test) { return total + test.timeSpentMs; }, 0); var overheadTimeMS = grossTimeMS - netTimeMS; return { net: netTimeMS, overhead: overheadTimeMS < 0 ? 0 : overheadTimeMS }; }; InitialTestExecutor.prototype.getCollectCoverageHooksIfNeeded = function () { if (this.options.coverageAnalysis === 'perTest') { if (this.testFramework) { // Add piece of javascript to collect coverage per test results this.log.debug("Adding test hooks for coverageAnalysis \"perTest\"."); return coverageHooks_1.coveragePerTestHooks(this.testFramework); } else { this.log.warn('Cannot measure coverage results per test, there is no testFramework and thus no way of executing code right before and after each test.'); } } return undefined; }; InitialTestExecutor.prototype.logTranspileResult = function (transpiledFiles) { if (this.options.transpilers.length && this.log.isDebugEnabled()) { this.log.debug("Transpiled files: " + JSON.stringify(transpiledFiles.map(function (f) { return "" + f.name; }), null, 2)); } }; InitialTestExecutor.prototype.filterOutFailedTests = function (runResult) { return runResult.tests.filter(function (testResult) { return testResult.status === test_runner_1.TestStatus.Failed; }); }; InitialTestExecutor.prototype.logInitialTestRunSucceeded = function (tests, timing) { this.log.info('Initial test run succeeded. Ran %s tests in %s (net %s ms, overhead %s ms).', tests.length, this.timer.humanReadableElapsed(), timing.net, timing.overhead); }; InitialTestExecutor.prototype.logFailedTestsInInitialRun = function (failedTests) { var message = 'One or more tests failed in the initial test run:'; failedTests.forEach(function (test) { message += os_1.EOL + "\t" + test.name; if (test.failureMessages && test.failureMessages.length) { message += os_1.EOL + "\t\t" + test.failureMessages.join(os_1.EOL + "\t\t"); } }); this.log.error(message); }; InitialTestExecutor.prototype.logErrorsInInitialRun = function (runResult) { var message = 'One or more tests resulted in an error:'; if (runResult.errorMessages && runResult.errorMessages.length) { runResult.errorMessages.forEach(function (error) { return message += os_1.EOL + "\t" + error; }); } this.log.error(message); }; InitialTestExecutor.prototype.logTimeoutInitialRun = function (runResult) { var message = 'Initial test run timed out! Ran following tests before timeout:'; runResult.tests.forEach(function (test) { return message += os_1.EOL + "\t" + test.name + " (" + test_runner_1.TestStatus[test.status] + ")"; }); this.log.error(message); }; InitialTestExecutor.inject = plugin_1.tokens(plugin_1.commonTokens.options, plugin_1.commonTokens.logger, di_1.coreTokens.inputFiles, di_1.coreTokens.testFramework, di_1.coreTokens.timer, di_1.coreTokens.loggingContext, di_1.coreTokens.transpiler); return InitialTestExecutor; }()); exports.default = InitialTestExecutor; //# sourceMappingURL=InitialTestExecutor.js.map