@stryker-mutator/core
Version:
The extendable JavaScript mutation testing framework
184 lines • 7.9 kB
JavaScript
import childProcess from 'child_process';
import { promises as fsPromises } from 'fs';
import { commonTokens, tokens } from '@stryker-mutator/api/plugin';
import { notEmpty } from '@stryker-mutator/util';
import { initializerTokens } from './index.js';
export class StrykerInitializer {
log;
out;
client;
customInitializers;
configWriter;
gitignoreWriter;
inquirer;
static inject = tokens(commonTokens.logger, initializerTokens.out, initializerTokens.npmClient, initializerTokens.customInitializers, initializerTokens.configWriter, initializerTokens.gitignoreWriter, initializerTokens.inquirer);
constructor(log, out, client, customInitializers, configWriter, gitignoreWriter, inquirer) {
this.log = log;
this.out = out;
this.client = client;
this.customInitializers = customInitializers;
this.configWriter = configWriter;
this.gitignoreWriter = gitignoreWriter;
this.inquirer = inquirer;
}
/**
* Runs the initializer will prompt the user for questions about his setup. After that, install plugins and configure Stryker.
* @function
*/
async initialize() {
await this.configWriter.guardForExistingConfig();
this.patchProxies();
const selectedPreset = await this.selectCustomInitializer();
let configFileName;
if (selectedPreset) {
configFileName = await this.initiateInitializer(this.configWriter, selectedPreset);
}
else {
configFileName = await this.initiateCustom(this.configWriter);
}
await this.gitignoreWriter.addStrykerTempFolder();
this.out(`Done configuring stryker. Please review "${configFileName}", you might need to configure your test runner correctly.`);
this.out("Let's kill some mutants with this command: `stryker run`");
}
/**
* The typed rest client works only with the specific HTTP_PROXY and HTTPS_PROXY env settings.
* Let's make sure they are available.
*/
patchProxies() {
const copyEnvVariable = (from, to) => {
if (process.env[from] && !process.env[to]) {
process.env[to] = process.env[from];
}
};
copyEnvVariable('http_proxy', 'HTTP_PROXY');
copyEnvVariable('https_proxy', 'HTTPS_PROXY');
}
async selectCustomInitializer() {
const customInitializer = this.customInitializers;
if (customInitializer.length) {
this.log.debug(`Found presets: ${JSON.stringify(customInitializer)}`);
return this.inquirer.promptPresets(customInitializer);
}
else {
this.log.debug('No presets have been configured, reverting to custom configuration');
return undefined;
}
}
async initiateInitializer(configWriter, selectedPreset) {
const presetConfig = await selectedPreset.createConfig();
const isJsonSelected = await this.selectJsonConfigType();
const configFileName = await configWriter.writeCustomInitializer(presetConfig, isJsonSelected);
if (presetConfig.additionalConfigFiles) {
await Promise.all(Object.entries(presetConfig.additionalConfigFiles).map(([name, content]) => fsPromises.writeFile(name, content)));
}
const selectedPackageManager = await this.selectPackageManager();
this.installNpmDependencies(this.ensureCoreDependencyIncluded(presetConfig.dependencies), selectedPackageManager);
return configFileName;
}
async initiateCustom(configWriter) {
const selectedTestRunner = await this.selectTestRunner();
const buildCommand = await this.getBuildCommand(selectedTestRunner);
const selectedReporters = await this.selectReporters();
const selectedPackageManager = await this.selectPackageManager();
const isJsonSelected = await this.selectJsonConfigType();
const npmDependencies = this.getSelectedNpmDependencies([selectedTestRunner].concat(selectedReporters));
const packageInfo = await this.fetchAdditionalConfig(npmDependencies);
const pkgInfoOfSelectedTestRunner = packageInfo.find((pkg) => pkg.name == selectedTestRunner.pkg?.name);
const additionalConfig = packageInfo
.map((dep) => dep.initStrykerConfig ?? {})
.filter(notEmpty);
const configFileName = await configWriter.write(selectedTestRunner, buildCommand, selectedReporters, selectedPackageManager, npmDependencies.map((pkg) => pkg.name), additionalConfig, pkgInfoOfSelectedTestRunner?.homepage ??
"(missing 'homepage' URL in package.json)", isJsonSelected);
this.installNpmDependencies(this.ensureCoreDependencyIncluded(npmDependencies.map((pkg) => pkg.name)), selectedPackageManager);
return configFileName;
}
async selectTestRunner() {
const testRunnerOptions = await this.client.getTestRunnerOptions();
this.log.debug(`Found test runners: ${JSON.stringify(testRunnerOptions)}`);
return this.inquirer.promptTestRunners(testRunnerOptions);
}
async getBuildCommand(selectedTestRunner) {
if (selectedTestRunner.name !== 'jest') {
return this.inquirer.promptBuildCommand();
}
return { name: '', pkg: null };
}
async selectReporters() {
const reporterOptions = await this.client.getTestReporterOptions();
reporterOptions.push({
name: 'html',
pkg: null,
}, {
name: 'clear-text',
pkg: null,
}, {
name: 'progress',
pkg: null,
}, {
name: 'dashboard',
pkg: null,
});
return this.inquirer.promptReporters(reporterOptions);
}
async selectPackageManager() {
return this.inquirer.promptPackageManager([
{
name: "npm" /* PackageManager.Npm */,
pkg: null,
},
{
name: "yarn" /* PackageManager.Yarn */,
pkg: null,
},
{
name: "pnpm" /* PackageManager.Pnpm */,
pkg: null,
},
]);
}
async selectJsonConfigType() {
return this.inquirer.promptJsonConfigFormat();
}
getSelectedNpmDependencies(selectedOptions) {
return selectedOptions
.filter(notEmpty)
.map((option) => option.pkg)
.filter(notEmpty);
}
/**
* Install the npm packages
* @function
*/
installNpmDependencies(dependencies, selectedOption) {
if (dependencies.length === 0) {
return;
}
const dependencyArg = dependencies.join(' ');
this.out('Installing NPM dependencies...');
const cmd = this.getInstallCommand(selectedOption.name, dependencyArg);
this.out(cmd);
try {
childProcess.execSync(cmd, { stdio: [0, 1, 2] });
}
catch {
this.out(`An error occurred during installation, please try it yourself: "${cmd}"`);
}
}
getInstallCommand(packageManager, dependencyArg) {
switch (packageManager) {
case "yarn" /* PackageManager.Yarn */:
return `yarn add ${dependencyArg} --dev`;
case "pnpm" /* PackageManager.Pnpm */:
return `pnpm add -D ${dependencyArg}`;
case "npm" /* PackageManager.Npm */:
return `npm i --save-dev ${dependencyArg}`;
}
}
async fetchAdditionalConfig(dependencies) {
return await Promise.all(dependencies.map((dep) => this.client.getAdditionalConfig(dep)));
}
ensureCoreDependencyIncluded(dependencies) {
return Array.from(new Set(['@stryker-mutator/core', ...dependencies]));
}
}
//# sourceMappingURL=stryker-initializer.js.map