UNPKG

@stryker-mutator/karma-runner

Version:

A plugin to use the karma test runner in Stryker, the JavaScript mutation testing framework

136 lines 4.57 kB
import { determineHitLimitReached, DryRunStatus, TestStatus } from '@stryker-mutator/api/test-runner'; import { Task } from '@stryker-mutator/util'; export function strykerReporterFactory(karmaServer, config) { StrykerReporter.instance.karmaServer = karmaServer; StrykerReporter.instance.karmaConfig = config; return StrykerReporter.instance; } strykerReporterFactory.$inject = ['server', 'config']; /** * This is a singleton implementation of a KarmaReporter. * It is loaded by karma and functions as a bridge between the karma world and the stryker world * * It uses properties as functions because karma is not able to find actual methods. * * i.e. use `public readonly onFoo = () => {}` instead of `onFoo() { }`. */ export class StrykerReporter { adapters = []; karmaServer; karmaConfig; runResultHandler; testResults = []; errorMessage; mutantCoverage; hitCount; hitLimit; initTask; runTask; karmaRunResult; browserIsRestarting = false; static _instance = new StrykerReporter(); static get instance() { return this._instance; } onBrowsersReady = () => { this.initTask?.resolve(); this.runTask?.resolve(this.collectRunResult()); }; configureHitLimit(hitLimit) { this.hitLimit = hitLimit; this.hitCount = undefined; } whenBrowsersReady() { this.initTask = new Task(); return this.initTask.promise.finally(() => { this.initTask = undefined; }); } whenRunCompletes() { this.runTask = new Task(); return this.runTask.promise.finally(() => { this.runTask = undefined; }); } onSpecComplete = (_browser, spec) => { const name = spec.suite.reduce((specName, suite) => specName + suite + ' ', '') + spec.description; const id = spec.id || name; if (spec.skipped) { this.testResults.push({ id, name, timeSpentMs: spec.time, status: TestStatus.Skipped, }); } else if (spec.success) { this.testResults.push({ id, name, timeSpentMs: spec.time, status: TestStatus.Success, }); } else { this.testResults.push({ id, name, timeSpentMs: spec.time, status: TestStatus.Failed, failureMessage: spec.log.join(', '), }); } }; onRunStart = () => { this.testResults = []; this.errorMessage = undefined; this.mutantCoverage = undefined; this.karmaRunResult = undefined; this.browserIsRestarting = false; }; onRunComplete = (_browsers, runResult) => { this.karmaRunResult = runResult; if (!this.browserIsRestarting) { this.runTask.resolve(this.collectRunResult()); } }; onBrowserComplete = (_browser, result) => { this.mutantCoverage = result.mutantCoverage; this.hitCount = result.hitCount; }; onBrowserError = (browser, error) => { if (this.initTask) { this.initTask.reject(error); } else { if (browser.state.toUpperCase().includes('DISCONNECTED')) { // Restart the browser for next run this.karmaServer.get('launcher').restart(browser.id); this.browserIsRestarting = true; } // Karma 2.0 has different error messages if (error.message) { this.errorMessage = error.message; } else { this.errorMessage = error.toString(); } } }; collectRunResult() { const timeoutResult = determineHitLimitReached(this.hitCount, this.hitLimit); if (timeoutResult) { return timeoutResult; } if (this.karmaRunResult?.disconnected) { return { status: DryRunStatus.Timeout, reason: `Browser disconnected during test execution. Karma error: ${this.errorMessage}` }; } else if (this.karmaRunResult?.error) { return { status: DryRunStatus.Error, errorMessage: this.errorMessage ?? 'A runtime error occurred' }; } else { return { status: DryRunStatus.Complete, tests: this.testResults, mutantCoverage: this.mutantCoverage }; } } } //# sourceMappingURL=stryker-reporter.js.map