@stryker-mutator/karma-runner
Version:
A plugin to use the karma test runner in Stryker, the JavaScript mutation testing framework
147 lines • 4.73 kB
JavaScript
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