Skip to content

Commit

Permalink
fix(presets): update init templates for 4.0 release (#2526)
Browse files Browse the repository at this point in the history
* Update the vuejs, react, angular and vue presets for the 4.0 release.
* Remove `@stryker-mutator/core` from presets
  • Loading branch information
nicojs authored Oct 7, 2020
1 parent 389d9f8 commit ec0d75e
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 137 deletions.
10 changes: 5 additions & 5 deletions packages/core/src/initializer/StrykerConfigWriter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { existsSync, promises as fs } from 'fs';

import { StrykerOptions } from '@stryker-mutator/api/core';
import { PartialStrykerOptions, StrykerOptions } from '@stryker-mutator/api/core';
import { Logger } from '@stryker-mutator/api/logging';
import { commonTokens, tokens } from '@stryker-mutator/api/plugin';
import { childProcessAsPromised } from '@stryker-mutator/util';
Expand Down Expand Up @@ -60,22 +60,22 @@ export default class StrykerConfigWriter {
*/
public async writePreset(presetConfig: PresetConfiguration, exportAsJson: boolean) {
const config = {
comment: `This config was generated using a preset. Please see the handbook for more information: ${presetConfig.handbookUrl}`,
_comment: `This config was generated using a preset. Please see the handbook for more information: ${presetConfig.handbookUrl}`,
...presetConfig.config,
};

return this.writeStrykerConfig(config, exportAsJson);
}

private writeStrykerConfig(config: Partial<StrykerOptions>, exportAsJson: boolean) {
private writeStrykerConfig(config: PartialStrykerOptions, exportAsJson: boolean) {
if (exportAsJson) {
return this.writeJsonConfig(config);
} else {
return this.writeJsConfig(config);
}
}

private async writeJsConfig(commentedConfig: Partial<StrykerOptions>) {
private async writeJsConfig(commentedConfig: PartialStrykerOptions) {
this.out(`Writing & formatting ${STRYKER_JS_CONFIG_FILE}...`);
const rawConfig = this.stringify(commentedConfig);
const formattedConfig = `/**
Expand All @@ -93,7 +93,7 @@ export default class StrykerConfigWriter {
return STRYKER_JS_CONFIG_FILE;
}

private async writeJsonConfig(commentedConfig: Partial<StrykerOptions>) {
private async writeJsonConfig(commentedConfig: PartialStrykerOptions) {
this.out(`Writing & formatting ${STRYKER_JSON_CONFIG_FILE}...`);
const typedConfig = {
$schema: './node_modules/@stryker-mutator/core/schema/stryker-schema.json',
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/initializer/StrykerInitializer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as child from 'child_process';
import { promises as fs } from 'fs';

import { commonTokens, tokens } from '@stryker-mutator/api/plugin';
import { Logger } from '@stryker-mutator/api/logging';
Expand Down Expand Up @@ -87,6 +88,9 @@ export default class StrykerInitializer {
const presetConfig = await selectedPreset.createConfig();
const isJsonSelected = await this.selectJsonConfigType();
const configFileName = await configWriter.writePreset(presetConfig, isJsonSelected);
if (presetConfig.additionalConfigFiles) {
await Promise.all(presetConfig.additionalConfigFiles.map(({ name, content }) => fs.writeFile(name, content)));
}
const selectedPackageManager = await this.selectPackageManager();
this.installNpmDependencies(presetConfig.dependencies, selectedPackageManager);
return configFileName;
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/initializer/presets/AngularPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const handbookUrl = 'https://github.com/stryker-mutator/stryker-handbook/blob/ma
export class AngularPreset implements Preset {
public readonly name = 'angular-cli';
// Please keep config in sync with handbook
private readonly dependencies = ['@stryker-mutator/core', '@stryker-mutator/karma-runner', '@stryker-mutator/typescript'];
private readonly dependencies = ['@stryker-mutator/karma-runner'];
private readonly config: Partial<StrykerOptions> = {
mutate: ['src/**/*.ts', '!src/**/*.spec.ts', '!src/test.ts', '!src/environments/*.ts'],
testRunner: 'karma',
Expand All @@ -24,8 +24,8 @@ export class AngularPreset implements Preset {
reporters: ['progress', 'clear-text', 'html'],
concurrency: Math.floor(os.cpus().length / 2),
// eslint-disable-next-line camelcase
maxConcurrentTestRunners_comment: 'Recommended to use about half of your available cores when running stryker with angular',
coverageAnalysis: 'off',
concurrency_comment: 'Recommended to use about half of your available cores when running stryker with angular',
coverageAnalysis: 'perTest',
};

public async createConfig(): Promise<PresetConfiguration> {
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/initializer/presets/PresetConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { StrykerOptions } from '@stryker-mutator/api/core';
import { File, PartialStrykerOptions } from '@stryker-mutator/api/core';

export default interface PresetConfiguration {
config: Partial<StrykerOptions>;
config: PartialStrykerOptions;
handbookUrl: string;
dependencies: string[];
additionalConfigFiles?: File[];
}
35 changes: 3 additions & 32 deletions packages/core/src/initializer/presets/ReactPreset.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import inquirer = require('inquirer');
import { StrykerOptions } from '@stryker-mutator/api/core';

import Preset from './Preset';
Expand All @@ -12,9 +11,9 @@ const handbookUrl = 'https://github.com/stryker-mutator/stryker-handbook/blob/ma
*/
export class ReactPreset implements Preset {
public readonly name = 'create-react-app';
private readonly generalDependencies = ['@stryker-mutator/core', '@stryker-mutator/jest-runner'];
private readonly dependencies = ['@stryker-mutator/jest-runner'];

private readonly sharedConfig: Partial<StrykerOptions> = {
private readonly config: Partial<StrykerOptions> = {
testRunner: 'jest',
reporters: ['progress', 'clear-text', 'html'],
coverageAnalysis: 'off',
Expand All @@ -23,35 +22,7 @@ export class ReactPreset implements Preset {
},
};

private readonly tsxDependencies = ['@stryker-mutator/typescript', ...this.generalDependencies];
private readonly tsxConf: Partial<StrykerOptions> = {
mutate: ['src/**/*.ts?(x)', '!src/**/*@(.test|.spec|Spec).ts?(x)'],
...this.sharedConfig,
};

private readonly jsxDependencies = ['@stryker-mutator/javascript-mutator', ...this.generalDependencies];
private readonly jsxConf: Partial<StrykerOptions> = {
mutate: ['src/**/*.js?(x)', '!src/**/*@(.test|.spec|Spec).js?(x)'],
...this.sharedConfig,
};

public async createConfig(): Promise<PresetConfiguration> {
const choices = ['JSX', 'TSX'];
const answers = await inquirer.prompt<{ choice: string }>({
choices,
message: 'Is your project a JSX project or a TSX project?',
name: 'choice',
type: 'list',
});
return this.load(answers.choice);
}
private load(choice: string): PresetConfiguration {
if (choice === 'JSX') {
return { config: this.jsxConf, handbookUrl, dependencies: this.jsxDependencies };
} else if (choice === 'TSX') {
return { config: this.tsxConf, handbookUrl, dependencies: this.tsxDependencies };
} else {
throw new Error(`Invalid project type ${choice}`);
}
return { config: this.config, handbookUrl, dependencies: this.dependencies };
}
}
103 changes: 58 additions & 45 deletions packages/core/src/initializer/presets/VueJsPreset.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import inquirer = require('inquirer');
import { StrykerOptions } from '@stryker-mutator/api/core';
import { File, PartialStrykerOptions } from '@stryker-mutator/api/core';

import Preset from './Preset';
import PresetConfiguration from './PresetConfiguration';
Expand All @@ -11,90 +11,103 @@ const handbookUrl = 'https://github.com/stryker-mutator/stryker-handbook/blob/ma
* https://github.com/stryker-mutator/stryker-handbook/blob/master/stryker/guides/vuejs.md#vuejs
*/
export class VueJsPreset implements Preset {
public readonly name = 'vueJs';
private readonly generalDependencies = ['@stryker-mutator/core', '@stryker-mutator/vue-mutator'];
public readonly name = 'vue-cli';

private readonly jestDependency = '@stryker-mutator/jest-runner';
private readonly jestConf: Partial<StrykerOptions> = {
mutate: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'],
private readonly jestConf: PartialStrykerOptions = {
testRunner: 'jest',
mutator: {
plugins: [],
},
jest: {
// config: require('path/to/your/custom/jestConfig.js')
},
reporters: ['progress', 'clear-text', 'html'],
coverageAnalysis: 'off',
};

private readonly karmaDependency = '@stryker-mutator/karma-runner';
private readonly karmaConf: Partial<StrykerOptions> = {
mutate: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'],
testRunner: 'karma',
karma: {
configFile: 'test/unit/karma.conf.js',
config: {
browsers: ['ChromeHeadless'],
},
private readonly mochaConf: PartialStrykerOptions = {
testRunner: 'mocha',
mutator: {
plugins: [],
},
mochaOptions: {
require: ['@vue/cli-plugin-unit-mocha/setup.js'],
spec: ['dist/js/chunk-vendors.js', 'dist/js/tests.js'],
},
buildCommand: 'webpack --config webpack.config.stryker.js',
reporters: ['progress', 'clear-text', 'html'],
coverageAnalysis: 'off',
coverageAnalysis: 'perTest',
};

public async createConfig(): Promise<PresetConfiguration> {
const testRunnerChoices = ['karma', 'jest'];
const testRunnerChoices = ['mocha', 'jest'];
const testRunnerAnswers = await inquirer.prompt<{ testRunner: string }>({
choices: testRunnerChoices,
message: 'Which test runner do you want to use?',
name: 'testRunner',
type: 'list',
});
const scriptChoices = ['typescript', 'javascript'];
const scriptAnswers = await inquirer.prompt<{ script: string }>({
choices: scriptChoices,
message: 'Which language does your project use?',
name: 'script',
type: 'list',
});
const chosenTestRunner = testRunnerAnswers.testRunner;
const chosenScript = scriptAnswers.script;
return {
config: this.getConfig(chosenTestRunner),
dependencies: this.createDependencies(chosenTestRunner, chosenScript),
dependencies: this.createDependencies(chosenTestRunner),
handbookUrl,
additionalConfigFiles: this.getAdditionalConfigFiles(chosenTestRunner),
};
}

private getConfig(testRunner: string) {
if (testRunner === 'karma') {
return this.karmaConf;
if (testRunner === 'mocha') {
return this.mochaConf;
} else if (testRunner === 'jest') {
return this.jestConf;
} else {
throw new Error(`Invalid test runner chosen: ${testRunner}`);
}
}

private createDependencies(testRunner: string, script: string): string[] {
const dependencies = this.generalDependencies;
dependencies.push(this.getTestRunnerDependency(testRunner));
dependencies.push(this.getScriptDependency(script));
return dependencies;
}
private getAdditionalConfigFiles(testRunner: string): File[] | undefined {
if (testRunner === 'mocha') {
return [
new File(
'webpack.config.stryker.js',
`
const glob = require('glob');
// Set env
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.VUE_CLI_BABEL_TARGET_NODE = 'true';
process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME = 'true';
// Load webpack config
const conf = require('@vue/cli-service/webpack.config.js');
// Override the entry files
conf.entry = {
// Choose your test files here:
tests: glob.sync('{test,tests}/**/*+(spec).js').map((fileName) => \`./\${fileName}\`),
};
private getScriptDependency(script: string): string {
if (script === 'typescript') {
return '@stryker-mutator/typescript';
} else if (script === 'javascript') {
return '@stryker-mutator/javascript-mutator';
module.exports = conf;
`
),
];
} else {
throw new Error(`Invalid script chosen: ${script}`);
return;
}
}

private getTestRunnerDependency(testRunner: string): string {
if (testRunner === 'karma') {
return this.karmaDependency;
private createDependencies(testRunner: string): string[] {
const dependencies = [];
dependencies.push(...this.getTestRunnerDependency(testRunner));
return dependencies;
}

private getTestRunnerDependency(testRunner: string): string[] {
if (testRunner === 'mocha') {
return ['@stryker-mutator/mocha-runner', 'glob', 'webpack-cli'];
} else if (testRunner === 'jest') {
return this.jestDependency;
return ['@stryker-mutator/jest-runner'];
} else {
throw new Error(`Invalid test runner chosen: ${testRunner}`);
}
Expand Down
46 changes: 6 additions & 40 deletions packages/core/test/unit/initializer/Presets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,6 @@ describe('Presets', () => {
it('should have the name "create-react-app"', () => {
expect(reactPreset.name).to.eq('create-react-app');
});

it('should install @stryker-mutator/typescript when TSX is chosen', async () => {
inquirerPrompt.resolves({
choice: 'TSX',
});
const config = await reactPreset.createConfig();
expect(config.dependencies).to.include('@stryker-mutator/typescript');
});

it('should install @stryker-mutator/javascript-mutator when JSX is chosen', async () => {
inquirerPrompt.resolves({
choice: 'JSX',
});
const config = await reactPreset.createConfig();
expect(config.dependencies).to.include('@stryker-mutator/javascript-mutator');
});
});

describe('VueJsPreset', () => {
Expand All @@ -64,21 +48,21 @@ describe('Presets', () => {
vueJsPreset = new VueJsPreset();
inquirerPrompt.resolves({
script: 'typescript',
testRunner: 'karma',
testRunner: 'jest',
});
});

it('should have the name "vueJs"', () => {
expect(vueJsPreset.name).to.eq('vueJs');
it('should have the name "vue-cli"', () => {
expect(vueJsPreset.name).to.eq('vue-cli');
});

it('should install @stryker-mutator/karma-runner when karma is chosen', async () => {
it('should install @stryker-mutator/mocha-runner when mocha is chosen', async () => {
inquirerPrompt.resolves({
script: 'typescript',
testRunner: 'karma',
testRunner: 'mocha',
});
const config = await vueJsPreset.createConfig();
expect(config.dependencies).to.include('@stryker-mutator/karma-runner');
expect(config.dependencies).to.include('@stryker-mutator/mocha-runner');
});

it('should install @stryker-mutator/jest-runner when jest is chosen', async () => {
Expand All @@ -89,23 +73,5 @@ describe('Presets', () => {
const config = await vueJsPreset.createConfig();
expect(config.dependencies).to.include('@stryker-mutator/jest-runner');
});

it('should install @stryker-mutator/typescript when typescript is chosen', async () => {
inquirerPrompt.resolves({
script: 'typescript',
testRunner: 'karma',
});
const config = await vueJsPreset.createConfig();
expect(config.dependencies).to.include('@stryker-mutator/typescript');
});

it('should install @stryker-mutator/javascript-mutator when javascript is chosen', async () => {
inquirerPrompt.resolves({
script: 'javascript',
testRunner: 'karma',
});
const config = await vueJsPreset.createConfig();
expect(config.dependencies).to.include('@stryker-mutator/javascript-mutator');
});
});
});
Loading

0 comments on commit ec0d75e

Please sign in to comment.