@stryker-mutator/core
Version:
The extendable JavaScript mutation testing framework
158 lines • 7.2 kB
JavaScript
import { PluginKind } from '@stryker-mutator/api/plugin';
import { factory, testInjector } from '@stryker-mutator/test-helpers';
import { expect } from 'chai';
import sinon from 'sinon';
import { coreTokens, PluginCreator } from '../../../src/di/index.js';
import { BroadcastReporter } from '../../../src/reporters/broadcast-reporter.js';
describe(BroadcastReporter.name, () => {
let sut;
let rep1;
let rep2;
let isTTY;
let pluginCreatorMock;
beforeEach(() => {
captureTTY();
testInjector.options.reporters = ['rep1', 'rep2'];
rep1 = factory.reporter('rep1');
rep2 = factory.reporter('rep2');
pluginCreatorMock = sinon.createStubInstance(PluginCreator);
pluginCreatorMock.create.withArgs(PluginKind.Reporter, 'rep1').returns(rep1).withArgs(PluginKind.Reporter, 'rep2').returns(rep2);
});
afterEach(() => {
restoreTTY();
});
describe('when constructed', () => {
it('should create "progress-append-only" instead of "progress" reporter if process.stdout is not a tty', () => {
// Arrange
setTTY(false);
const expectedReporter = factory.reporter('progress-append-only');
testInjector.options.reporters = ['progress'];
pluginCreatorMock.create.returns(expectedReporter);
// Act
sut = createSut();
// Assert
expect(sut.reporters).deep.eq({ 'progress-append-only': expectedReporter });
sinon.assert.calledWith(pluginCreatorMock.create, PluginKind.Reporter, 'progress-append-only');
});
it('should create the correct reporters', () => {
// Arrange
setTTY(true);
testInjector.options.reporters = ['progress', 'rep2'];
const progress = factory.reporter('progress');
pluginCreatorMock.create.withArgs(PluginKind.Reporter, 'progress').returns(progress);
// Act
sut = createSut();
// Assert
expect(sut.reporters).deep.eq({
progress,
rep2,
});
});
it('should warn if there is no reporter', () => {
testInjector.options.reporters = [];
sut = createSut();
expect(testInjector.logger.warn).calledWith(sinon.match('No reporter configured'));
});
});
describe('with 2 reporters', () => {
beforeEach(() => {
sut = createSut();
});
it('should forward "onDryRunCompleted"', async () => {
await actAssertShouldForward('onDryRunCompleted', factory.dryRunCompletedEvent());
});
it('should forward "onMutationTestingPlanReady"', async () => {
await actAssertShouldForward('onMutationTestingPlanReady', factory.mutationTestingPlanReadyEvent());
});
it('should forward "onMutantTested"', async () => {
await actAssertShouldForward('onMutantTested', factory.mutantResult());
});
it('should forward "onMutationTestReportReady"', async () => {
await actAssertShouldForward('onMutationTestReportReady', factory.mutationTestReportSchemaMutationTestResult(), factory.mutationTestMetricsResult());
});
it('should forward "wrapUp"', async () => {
await actAssertShouldForward('wrapUp');
});
describe('when "wrapUp" returns promises', () => {
let wrapUpResolveFn;
let wrapUpResolveFn2;
let wrapUpRejectFn;
let result;
let isResolved;
beforeEach(() => {
isResolved = false;
rep1.wrapUp.returns(new Promise((resolve, reject) => {
wrapUpResolveFn = resolve;
wrapUpRejectFn = reject;
}));
rep2.wrapUp.returns(new Promise((resolve) => (wrapUpResolveFn2 = resolve)));
result = sut.wrapUp().then(() => void (isResolved = true));
});
it('should forward a combined promise', () => {
expect(isResolved).to.be.eq(false);
wrapUpResolveFn();
wrapUpResolveFn2();
return result;
});
describe('and one of the promises results in a rejection', () => {
let actualError;
beforeEach(() => {
actualError = new Error('some error');
wrapUpRejectFn(actualError);
wrapUpResolveFn2();
return result;
});
it('should not result in a rejection', () => result);
it('should log the error', () => {
expect(testInjector.logger.error).calledWith("An error occurred during 'wrapUp' on reporter 'rep1'.", actualError);
});
});
});
describe('with one faulty reporter', () => {
let actualError;
beforeEach(() => {
actualError = new Error('some error');
factory.ALL_REPORTER_EVENTS.forEach((eventName) => rep1[eventName].throws(actualError));
});
it('should still broadcast "onDryRunCompleted"', async () => {
await actAssertShouldForward('onDryRunCompleted', factory.dryRunCompletedEvent());
});
it('should still broadcast "onMutationTestingPlanReady"', async () => {
await actAssertShouldForward('onMutationTestingPlanReady', factory.mutationTestingPlanReadyEvent());
});
it('should still broadcast "onMutantTested"', async () => {
await actAssertShouldForward('onMutantTested', factory.mutantResult());
});
it('should still broadcast "onMutationTestReportReady"', async () => {
await actAssertShouldForward('onMutationTestReportReady', factory.mutationTestReportSchemaMutationTestResult(), factory.mutationTestMetricsResult());
});
it('should still broadcast "wrapUp"', async () => {
await actAssertShouldForward('wrapUp');
});
it('should log each error', () => {
factory.ALL_REPORTER_EVENTS.forEach((eventName) => {
sut[eventName]();
expect(testInjector.logger.error).to.have.been.calledWith(`An error occurred during '${eventName}' on reporter 'rep1'.`, actualError);
});
});
});
});
function createSut() {
return testInjector.injector.provideValue(coreTokens.pluginCreator, pluginCreatorMock).injectClass(BroadcastReporter);
}
function captureTTY() {
isTTY = process.stdout.isTTY;
}
function restoreTTY() {
process.stdout.isTTY = isTTY;
}
function setTTY(val) {
process.stdout.isTTY = val;
}
async function actAssertShouldForward(method, ...input) {
await sut[method](...input);
expect(rep1[method]).calledWithExactly(...input);
expect(rep2[method]).calledWithExactly(...input);
}
});
//# sourceMappingURL=broadcast-reporter.spec.js.map