@stryker-mutator/core
Version:
The extendable JavaScript mutation testing framework
145 lines • 7.68 kB
JavaScript
import path from 'path';
import sinon from 'sinon';
import { expect } from 'chai';
import { testInjector, factory } from '@stryker-mutator/test-helpers';
import { PrepareExecutor } from '../../../src/process/index.js';
import { coreTokens, PluginLoader } from '../../../src/di/index.js';
import { LogConfigurator } from '../../../src/logging/index.js';
import { Project, ProjectReader } from '../../../src/fs/index.js';
import { TemporaryDirectory } from '../../../src/utils/temporary-directory.js';
import { ConfigError } from '../../../src/errors.js';
import { ConfigReader, OptionsValidator, MetaSchemaBuilder } from '../../../src/config/index.js';
import { BroadcastReporter, reporterPluginsFileUrl } from '../../../src/reporters/index.js';
import { UnexpectedExitHandler } from '../../../src/unexpected-exit-handler.js';
import { FileSystemTestDouble } from '../../helpers/file-system-test-double.js';
describe(PrepareExecutor.name, () => {
let cliOptions;
let configReaderMock;
let pluginLoaderMock;
let metaSchemaBuilderMock;
let configureMainProcessStub;
let optionsValidatorMock;
let configureLoggingServerStub;
let injectorMock;
let projectReaderMock;
let project;
let temporaryDirectoryMock;
let loadedPlugins;
let sut;
beforeEach(() => {
const fsTestDouble = new FileSystemTestDouble({ 'index.js': 'console.log("hello world");' });
project = new Project(fsTestDouble, fsTestDouble.toFileDescriptions());
cliOptions = {};
configReaderMock = sinon.createStubInstance(ConfigReader);
configReaderMock.readConfig.resolves(testInjector.options);
metaSchemaBuilderMock = sinon.createStubInstance(MetaSchemaBuilder);
configureMainProcessStub = sinon.stub(LogConfigurator, 'configureMainProcess');
pluginLoaderMock = sinon.createStubInstance(PluginLoader);
loadedPlugins = { pluginModulePaths: [], pluginsByKind: new Map(), schemaContributions: [] };
pluginLoaderMock.load.resolves(loadedPlugins);
temporaryDirectoryMock = sinon.createStubInstance(TemporaryDirectory);
projectReaderMock = sinon.createStubInstance(ProjectReader);
optionsValidatorMock = sinon.createStubInstance(OptionsValidator);
configureLoggingServerStub = sinon.stub(LogConfigurator, 'configureLoggingServer');
injectorMock = factory.injector();
injectorMock.resolve.withArgs(coreTokens.temporaryDirectory).returns(temporaryDirectoryMock);
injectorMock.injectClass
.withArgs(PluginLoader)
.returns(pluginLoaderMock)
.withArgs(OptionsValidator)
.returns(optionsValidatorMock)
.withArgs(MetaSchemaBuilder)
.returns(metaSchemaBuilderMock)
.withArgs(ConfigReader)
.returns(configReaderMock)
.withArgs(ProjectReader)
.returns(projectReaderMock);
projectReaderMock.read.resolves(project);
sut = new PrepareExecutor(injectorMock);
});
it('should provide the cliOptions to the config reader', async () => {
await sut.execute(cliOptions);
expect(configReaderMock.readConfig).calledWithExactly(cliOptions);
});
it('should load the plugins', async () => {
// Arrange
testInjector.options.appendPlugins = ['appended'];
testInjector.options.plugins = ['@stryker-mutator/*', './my-custom-plugin.js'];
// Act
await sut.execute(cliOptions);
// Assert
sinon.assert.calledWithExactly(pluginLoaderMock.load, ['@stryker-mutator/*', './my-custom-plugin.js', reporterPluginsFileUrl, 'appended']);
});
it('should provided the loaded modules as pluginModulePaths', async () => {
// Arrange
const expectedPluginPaths = ['@stryker-mutator/core', path.resolve('./my-custom-plugin.js'), 'appended'];
loadedPlugins.pluginModulePaths.push(...expectedPluginPaths);
// Act
await sut.execute(cliOptions);
// Assert
sinon.assert.calledWithExactly(injectorMock.provideValue, coreTokens.pluginModulePaths, expectedPluginPaths);
});
it('should validate final options with the meta schema', async () => {
// Arrange
const contributions = [{ some: 'schema contributions' }];
const metaSchema = { properties: { meta: { $comment: 'schema' } } };
loadedPlugins.schemaContributions.push(...contributions);
metaSchemaBuilderMock.buildMetaSchema.returns(metaSchema);
// Act
await sut.execute(cliOptions);
// Assert
sinon.assert.calledWithExactly(metaSchemaBuilderMock.buildMetaSchema, contributions);
sinon.assert.calledWithExactly(injectorMock.provideValue, coreTokens.validationSchema, metaSchema);
sinon.assert.calledWithExactly(optionsValidatorMock.validate, testInjector.options, true);
});
it('should configure logging for the main process', async () => {
await sut.execute(cliOptions);
expect(configureMainProcessStub).calledOnce;
});
it('should configure the logging server', async () => {
const expectedLoggingContext = {
level: "fatal" /* LogLevel.Fatal */,
port: 1337,
};
configureLoggingServerStub.resolves(expectedLoggingContext);
testInjector.options.logLevel = "info" /* LogLevel.Information */;
testInjector.options.fileLogLevel = "trace" /* LogLevel.Trace */;
testInjector.options.allowConsoleColors = true;
await sut.execute(cliOptions);
expect(configureLoggingServerStub).calledWithExactly("info" /* LogLevel.Information */, "trace" /* LogLevel.Trace */, true);
expect(injectorMock.provideValue).calledWithExactly(coreTokens.loggingContext, expectedLoggingContext);
});
it('should resolve input files', async () => {
await sut.execute(cliOptions);
expect(projectReaderMock.read).called;
expect(injectorMock.provideValue).calledWithExactly(coreTokens.project, project);
});
it('should provide the reporter the reporter', async () => {
await sut.execute(cliOptions);
sinon.assert.calledWithExactly(injectorMock.provideClass, coreTokens.reporter, BroadcastReporter);
});
it('should provide the UnexpectedExitRegister', async () => {
await sut.execute(cliOptions);
sinon.assert.calledWithExactly(injectorMock.provideClass, coreTokens.unexpectedExitRegistry, UnexpectedExitHandler);
});
it('should reject when logging server rejects', async () => {
const expectedError = Error('expected error');
configureLoggingServerStub.rejects(expectedError);
await expect(sut.execute(cliOptions)).rejectedWith(expectedError);
});
it('should reject when input file globbing results in a rejection', async () => {
const expectedError = Error('expected error');
projectReaderMock.read.rejects(expectedError);
await expect(sut.execute(cliOptions)).rejectedWith(expectedError);
});
it('should reject when no input files where found', async () => {
projectReaderMock.read.resolves(new Project(new FileSystemTestDouble(), {}));
await expect(sut.execute(cliOptions)).rejectedWith(ConfigError, 'No input files found');
});
it('should not create the temp directory when no input files where found', async () => {
projectReaderMock.read.resolves(new Project(new FileSystemTestDouble(), {}));
await expect(sut.execute(cliOptions)).rejected;
expect(temporaryDirectoryMock.initialize).not.called;
});
});
//# sourceMappingURL=1-prepare-executor.spec.js.map