From 70df62edd854657aec41ae2bdac74a30bef568cf Mon Sep 17 00:00:00 2001 From: Simon de Lang Date: Wed, 11 Mar 2020 11:07:18 +0100 Subject: [PATCH 1/9] feat(json config): Load json config file if no js config file is present --- packages/core/README.md | 4 +-- packages/core/src/StrykerCli.ts | 6 ++-- packages/core/src/config/ConfigReader.ts | 9 +++--- .../core/src/input/InputFileCollection.ts | 2 +- packages/core/src/transpiler/SourceMapper.ts | 2 +- .../config-reader/ConfigReader.it.spec.ts | 32 ++++++++++++++++--- .../config-reader/{ => js}/stryker.conf.js | 5 +-- .../config-reader/json-and-js/stryker.conf.js | 9 ++++++ .../json-and-js/stryker.conf.json | 6 ++++ .../config-reader/json/stryker.conf.json | 6 ++++ .../testResources/config-reader/valid.conf.js | 2 +- 11 files changed, 64 insertions(+), 19 deletions(-) rename packages/core/testResources/config-reader/{ => js}/stryker.conf.js (72%) create mode 100644 packages/core/testResources/config-reader/json-and-js/stryker.conf.js create mode 100644 packages/core/testResources/config-reader/json-and-js/stryker.conf.json create mode 100644 packages/core/testResources/config-reader/json/stryker.conf.json diff --git a/packages/core/README.md b/packages/core/README.md index 18db714d9a..feb958f424 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -33,12 +33,12 @@ It will run stryker with default values: ## Usage ```sh -$ npx stryker [options] [stryker.conf.js] +$ npx stryker [options] [configfilePath] ``` The main `command` for Stryker is `run`, which kicks off mutation testing. -Although Stryker can run without any configuration, it is recommended to configure it when you can, as it can greatly improve performance of the mutation testing process. By default, Stryker will look for a `stryker.conf.js` file in the current working directory (if it exists). This can be overridden by specifying a different file as the last parameter. +Although Stryker can run without any configuration, it is recommended to configure it when you can, as it can greatly improve performance of the mutation testing process. By default, Stryker will look for a `stryker.conf.js` or `stryker.conf.json` file in the current working directory (if it exists). This can be overridden by specifying a different file as the last parameter. Before your first run, we recommend you try the `init` command, which helps you to set up this `stryker.conf.js` file and install any missing packages needed for your specific configuration. We recommend you verify the contents of the configuration file after this initialization, to make sure everything is setup correctly. Of course, you can still make changes to it, before you run Stryker for the first time. diff --git a/packages/core/src/StrykerCli.ts b/packages/core/src/StrykerCli.ts index 1926eab2b8..b59a8a59dd 100644 --- a/packages/core/src/StrykerCli.ts +++ b/packages/core/src/StrykerCli.ts @@ -46,15 +46,15 @@ export default class StrykerCli { const defaultValues = new Config(); this.program .version(require('../package.json').version) - .usage(' [options] [stryker.conf.js]') + .usage(' [options] [configFile]') .description( `Possible commands: run: Run mutation testing init: Initialize Stryker for your project - Optional location to the stryker.conf.js file as last argument. That file should export a function which accepts a "config" object\n${CONFIG_SYNTAX_HELP}` + Optional location to a JSON or JavaScript configfile as last argument. If it's a JavaScript file, that file should export a function which accepts a "config" object\n${CONFIG_SYNTAX_HELP}` ) - .arguments(' [stryker.conf.js]') + .arguments(' [configFile]') .action((cmd: string, config: string) => { this.command = cmd; this.strykerConfig = config; diff --git a/packages/core/src/config/ConfigReader.ts b/packages/core/src/config/ConfigReader.ts index bbe63df053..8d157837c6 100644 --- a/packages/core/src/config/ConfigReader.ts +++ b/packages/core/src/config/ConfigReader.ts @@ -1,4 +1,3 @@ -import * as fs from 'fs'; import * as path from 'path'; import { Config } from '@stryker-mutator/api/config'; @@ -11,7 +10,7 @@ import { coreTokens } from '../di'; export const CONFIG_SYNTAX_HELP = ' module.exports = function(config) {\n' + ' config.set({\n' + ' // your config\n' + ' });\n' + ' };'; -const DEFAULT_CONFIG_FILE = 'stryker.conf.js'; +const DEFAULT_CONFIG_FILE = 'stryker.conf'; export default class ConfigReader { public static inject = tokens(coreTokens.cliOptions, commonTokens.logger); @@ -41,9 +40,9 @@ export default class ConfigReader { if (!this.cliOptions.configFile) { try { - fs.accessSync(path.resolve(`./${DEFAULT_CONFIG_FILE}`)); - this.log.info(`Using ${DEFAULT_CONFIG_FILE} in the current working directory.`); - this.cliOptions.configFile = DEFAULT_CONFIG_FILE; + const configFile = require.resolve(path.resolve(`./${DEFAULT_CONFIG_FILE}`)); + this.log.info(`Using ${configFile}`); + this.cliOptions.configFile = configFile; } catch (e) { this.log.info('No config file specified. Running with command line arguments.'); this.log.info('Use `stryker init` command to generate your config file.'); diff --git a/packages/core/src/input/InputFileCollection.ts b/packages/core/src/input/InputFileCollection.ts index 2c7ad95790..a0bcb9d524 100644 --- a/packages/core/src/input/InputFileCollection.ts +++ b/packages/core/src/input/InputFileCollection.ts @@ -26,7 +26,7 @@ export default class InputFileCollection { } else { log.warn( normalizeWhitespaces(`No files marked to be mutated, Stryker will perform a dry-run without actually mutating anything. - You can configure the \`mutate\` property in your stryker.conf.js file (or use \`--mutate\` via command line).`) + You can configure the \`mutate\` property in your config file (or use \`--mutate\` via command line).`) ); } if (log.isDebugEnabled()) { diff --git a/packages/core/src/transpiler/SourceMapper.ts b/packages/core/src/transpiler/SourceMapper.ts index 5af4c4a529..caf8f47312 100644 --- a/packages/core/src/transpiler/SourceMapper.ts +++ b/packages/core/src/transpiler/SourceMapper.ts @@ -21,7 +21,7 @@ export interface MappedLocation { export class SourceMapError extends StrykerError { constructor(message: string, innerError?: Error) { super( - `${message}. Cannot analyse code coverage. Setting \`coverageAnalysis: "off"\` in your stryker.conf.js will prevent this error, but forces Stryker to run each test for each mutant.`, + `${message}. Cannot analyse code coverage. Setting \`coverageAnalysis: "off"\` in your config will prevent this error, but forces Stryker to run each test for each mutant.`, innerError ); Error.captureStackTrace(this, SourceMapError); diff --git a/packages/core/test/integration/config-reader/ConfigReader.it.spec.ts b/packages/core/test/integration/config-reader/ConfigReader.it.spec.ts index 7d7372baf8..754dab21fe 100644 --- a/packages/core/test/integration/config-reader/ConfigReader.it.spec.ts +++ b/packages/core/test/integration/config-reader/ConfigReader.it.spec.ts @@ -34,15 +34,39 @@ describe(ConfigReader.name, () => { describe('without config file or CLI options', () => { describe('with a stryker.conf.js in the CWD', () => { it('should parse the config', () => { - const mockCwd = path.resolve(__dirname, '..', '..', '..', 'testResources', 'config-reader'); + const mockCwd = path.resolve(__dirname, '..', '..', '..', 'testResources', 'config-reader', 'js'); sinon.stub(process, 'cwd').returns(mockCwd); sut = createSut({}); result = sut.readConfig(); - expect(result.valid).to.be.eq('config'); - expect(result.should).to.be.eq('be'); - expect(result.read).to.be.eq(true); + expect(result.type).to.be.eq('js'); + expect(testInjector.logger.warn).not.called; + }); + }); + + describe('with a stryker.conf.json in the CWD', () => { + it('should parse the config', () => { + const mockCwd = path.resolve(__dirname, '..', '..', '..', 'testResources', 'config-reader', 'json'); + sinon.stub(process, 'cwd').returns(mockCwd); + sut = createSut({}); + + result = sut.readConfig(); + + expect(result.type).to.be.eq('json'); + expect(testInjector.logger.warn).not.called; + }); + }); + + describe('with a stryker.conf.js and stryker.conf.json in the CWD', () => { + it('should parse the js config', () => { + const mockCwd = path.resolve(__dirname, '..', '..', '..', 'testResources', 'config-reader', 'json-and-js'); + sinon.stub(process, 'cwd').returns(mockCwd); + sut = createSut({}); + + result = sut.readConfig(); + + expect(result.type).to.be.eq('js'); expect(testInjector.logger.warn).not.called; }); }); diff --git a/packages/core/testResources/config-reader/stryker.conf.js b/packages/core/testResources/config-reader/js/stryker.conf.js similarity index 72% rename from packages/core/testResources/config-reader/stryker.conf.js rename to packages/core/testResources/config-reader/js/stryker.conf.js index 1ebbaafb0a..6f32162dd8 100644 --- a/packages/core/testResources/config-reader/stryker.conf.js +++ b/packages/core/testResources/config-reader/js/stryker.conf.js @@ -3,6 +3,7 @@ module.exports = function(config){ config.set({ 'valid': 'config', 'should': 'be', - 'read': true + 'read': true, + 'type': 'js' }); -}; \ No newline at end of file +}; diff --git a/packages/core/testResources/config-reader/json-and-js/stryker.conf.js b/packages/core/testResources/config-reader/json-and-js/stryker.conf.js new file mode 100644 index 0000000000..6f32162dd8 --- /dev/null +++ b/packages/core/testResources/config-reader/json-and-js/stryker.conf.js @@ -0,0 +1,9 @@ + +module.exports = function(config){ + config.set({ + 'valid': 'config', + 'should': 'be', + 'read': true, + 'type': 'js' + }); +}; diff --git a/packages/core/testResources/config-reader/json-and-js/stryker.conf.json b/packages/core/testResources/config-reader/json-and-js/stryker.conf.json new file mode 100644 index 0000000000..6a5ce6766b --- /dev/null +++ b/packages/core/testResources/config-reader/json-and-js/stryker.conf.json @@ -0,0 +1,6 @@ +{ + "valid": "config", + "should": "be", + "read": true, + "type": "json" +} diff --git a/packages/core/testResources/config-reader/json/stryker.conf.json b/packages/core/testResources/config-reader/json/stryker.conf.json new file mode 100644 index 0000000000..6a5ce6766b --- /dev/null +++ b/packages/core/testResources/config-reader/json/stryker.conf.json @@ -0,0 +1,6 @@ +{ + "valid": "config", + "should": "be", + "read": true, + "type": "json" +} diff --git a/packages/core/testResources/config-reader/valid.conf.js b/packages/core/testResources/config-reader/valid.conf.js index 755c7dc9fd..093f324531 100644 --- a/packages/core/testResources/config-reader/valid.conf.js +++ b/packages/core/testResources/config-reader/valid.conf.js @@ -1 +1 @@ -module.exports = require('./stryker.conf.js'); \ No newline at end of file +module.exports = require('./js/stryker.conf.js'); From f7662e04615b6f3c331b17c5c39534f4c1d9f371 Mon Sep 17 00:00:00 2001 From: Simon de Lang Date: Wed, 11 Mar 2020 11:18:42 +0100 Subject: [PATCH 2/9] test: use correct config key --- packages/core/test/unit/transpiler/SourceMapper.spec.ts | 4 ++-- packages/mocha-runner/src/MochaTestRunner.ts | 2 +- packages/mocha-runner/test/unit/MochaTestRunner.spec.ts | 2 +- packages/wct-runner/src/WctTestRunner.ts | 2 +- packages/wct-runner/test/unit/WctTestRunner.spec.ts | 2 +- packages/webpack-transpiler/src/compiler/ConfigLoader.ts | 2 +- .../test/unit/compiler/ConfigLoader.spec.ts | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/test/unit/transpiler/SourceMapper.spec.ts b/packages/core/test/unit/transpiler/SourceMapper.spec.ts index ec2139713b..03f288dec9 100644 --- a/packages/core/test/unit/transpiler/SourceMapper.spec.ts +++ b/packages/core/test/unit/transpiler/SourceMapper.spec.ts @@ -16,7 +16,7 @@ function base64Encode(input: string) { } const ERROR_POSTFIX = - '. Cannot analyse code coverage. Setting `coverageAnalysis: "off"` in your stryker.conf.js will prevent this error, but forces Stryker to run each test for each mutant.'; + '. Cannot analyse code coverage. Setting `coverageAnalysis: "off"` in your config will prevent this error, but forces Stryker to run each test for each mutant.'; describe('SourceMapper', () => { let sut: SourceMapper; @@ -124,7 +124,7 @@ describe('SourceMapper', () => { await expect(sut.transpiledLocationFor(mappedLocation({ fileName: 'foobar' }))).to.be.rejectedWith( SourceMapError, - /^Source map file "file1.js.map" could not be parsed as json. Cannot analyse code coverage. Setting `coverageAnalysis: "off"` in your stryker.conf.js will prevent this error/ + /^Source map file "file1.js.map" could not be parsed as json. Cannot analyse code coverage. Setting `coverageAnalysis: "off"` in your config will prevent this error/ ); }); diff --git a/packages/mocha-runner/src/MochaTestRunner.ts b/packages/mocha-runner/src/MochaTestRunner.ts index 954f64ae74..61b95385f0 100644 --- a/packages/mocha-runner/src/MochaTestRunner.ts +++ b/packages/mocha-runner/src/MochaTestRunner.ts @@ -58,7 +58,7 @@ export class MochaTestRunner implements TestRunner { globPatterns, null, 2 - )}). Please specify the files (glob patterns) containing your tests in ${mochaOptionsKey}.files in your stryker.conf.js file.` + )}). Please specify the files (glob patterns) containing your tests in ${mochaOptionsKey}.files in your config file.` ); } return fileNames; diff --git a/packages/mocha-runner/test/unit/MochaTestRunner.spec.ts b/packages/mocha-runner/test/unit/MochaTestRunner.spec.ts index 59948d423e..818bb56142 100644 --- a/packages/mocha-runner/test/unit/MochaTestRunner.spec.ts +++ b/packages/mocha-runner/test/unit/MochaTestRunner.spec.ts @@ -122,7 +122,7 @@ describe(MochaTestRunner.name, () => { // Assert expect(actFn).throws( - `[MochaTestRunner] No files discovered (tried pattern(s) ${relativeGlobbing}). Please specify the files (glob patterns) containing your tests in mochaOptions.files in your stryker.conf.js file.` + `[MochaTestRunner] No files discovered (tried pattern(s) ${relativeGlobbing}). Please specify the files (glob patterns) containing your tests in mochaOptions.files in your config file.` ); expect(testInjector.logger.debug).calledWith(`Tried ${absoluteGlobbing} on files: ${filesStringified}.`); }); diff --git a/packages/wct-runner/src/WctTestRunner.ts b/packages/wct-runner/src/WctTestRunner.ts index 9a1b3cd587..9168dd7abd 100644 --- a/packages/wct-runner/src/WctTestRunner.ts +++ b/packages/wct-runner/src/WctTestRunner.ts @@ -22,7 +22,7 @@ export default class WctTestRunner implements TestRunner { constructor(private readonly log: Logger, options: StrykerOptions) { if (options.coverageAnalysis !== 'off') { throw new Error( - `Coverage analysis "${options.coverageAnalysis}" is not (yet) supported by the WCT test runner plugin. Please set \`coverageAnalysis: "off"\` in your stryker.conf.js file.` + `Coverage analysis "${options.coverageAnalysis}" is not (yet) supported by the WCT test runner plugin. Please set \`coverageAnalysis: "off"\` in your config file.` ); } this.log.debug('Running wct version %s from %s', require(`${WCT_PACKAGE}/package.json`).version, require.resolve(WCT_PACKAGE)); diff --git a/packages/wct-runner/test/unit/WctTestRunner.spec.ts b/packages/wct-runner/test/unit/WctTestRunner.spec.ts index c053b57929..e2981043fc 100644 --- a/packages/wct-runner/test/unit/WctTestRunner.spec.ts +++ b/packages/wct-runner/test/unit/WctTestRunner.spec.ts @@ -65,7 +65,7 @@ describe(WctTestRunner.name, () => { it('should throw when coverageAnalysis != "off"', () => { testInjector.options.coverageAnalysis = 'all'; const expectedError = - 'Coverage analysis "all" is not (yet) supported by the WCT test runner plugin. Please set `coverageAnalysis: "off"` in your stryker.conf.js file.'; + 'Coverage analysis "all" is not (yet) supported by the WCT test runner plugin. Please set `coverageAnalysis: "off"` in your config file.'; expect(() => createSut()).throws(expectedError); }); diff --git a/packages/webpack-transpiler/src/compiler/ConfigLoader.ts b/packages/webpack-transpiler/src/compiler/ConfigLoader.ts index 832ca57157..60c85b1bb1 100644 --- a/packages/webpack-transpiler/src/compiler/ConfigLoader.ts +++ b/packages/webpack-transpiler/src/compiler/ConfigLoader.ts @@ -50,7 +50,7 @@ export default class ConfigLoader { webpackConfig.plugins = webpackConfig.plugins.filter(plugin => { if (plugin.constructor && plugin.constructor.name === PROGRESS_PLUGIN_NAME) { this.log.debug( - 'Removing webpack plugin "%s" to keep webpack bundling silent. Set `webpack: { silent: false }` in your stryker.conf.js file to disable this feature.', + 'Removing webpack plugin "%s" to keep webpack bundling silent. Set `webpack: { silent: false }` in your config file to disable this feature.', PROGRESS_PLUGIN_NAME ); return false; diff --git a/packages/webpack-transpiler/test/unit/compiler/ConfigLoader.spec.ts b/packages/webpack-transpiler/test/unit/compiler/ConfigLoader.spec.ts index 183e1846fb..63b1738d2c 100644 --- a/packages/webpack-transpiler/test/unit/compiler/ConfigLoader.spec.ts +++ b/packages/webpack-transpiler/test/unit/compiler/ConfigLoader.spec.ts @@ -76,7 +76,7 @@ describe('ConfigLoader', () => { .to.be.an('array') .that.deep.equals([new FooPlugin(), new BarPlugin(), bazPlugin]); expect(testInjector.logger.debug).calledWith( - 'Removing webpack plugin "%s" to keep webpack bundling silent. Set `webpack: { silent: false }` in your stryker.conf.js file to disable this feature.', + 'Removing webpack plugin "%s" to keep webpack bundling silent. Set `webpack: { silent: false }` in your config file to disable this feature.', 'ProgressPlugin' ); }); From 36b5e0ba82f3b07fcc8ac6767201cd5a69f73367 Mon Sep 17 00:00:00 2001 From: Simon de Lang Date: Wed, 11 Mar 2020 11:34:34 +0100 Subject: [PATCH 3/9] fix: review comments --- packages/core/README.md | 2 +- packages/core/src/StrykerCli.ts | 2 +- packages/core/src/config/ConfigReader.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index feb958f424..77dd14c831 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -33,7 +33,7 @@ It will run stryker with default values: ## Usage ```sh -$ npx stryker [options] [configfilePath] +$ npx stryker [options] [configFile] ``` The main `command` for Stryker is `run`, which kicks off mutation testing. diff --git a/packages/core/src/StrykerCli.ts b/packages/core/src/StrykerCli.ts index b59a8a59dd..8fec2a4ce1 100644 --- a/packages/core/src/StrykerCli.ts +++ b/packages/core/src/StrykerCli.ts @@ -52,7 +52,7 @@ export default class StrykerCli { run: Run mutation testing init: Initialize Stryker for your project - Optional location to a JSON or JavaScript configfile as last argument. If it's a JavaScript file, that file should export a function which accepts a "config" object\n${CONFIG_SYNTAX_HELP}` + Optional location to a JSON or JavaScript config file as the last argument. If it's a JavaScript file, that file should export the config directly.` ) .arguments(' [configFile]') .action((cmd: string, config: string) => { diff --git a/packages/core/src/config/ConfigReader.ts b/packages/core/src/config/ConfigReader.ts index 8d157837c6..bf19e3ed4a 100644 --- a/packages/core/src/config/ConfigReader.ts +++ b/packages/core/src/config/ConfigReader.ts @@ -41,7 +41,7 @@ export default class ConfigReader { if (!this.cliOptions.configFile) { try { const configFile = require.resolve(path.resolve(`./${DEFAULT_CONFIG_FILE}`)); - this.log.info(`Using ${configFile}`); + this.log.info(`Using ${path.basename(configFile)}`); this.cliOptions.configFile = configFile; } catch (e) { this.log.info('No config file specified. Running with command line arguments.'); From 207525031e26d1dc332b59160dc3bb52cbd1e565 Mon Sep 17 00:00:00 2001 From: Simon de Lang Date: Wed, 11 Mar 2020 11:46:15 +0100 Subject: [PATCH 4/9] fix: remove unused import --- packages/core/src/StrykerCli.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/StrykerCli.ts b/packages/core/src/StrykerCli.ts index 8fec2a4ce1..8743d65c9a 100644 --- a/packages/core/src/StrykerCli.ts +++ b/packages/core/src/StrykerCli.ts @@ -4,7 +4,6 @@ import { DashboardOptions, StrykerOptions, ALL_REPORT_TYPES } from '@stryker-mut import { Config } from '@stryker-mutator/api/config'; import { Logger } from '@stryker-mutator/api/logging'; -import { CONFIG_SYNTAX_HELP } from './config/ConfigReader'; import { initializerFactory } from './initializer'; import LogConfigurator from './logging/LogConfigurator'; import Stryker from './Stryker'; From a86d4fe6b515270a98f636b0d538c72559e8f829 Mon Sep 17 00:00:00 2001 From: Simon de Lang Date: Wed, 11 Mar 2020 15:27:31 +0100 Subject: [PATCH 5/9] feat(Initializer): Initialize config file as JSON by default --- packages/core/README.md | 50 ++++--- .../src/initializer/StrykerConfigWriter.ts | 81 +++++++---- .../src/initializer/StrykerInitializer.ts | 22 ++- .../core/src/initializer/StrykerInquirer.ts | 13 ++ .../src/initializer/presets/AngularPreset.ts | 42 +++--- .../presets/PresetConfiguration.ts | 4 +- .../src/initializer/presets/ReactPreset.ts | 27 ++-- .../src/initializer/presets/VueJsPreset.ts | 52 +++---- .../test/unit/initializer/Presets.spec.ts | 10 +- .../initializer/StrykerInitializer.spec.ts | 127 +++++++++++------- packages/grunt-stryker/README.md | 12 +- 11 files changed, 269 insertions(+), 171 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index 77dd14c831..f22fd33cb4 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -40,26 +40,40 @@ The main `command` for Stryker is `run`, which kicks off mutation testing. Although Stryker can run without any configuration, it is recommended to configure it when you can, as it can greatly improve performance of the mutation testing process. By default, Stryker will look for a `stryker.conf.js` or `stryker.conf.json` file in the current working directory (if it exists). This can be overridden by specifying a different file as the last parameter. -Before your first run, we recommend you try the `init` command, which helps you to set up this `stryker.conf.js` file and install any missing packages needed for your specific configuration. We recommend you verify the contents of the configuration file after this initialization, to make sure everything is setup correctly. Of course, you can still make changes to it, before you run Stryker for the first time. - -The following is an example `stryker.conf.js` file. It specifies running mocha tests with the mocha test runner. - -```javascript -module.exports = function(config){ - config.set({ - mutate: [ - 'src/**/*.js', - '!src/index.js' - ], - testFramework: 'mocha', - testRunner: 'mocha', - reporters: ['progress', 'clear-text', 'html'], - coverageAnalysis: 'perTest' - }); +Before your first run, we recommend you try the `init` command, which helps you to set up this config file and install any missing packages needed for your specific configuration. We recommend you verify the contents of the configuration file after this initialization, to make sure everything is setup correctly. Of course, you can still make changes to it, before you run Stryker for the first time. + +The following is an example `stryker.conf.json` file. It specifies running mocha tests with the mocha test runner. + +```json +{ + "$schema": "https://raw.githubusercontent.com/stryker-mutator/stryker/master/packages/api/schema/stryker-core.json", + "mutate": [ + "src/**/*.js", + "!src/index.js" + ], + "testFramework": "mocha", + "testRunner": "mocha", + "reporters": ["progress", "clear-text", "html"], + "coverageAnalysis": "perTest" } ``` -As you can see, the config file is *not* a simple JSON file. It should be a node module. You might recognize this way of working from the karma test runner. +As a `stryker.conf.js` file this looks like this: +```javascript +/** +* @type {import('@stryker-mutator/api/core').StrykerOptions} +*/ +module.exports = { + mutate: [ + 'src/**/*.js', + '!src/index.js' + ], + testFramework: 'mocha', + testRunner: 'mocha', + reporters: ['progress', 'clear-text', 'html'], + coverageAnalysis: 'perTest' +}; +``` Make sure you *at least* specify the `testRunner` options when mixing the config file and/or command line options. @@ -80,7 +94,7 @@ See our website for the [list of currently supported mutators](https://stryker-m ## Configuration -All configuration options can either be set via the command line or via the `stryker.conf.js` config file. +All configuration options can either be set via the command line or via a config file. `files` and `mutate` both support globbing expressions using [node glob](https://github.com/isaacs/node-glob). This is the same globbing format you might know from [Grunt](https://github.com/gruntjs/grunt) or [Karma](https://github.com/karma-runner/karma). diff --git a/packages/core/src/initializer/StrykerConfigWriter.ts b/packages/core/src/initializer/StrykerConfigWriter.ts index e26a8166c6..62ced73848 100644 --- a/packages/core/src/initializer/StrykerConfigWriter.ts +++ b/packages/core/src/initializer/StrykerConfigWriter.ts @@ -10,22 +10,28 @@ import PromptOption from './PromptOption'; import { initializerTokens } from '.'; -const STRYKER_CONFIG_FILE = 'stryker.conf.js'; +const STRYKER_JS_CONFIG_FILE = 'stryker.conf.js'; +const STRYKER_JSON_CONFIG_FILE = 'stryker.conf.json'; export default class StrykerConfigWriter { public static inject = tokens(commonTokens.logger, initializerTokens.out); constructor(private readonly log: Logger, private readonly out: typeof console.log) {} public guardForExistingConfig() { - if (existsSync(STRYKER_CONFIG_FILE)) { - const msg = 'Stryker config file "stryker.conf.js" already exists in the current directory. Please remove it and try again.'; + this.checkIfConfigFileExists(STRYKER_JS_CONFIG_FILE); + this.checkIfConfigFileExists(STRYKER_JSON_CONFIG_FILE); + } + + private checkIfConfigFileExists(file: string) { + if (existsSync(file)) { + const msg = `Stryker config file "${file}" already exists in the current directory. Please remove it and try again.`; this.log.error(msg); throw new Error(msg); } } /** - * Create stryker.conf.js based on the chosen framework and test runner + * Create config based on the chosen framework and test runner * @function */ public write( @@ -35,8 +41,9 @@ export default class StrykerConfigWriter { selectedTranspilers: null | PromptOption[], selectedReporters: PromptOption[], selectedPackageManager: PromptOption, - additionalPiecesOfConfig: Array> - ): Promise { + additionalPiecesOfConfig: Array>, + exportAsJson: boolean + ): Promise { const configObject: Partial = { mutator: selectedMutator ? selectedMutator.name : '', packageManager: selectedPackageManager.name, @@ -47,19 +54,20 @@ export default class StrykerConfigWriter { this.configureTestFramework(configObject, selectedTestFramework); Object.assign(configObject, ...additionalPiecesOfConfig); - return this.writeStrykerConfig(configObject); + return this.writeStrykerConfig(configObject, exportAsJson); } /** - * Create stryker.conf.js based on the chosen preset + * Create config based on the chosen preset * @function */ - public async writePreset(presetConfig: PresetConfiguration) { - return this.writeStrykerConfigRaw( - presetConfig.config, - `// This config was generated using a preset. - // Please see the handbook for more information: ${presetConfig.handbookUrl}` - ); + 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}`, + ...presetConfig.config + }; + + return this.writeStrykerConfig(config, exportAsJson); } private configureTestFramework(configObject: Partial, selectedTestFramework: null | PromptOption) { @@ -71,28 +79,45 @@ export default class StrykerConfigWriter { } } - private async writeStrykerConfigRaw(rawConfig: string, rawHeader = '') { - this.out('Writing & formatting stryker.conf.js...'); - const formattedConf = `${rawHeader} - module.exports = function(config){ - config.set( - ${rawConfig} - ); - }`; - await fs.writeFile(STRYKER_CONFIG_FILE, formattedConf); + private writeStrykerConfig(config: Partial, exportAsJson: boolean) { + if (exportAsJson) { + return this.writeJsonConfig(config); + } else { + return this.writeJsConfig(config); + } + } + + private async writeJsConfig(commentedConfig: Partial) { + this.out(`Writing & formatting ${STRYKER_JS_CONFIG_FILE}...`); + const rawConfig = this.stringify(commentedConfig); + const formattedConfig = `/** + * @type {import('@stryker-mutator/api/core').StrykerOptions} + */ + module.exports = ${rawConfig};`; + await fs.writeFile(STRYKER_JS_CONFIG_FILE, formattedConfig); try { - await childProcessAsPromised.exec(`npx prettier --write ${STRYKER_CONFIG_FILE}`); + await childProcessAsPromised.exec(`npx prettier --write ${STRYKER_JS_CONFIG_FILE}`); } catch (error) { this.log.debug('Prettier exited with error', error); this.out('Unable to format stryker.conf.js file for you. This is not a big problem, but it might look a bit messy 🙈.'); } + + return STRYKER_JS_CONFIG_FILE; } - private writeStrykerConfig(configObject: Partial) { - return this.writeStrykerConfigRaw(this.wrapInModule(configObject)); + private async writeJsonConfig(commentedConfig: Partial) { + this.out(`Writing & formatting ${STRYKER_JSON_CONFIG_FILE}...`); + const typedConfig = { + $schema: 'https://raw.githubusercontent.com/stryker-mutator/stryker/master/packages/api/schema/stryker-core.json', + ...commentedConfig + }; + const formattedConfig = this.stringify(typedConfig); + await fs.writeFile(STRYKER_JSON_CONFIG_FILE, formattedConfig); + + return STRYKER_JSON_CONFIG_FILE; } - private wrapInModule(configObject: Partial): string { - return JSON.stringify(configObject, null, 2); + private stringify(input: object): string { + return JSON.stringify(input, undefined, 2); } } diff --git a/packages/core/src/initializer/StrykerInitializer.ts b/packages/core/src/initializer/StrykerInitializer.ts index 96cc502303..6116a02c5c 100644 --- a/packages/core/src/initializer/StrykerInitializer.ts +++ b/packages/core/src/initializer/StrykerInitializer.ts @@ -49,13 +49,14 @@ export default class StrykerInitializer { this.configWriter.guardForExistingConfig(); this.patchProxies(); const selectedPreset = await this.selectPreset(); + let configFileName: string; if (selectedPreset) { - await this.initiatePreset(this.configWriter, selectedPreset); + configFileName = await this.initiatePreset(this.configWriter, selectedPreset); } else { - await this.initiateCustom(this.configWriter); + configFileName = await this.initiateCustom(this.configWriter); } await this.gitignoreWriter.addStrykerTempFolder(); - this.out('Done configuring stryker. Please review `stryker.conf.js`, you might need to configure transpilers or your test runner correctly.'); + this.out(`Done configuring stryker. Please review "${configFileName}", you might need to configure transpilers or your test runner correctly.`); this.out("Let's kill some mutants with this command: `stryker run`"); } @@ -86,9 +87,11 @@ export default class StrykerInitializer { private async initiatePreset(configWriter: StrykerConfigWriter, selectedPreset: Preset) { const presetConfig = await selectedPreset.createConfig(); - await configWriter.writePreset(presetConfig); + const isJsonSelected = await this.selectJsonConfigType(); + const configFileName = await configWriter.writePreset(presetConfig, isJsonSelected); const selectedPackageManager = await this.selectPackageManager(); this.installNpmDependencies(presetConfig.dependencies, selectedPackageManager); + return configFileName; } private async initiateCustom(configWriter: StrykerConfigWriter) { @@ -99,22 +102,25 @@ export default class StrykerInitializer { const selectedTranspilers = await this.selectTranspilers(); const selectedReporters = await this.selectReporters(); const selectedPackageManager = await this.selectPackageManager(); + const isJsonSelected = await this.selectJsonConfigType(); const npmDependencies = this.getSelectedNpmDependencies( [selectedTestRunner, selectedTestFramework, selectedMutator].concat(selectedTranspilers).concat(selectedReporters) ); - await configWriter.write( + const configFileName = await configWriter.write( selectedTestRunner, selectedTestFramework, selectedMutator, selectedTranspilers, selectedReporters, selectedPackageManager, - await this.fetchAdditionalConfig(npmDependencies) + await this.fetchAdditionalConfig(npmDependencies), + isJsonSelected ); this.installNpmDependencies( npmDependencies.map(pkg => pkg.name), selectedPackageManager ); + return configFileName; } private async selectTestRunner(): Promise { @@ -208,6 +214,10 @@ export default class StrykerInitializer { ]); } + private async selectJsonConfigType(): Promise { + return this.inquirer.promptJsonConfigType(); + } + private getSelectedNpmDependencies(selectedOptions: Array): PackageInfo[] { return filterEmpty(filterEmpty(selectedOptions).map(option => option.pkg)); } diff --git a/packages/core/src/initializer/StrykerInquirer.ts b/packages/core/src/initializer/StrykerInquirer.ts index 542769115c..d5b18693ce 100644 --- a/packages/core/src/initializer/StrykerInquirer.ts +++ b/packages/core/src/initializer/StrykerInquirer.ts @@ -90,4 +90,17 @@ export class StrykerInquirer { }); return options.filter(_ => _.name === answers.packageManager)[0]; } + + public async promptJsonConfigType(): Promise { + const json = 'JSON'; + + const answers = await inquirer.prompt<{ configType: string }>({ + choices: [json, 'JavaScript'], + default: json, + message: 'What kind of config do you want?', + name: 'configType', + type: 'list' + }); + return answers.configType === json; + } } diff --git a/packages/core/src/initializer/presets/AngularPreset.ts b/packages/core/src/initializer/presets/AngularPreset.ts index 600641e300..d14dde08b7 100644 --- a/packages/core/src/initializer/presets/AngularPreset.ts +++ b/packages/core/src/initializer/presets/AngularPreset.ts @@ -1,5 +1,7 @@ import * as os from 'os'; +import { StrykerOptions } from '@stryker-mutator/api/core'; + import Preset from './Preset'; import PresetConfiguration from './PresetConfiguration'; @@ -9,28 +11,24 @@ 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 config = `{ - mutate: [ - 'src/**/*.ts', - '!src/**/*.spec.ts', - '!src/test.ts', - '!src/environments/*.ts' - ], - mutator: 'typescript', - testRunner: 'karma', - karma: { - configFile: 'src/karma.conf.js', - projectType: 'angular-cli', - config: { - browsers: ['ChromeHeadless'] - } - }, - reporters: ['progress', 'clear-text', 'html'], - maxConcurrentTestRunners: ${Math.floor( - os.cpus().length / 2 - )}, // Recommended to use about half of your available cores when running stryker with angular. - coverageAnalysis: 'off' - }`; + private readonly config: Partial = { + mutate: ['src/**/*.ts', '!src/**/*.spec.ts', '!src/test.ts', '!src/environments/*.ts'], + mutator: 'typescript', + testRunner: 'karma', + karma: { + configFile: 'src/karma.conf.js', + projectType: 'angular-cli', + config: { + browsers: ['ChromeHeadless'] + } + }, + reporters: ['progress', 'clear-text', 'html'], + maxConcurrentTestRunners: Math.floor(os.cpus().length / 2), + // eslint-disable-next-line @typescript-eslint/camelcase + maxConcurrentTestRunners_comment: 'Recommended to use about half of your available cores when running stryker with angular', + coverageAnalysis: 'off' + }; + public async createConfig(): Promise { return { config: this.config, handbookUrl, dependencies: this.dependencies }; } diff --git a/packages/core/src/initializer/presets/PresetConfiguration.ts b/packages/core/src/initializer/presets/PresetConfiguration.ts index 1c669f3284..ac5d0d276b 100644 --- a/packages/core/src/initializer/presets/PresetConfiguration.ts +++ b/packages/core/src/initializer/presets/PresetConfiguration.ts @@ -1,5 +1,7 @@ +import { StrykerOptions } from '@stryker-mutator/api/core'; + export default interface PresetConfiguration { - config: string; + config: Partial; handbookUrl: string; dependencies: string[]; } diff --git a/packages/core/src/initializer/presets/ReactPreset.ts b/packages/core/src/initializer/presets/ReactPreset.ts index ef2488711a..84746cb1e6 100644 --- a/packages/core/src/initializer/presets/ReactPreset.ts +++ b/packages/core/src/initializer/presets/ReactPreset.ts @@ -1,4 +1,6 @@ import inquirer = require('inquirer'); +import { StrykerOptions } from '@stryker-mutator/api/core'; + import Preset from './Preset'; import PresetConfiguration from './PresetConfiguration'; @@ -12,27 +14,28 @@ export class ReactPreset implements Preset { public readonly name = 'create-react-app'; private readonly generalDependencies = ['@stryker-mutator/core', '@stryker-mutator/jest-runner']; - private readonly sharedConfig = `testRunner: 'jest', + private readonly sharedConfig: Partial = { + testRunner: 'jest', reporters: ['progress', 'clear-text', 'html'], coverageAnalysis: 'off', jest: { projectType: 'create-react-app' } - `; + }; private readonly tsxDependencies = ['@stryker-mutator/typescript', ...this.generalDependencies]; - private readonly tsxConf = `{ - mutate: ['src/**/*.ts?(x)', '!src/**/*@(.test|.spec|Spec).ts?(x)'], - mutator: 'typescript', - ${this.sharedConfig} - }`; + private readonly tsxConf: Partial = { + mutate: ['src/**/*.ts?(x)', '!src/**/*@(.test|.spec|Spec).ts?(x)'], + mutator: 'typescript', + ...this.sharedConfig + }; private readonly jsxDependencies = ['@stryker-mutator/javascript-mutator', ...this.generalDependencies]; - private readonly jsxConf = `{ - mutate: ['src/**/*.js?(x)', '!src/**/*@(.test|.spec|Spec).js?(x)'], - mutator: 'javascript', - ${this.sharedConfig} - }`; + private readonly jsxConf: Partial = { + mutate: ['src/**/*.js?(x)', '!src/**/*@(.test|.spec|Spec).js?(x)'], + mutator: 'javascript', + ...this.sharedConfig + }; public async createConfig(): Promise { const choices: Array> = ['JSX', 'TSX']; diff --git a/packages/core/src/initializer/presets/VueJsPreset.ts b/packages/core/src/initializer/presets/VueJsPreset.ts index ecc0c64ea0..4731b760c5 100644 --- a/packages/core/src/initializer/presets/VueJsPreset.ts +++ b/packages/core/src/initializer/presets/VueJsPreset.ts @@ -1,4 +1,6 @@ import inquirer = require('inquirer'); +import { StrykerOptions } from '@stryker-mutator/api/core'; + import Preset from './Preset'; import PresetConfiguration from './PresetConfiguration'; @@ -13,31 +15,31 @@ export class VueJsPreset implements Preset { private readonly generalDependencies = ['@stryker-mutator/core', '@stryker-mutator/vue-mutator']; private readonly jestDependency = '@stryker-mutator/jest-runner'; - private readonly jestConf = `{ - mutate: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'], - mutator: 'vue', - testRunner: 'jest', - jest: { - // config: require('path/to/your/custom/jestConfig.js') - }, - reporters: ['progress', 'clear-text', 'html'], - coverageAnalysis: 'off' - }`; + private readonly jestConf: Partial = { + mutate: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'], + mutator: 'vue', + testRunner: 'jest', + 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 = `{ - mutate: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'], - mutator: 'vue', - testRunner: 'karma', - karma: { - configFile: 'test/unit/karma.conf.js', - config: { - browsers: ['ChromeHeadless'] - } - }, - reporters: ['progress', 'clear-text', 'html'], - coverageAnalysis: 'off' - }`; + private readonly karmaConf: Partial = { + mutate: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'], + mutator: 'vue', + testRunner: 'karma', + karma: { + configFile: 'test/unit/karma.conf.js', + config: { + browsers: ['ChromeHeadless'] + } + }, + reporters: ['progress', 'clear-text', 'html'], + coverageAnalysis: 'off' + }; public async createConfig(): Promise { const testRunnerChoices: Array> = ['karma', 'jest']; @@ -57,13 +59,13 @@ export class VueJsPreset implements Preset { const chosenTestRunner = testRunnerAnswers.testRunner; const chosenScript = scriptAnswers.script; return { - config: this.getConfigString(chosenTestRunner), + config: this.getConfig(chosenTestRunner), dependencies: this.createDependencies(chosenTestRunner, chosenScript), handbookUrl }; } - private getConfigString(testRunner: string) { + private getConfig(testRunner: string) { if (testRunner === 'karma') { return this.karmaConf; } else if (testRunner === 'jest') { diff --git a/packages/core/test/unit/initializer/Presets.spec.ts b/packages/core/test/unit/initializer/Presets.spec.ts index f1ccfbd64e..14b5b12267 100644 --- a/packages/core/test/unit/initializer/Presets.spec.ts +++ b/packages/core/test/unit/initializer/Presets.spec.ts @@ -25,12 +25,12 @@ describe('Presets', () => { it('should mutate typescript', async () => { const config = await angularPreset.createConfig(); - expect(config.config).to.contain("mutator: 'typescript'"); + expect(config.config.mutator).to.eq('typescript'); }); it('should use the angular-cli', async () => { const config = await angularPreset.createConfig(); - expect(config.config).to.contain("projectType: 'angular-cli'"); + expect(config.config.karma.projectType).to.eq('angular-cli'); }); }); @@ -50,7 +50,7 @@ describe('Presets', () => { choice: 'TSX' }); const config = await reactPreset.createConfig(); - expect(config.config).to.contain("mutator: 'typescript'"); + expect(config.config.mutator).to.eq('typescript'); }); it('should install @stryker-mutator/typescript when TSX is chosen', async () => { @@ -66,7 +66,7 @@ describe('Presets', () => { choice: 'JSX' }); const config = await reactPreset.createConfig(); - expect(config.config).to.include("mutator: 'javascript'"); + expect(config.config.mutator).to.eq('javascript'); }); it('should install @stryker-mutator/javascript-mutator when JSX is chosen', async () => { @@ -95,7 +95,7 @@ describe('Presets', () => { it('should use the vue mutator', async () => { const config = await vueJsPreset.createConfig(); - expect(config.config).to.contain("mutator: 'vue'"); + expect(config.config.mutator).to.contain('vue'); }); it('should install @stryker-mutator/karma-runner when karma is chosen', async () => { diff --git a/packages/core/test/unit/initializer/StrykerInitializer.spec.ts b/packages/core/test/unit/initializer/StrykerInitializer.spec.ts index 3ed60cbee8..377be2cd6f 100644 --- a/packages/core/test/unit/initializer/StrykerInitializer.spec.ts +++ b/packages/core/test/unit/initializer/StrykerInitializer.spec.ts @@ -89,7 +89,7 @@ describe(StrykerInitializer.name, () => { presets.push(presetMock); }); - it('should prompt for preset, test runner, test framework, mutator, transpilers, reporters, and package manager', async () => { + it('should prompt for preset, test runner, test framework, mutator, transpilers, reporters, package manager and config type', async () => { arrangeAnswers({ mutator: 'typescript', packageManager: 'yarn', @@ -98,14 +98,24 @@ describe(StrykerInitializer.name, () => { testRunner: 'awesome', transpilers: ['webpack'] }); + await sut.initialize(); - expect(inquirerPrompt).callCount(7); - const [promptPreset, promptTestRunner, promptTestFramework, promptMutator, promptPackageManagers]: Array> = [ + + expect(inquirerPrompt).callCount(8); + const [ + promptPreset, + promptTestRunner, + promptTestFramework, + promptMutator, + promptPackageManagers, + promptConfigTypes + ]: Array> = [ inquirerPrompt.getCall(0).args[0], inquirerPrompt.getCall(1).args[0], inquirerPrompt.getCall(2).args[0], inquirerPrompt.getCall(3).args[0], - inquirerPrompt.getCall(6).args[0] + inquirerPrompt.getCall(6).args[0], + inquirerPrompt.getCall(7).args[0] ]; const [promptTranspilers, promptReporters]: Array> = [ inquirerPrompt.getCall(4).args[0], @@ -127,43 +137,47 @@ describe(StrykerInitializer.name, () => { expect(promptReporters.choices).to.deep.eq(['dimension', 'mars', 'html', 'clear-text', 'progress', 'dashboard']); expect(promptPackageManagers.type).to.eq('list'); expect(promptPackageManagers.choices).to.deep.eq(['npm', 'yarn']); + expect(promptConfigTypes.type).to.eq('list'); + expect(promptConfigTypes.choices).to.deep.eq(['JSON', 'JavaScript']); }); it('should immediately complete when a preset and package manager is chosen', async () => { inquirerPrompt.resolves({ packageManager: 'npm', - preset: 'awesome-preset' + preset: 'awesome-preset', + configType: 'JSON' }); resolvePresetConfig(); await sut.initialize(); - expect(inquirerPrompt).callCount(2); + expect(inquirerPrompt).callCount(3); expect(out).calledWith( - 'Done configuring stryker. Please review `stryker.conf.js`, you might need to configure transpilers or your test runner correctly.' + 'Done configuring stryker. Please review "stryker.conf.json", you might need to configure transpilers or your test runner correctly.' ); expect(out).calledWith("Let's kill some mutants with this command: `stryker run`"); }); - it('should correctly write and format the stryker configuration file', async () => { - const config = `{ - 'awesome-conf': 'awesome', - }`; + it('should correctly write and format the stryker js configuration file', async () => { const handbookUrl = 'https://awesome-preset.org'; + const config = { + comment: `This config was generated using a preset. Please see the handbook for more information: ${handbookUrl}`, + awesomeConf: 'awesome' + }; childExec.resolves(); resolvePresetConfig({ config, handbookUrl }); - const expectedOutput = ` - // This config was generated using a preset. - // Please see the handbook for more information: ${handbookUrl} - module.exports = function(config){ - config.set( - ${config} - ); - }`; + const expectedOutput = `/** + * @type {import('@stryker-mutator/api/core').StrykerOptions} + */ + module.exports = { + "comment": "${config.comment}", + "awesomeConf": "${config.awesomeConf}" + };`; inquirerPrompt.resolves({ packageManager: 'npm', - preset: 'awesome-preset' + preset: 'awesome-preset', + configType: 'JavaScript' }); await sut.initialize(); expectStrykerConfWritten(expectedOutput); @@ -176,7 +190,8 @@ describe(StrykerInitializer.name, () => { childExec.rejects(expectedError); inquirerPrompt.resolves({ packageManager: 'npm', - preset: 'awesome-preset' + preset: 'awesome-preset', + configType: 'JavaScript' }); resolvePresetConfig(); @@ -192,7 +207,8 @@ describe(StrykerInitializer.name, () => { resolvePresetConfig({ dependencies: ['my-awesome-dependency', 'another-awesome-dependency'] }); inquirerPrompt.resolves({ packageManager: 'npm', - preset: 'awesome-preset' + preset: 'awesome-preset', + configType: 'JSON' }); await sut.initialize(); expect(fsWriteFile).calledOnce; @@ -203,17 +219,21 @@ describe(StrykerInitializer.name, () => { resolvePresetConfig(); inquirerPrompt.resolves({ packageManager: 'npm', - preset: 'awesome-preset' + preset: 'awesome-preset', + configType: 'JSON' }); await sut.initialize(); - expect(inquirerPrompt).callCount(2); - const [promptPreset, promptPackageManager]: Array> = [ + expect(inquirerPrompt).callCount(3); + const [promptPreset, promptConfigType, promptPackageManager]: Array> = [ inquirerPrompt.getCall(0).args[0], - inquirerPrompt.getCall(1).args[0] + inquirerPrompt.getCall(1).args[0], + inquirerPrompt.getCall(2).args[0] ]; expect(promptPreset.type).to.eq('list'); expect(promptPreset.name).to.eq('preset'); expect(promptPreset.choices).to.deep.eq(['awesome-preset', new inquirer.Separator(), 'None/other']); + expect(promptConfigType.type).to.eq('list'); + expect(promptConfigType.choices).to.deep.eq(['JSON', 'JavaScript']); expect(promptPackageManager.type).to.eq('list'); expect(promptPackageManager.choices).to.deep.eq(['npm', 'yarn']); }); @@ -230,12 +250,13 @@ describe(StrykerInitializer.name, () => { reporters: ['dimension', 'mars'], testFramework: 'None/other', testRunner: 'awesome', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); await sut.initialize(); - expect(inquirerPrompt).callCount(7); + expect(inquirerPrompt).callCount(8); expect(out).calledWith('OK, downgrading coverageAnalysis to "all"'); - expect(fs.promises.writeFile).calledWith('stryker.conf.js', sinon.match('"coverageAnalysis": "all"')); + expect(fs.promises.writeFile).calledWith('stryker.conf.json', sinon.match('"coverageAnalysis": "all"')); }); it('should install any additional dependencies', async () => { @@ -245,7 +266,8 @@ describe(StrykerInitializer.name, () => { reporters: ['dimension', 'mars'], testFramework: 'awesome', testRunner: 'awesome', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); await sut.initialize(); expect(out).calledWith('Installing NPM dependencies...'); @@ -264,13 +286,14 @@ describe(StrykerInitializer.name, () => { reporters: ['dimension', 'mars', 'progress'], testFramework: 'awesome', testRunner: 'awesome', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); await sut.initialize(); const matchNormalized = (expected: string) => sinon.match((actual: string) => normalizeWhitespaces(actual).includes(normalizeWhitespaces(expected))); expect(fs.promises.writeFile).calledWith( - 'stryker.conf.js', + 'stryker.conf.json', matchNormalized('"testRunner": "awesome"') .and(matchNormalized('"testFramework": "awesome"')) .and(matchNormalized('"packageManager": "npm"')) @@ -288,11 +311,12 @@ describe(StrykerInitializer.name, () => { reporters: [], testFramework: 'hyper', testRunner: 'hyper', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); await sut.initialize(); - expect(fs.promises.writeFile).calledWith('stryker.conf.js', sinon.match('"someOtherSetting": "enabled"')); - expect(fs.promises.writeFile).calledWith('stryker.conf.js', sinon.match('"files": []')); + expect(fs.promises.writeFile).calledWith('stryker.conf.json', sinon.match('"someOtherSetting": "enabled"')); + expect(fs.promises.writeFile).calledWith('stryker.conf.json', sinon.match('"files": []')); }); describe('but no testFramework can be found that supports the testRunner', () => { @@ -301,14 +325,15 @@ describe(StrykerInitializer.name, () => { packageManager: 'npm', reporters: ['dimension', 'mars'], testRunner: 'ghost', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }) ); it('should not prompt for test framework', async () => { await sut.initialize(); - expect(inquirerPrompt).callCount(6); + expect(inquirerPrompt).callCount(7); expect(inquirerPrompt).not.calledWithMatch(sinon.match({ name: 'testFramework' })); }); @@ -316,7 +341,7 @@ describe(StrykerInitializer.name, () => { await sut.initialize(); expect(out).calledWith('No stryker test framework plugin found that is compatible with ghost, downgrading coverageAnalysis to "all"'); - expect(fs.promises.writeFile).calledWith('stryker.conf.js', sinon.match('"coverageAnalysis": "all"')); + expect(fs.promises.writeFile).calledWith('stryker.conf.json', sinon.match('"coverageAnalysis": "all"')); }); }); @@ -327,7 +352,8 @@ describe(StrykerInitializer.name, () => { packageManager: 'npm', reporters: [], testRunner: 'ghost', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); return expect(sut.initialize()).to.eventually.be.rejectedWith(expectedError); @@ -339,7 +365,8 @@ describe(StrykerInitializer.name, () => { packageManager: 'npm', reporters: [], testRunner: 'ghost', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); stubTranspilers('@stryker-mutator/webpack-transpiler'); stubPackageClient({ '@stryker-mutator/webpack-transpiler': null }); @@ -363,7 +390,8 @@ describe(StrykerInitializer.name, () => { inquirerPrompt.resolves({ packageManager: 'npm', reporters: ['clear-text'], - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); await sut.initialize(); @@ -382,7 +410,8 @@ describe(StrykerInitializer.name, () => { packageManager: 'npm', reporters: ['clear-text'], testRunner: 'awesome', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); stubMutators('stryker-javascript'); stubTranspilers('stryker-webpack'); @@ -408,7 +437,8 @@ describe(StrykerInitializer.name, () => { packageManager: 'npm', reporters: ['clear-text'], testRunner: 'awesome', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); stubPackageClient({ 'stryker-awesome-runner': null, 'stryker-webpack': null }); @@ -430,7 +460,8 @@ describe(StrykerInitializer.name, () => { inquirerPrompt.resolves({ packageManager: 'npm', reporters: ['clear-text'], - testRunner: 'awesome' + testRunner: 'awesome', + configType: 'JSON' }); stubPackageClient({ 'stryker-awesome-runner': null, 'stryker-javascript': null }); @@ -453,7 +484,8 @@ describe(StrykerInitializer.name, () => { packageManager: 'npm', reporters: ['clear-text'], testRunner: 'awesome', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); stubPackageClient({ 'stryker-awesome-runner': null, 'stryker-javascript': null, 'stryker-webpack': null }); @@ -475,7 +507,8 @@ describe(StrykerInitializer.name, () => { packageManager: 'npm', reporters: ['clear-text'], testRunner: 'awesome', - transpilers: ['webpack'] + transpilers: ['webpack'], + configType: 'JSON' }); restClientPackage.get.rejects(); @@ -587,7 +620,7 @@ describe(StrykerInitializer.name, () => { function resolvePresetConfig(presetConfigOverrides?: Partial) { const presetConfig: PresetConfiguration = { - config: '', + config: {}, dependencies: [], handbookUrl: '' }; diff --git a/packages/grunt-stryker/README.md b/packages/grunt-stryker/README.md index b22c27d31a..c85005d94f 100644 --- a/packages/grunt-stryker/README.md +++ b/packages/grunt-stryker/README.md @@ -124,13 +124,11 @@ The content of the file `stryker.conf.js` in this example is: ```javascript // stryker.conf.js -module.exports = function(config){ - config.set({ - files: [{ pattern: 'src/**/*.js', mutated: true} , 'test/myFirstFile.spec.js', 'test/mySecondFile.spec.js'], - testFramework: 'jasmine', - testRunner: 'karma' - }); -} +module.exports = { + files: [{ pattern: 'src/**/*.js', mutated: true} , 'test/myFirstFile.spec.js', 'test/mySecondFile.spec.js'], + testFramework: 'jasmine', + testRunner: 'karma' +}; ``` **Note:** It's not possible to exclude files in a config file using `!` like: `!myFile.js`. This is possible when you don't use a config file but define the options your Gruntfile. See [node-glob](https://github.com/isaacs/node-glob#glob) to know what *is* possible. From 58d68e7b2211eed988738a8626f510dcd00051c8 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 11 Mar 2020 15:49:00 +0100 Subject: [PATCH 6/9] Improve wording --- packages/core/src/initializer/StrykerInquirer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/initializer/StrykerInquirer.ts b/packages/core/src/initializer/StrykerInquirer.ts index d5b18693ce..182f31da98 100644 --- a/packages/core/src/initializer/StrykerInquirer.ts +++ b/packages/core/src/initializer/StrykerInquirer.ts @@ -97,7 +97,7 @@ export class StrykerInquirer { const answers = await inquirer.prompt<{ configType: string }>({ choices: [json, 'JavaScript'], default: json, - message: 'What kind of config do you want?', + message: 'What file type do you want for your config file?', name: 'configType', type: 'list' }); From 26e21b27018361787ee0e0705636e7983e1b9727 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 11 Mar 2020 16:07:10 +0100 Subject: [PATCH 7/9] Spread the joy accross or e2e tests --- e2e/test/babel-transpiling/stryker.conf.js | 38 ++++++++++------------ e2e/test/command/stryker.conf.js | 15 --------- e2e/test/command/stryker.conf.json | 18 ++++++++++ e2e/test/exit-prematurely/stryker.conf.js | 36 ++++++++++---------- 4 files changed, 53 insertions(+), 54 deletions(-) delete mode 100644 e2e/test/command/stryker.conf.js create mode 100644 e2e/test/command/stryker.conf.json diff --git a/e2e/test/babel-transpiling/stryker.conf.js b/e2e/test/babel-transpiling/stryker.conf.js index e6cb4cedd6..f398fca69c 100644 --- a/e2e/test/babel-transpiling/stryker.conf.js +++ b/e2e/test/babel-transpiling/stryker.conf.js @@ -1,21 +1,19 @@ -module.exports = function (config) { - config.set({ - mutate: [ - 'src/*.js' - ], - testFramework: 'mocha', - testRunner: 'mocha', - coverageAnalysis: 'off', - mutator: { - name: 'javascript', - plugins: [['pipelineOperator', { proposal: 'minimal' }]] - }, - transpilers: [ - 'babel' - ], - timeoutMS: 60000, - reporters: ['clear-text', 'html', 'event-recorder'], - maxConcurrentTestRunners: 2, - logLevel: 'info' - }); +module.exports = { + mutate: [ + 'src/*.js' + ], + testFramework: 'mocha', + testRunner: 'mocha', + coverageAnalysis: 'off', + mutator: { + name: 'javascript', + plugins: [['pipelineOperator', { proposal: 'minimal' }]] + }, + transpilers: [ + 'babel' + ], + timeoutMS: 60000, + reporters: ['clear-text', 'html', 'event-recorder'], + maxConcurrentTestRunners: 2, + logLevel: 'info' }; diff --git a/e2e/test/command/stryker.conf.js b/e2e/test/command/stryker.conf.js deleted file mode 100644 index e8dc10c203..0000000000 --- a/e2e/test/command/stryker.conf.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = function (config) { - config.set({ - mutate: ['src/*.js'], - testFramework: 'mocha', - coverageAnalysis: 'off', - reporters: ['clear-text', 'event-recorder'], - mutator: 'javascript', - maxConcurrentTestRunners: 2, - commandRunner: { - command: 'npm run mocha' - }, - symlinkNodeModules: false, - fileLogLevel: 'info' - }); -}; diff --git a/e2e/test/command/stryker.conf.json b/e2e/test/command/stryker.conf.json new file mode 100644 index 0000000000..b60da08268 --- /dev/null +++ b/e2e/test/command/stryker.conf.json @@ -0,0 +1,18 @@ +{ + "mutate": [ + "src/*.js" + ], + "testFramework": "mocha", + "coverageAnalysis": "off", + "reporters": [ + "clear-text", + "event-recorder" + ], + "mutator": "javascript", + "maxConcurrentTestRunners": 2, + "commandRunner": { + "command": "npm run mocha" + }, + "symlinkNodeModules": false, + "fileLogLevel": "info" +} diff --git a/e2e/test/exit-prematurely/stryker.conf.js b/e2e/test/exit-prematurely/stryker.conf.js index d47663ee3b..b7422238b2 100644 --- a/e2e/test/exit-prematurely/stryker.conf.js +++ b/e2e/test/exit-prematurely/stryker.conf.js @@ -1,19 +1,17 @@ -module.exports = function (config) { - config.set({ - mutate: [ - 'src/*.js' - ], - testFramework: 'mocha', - testRunner: 'mocha', - coverageAnalysis: 'off', - mutator: 'javascript', - transpilers: [ - 'babel' - ], - timeoutMS: 60000, - reporters: ['clear-text', 'html', 'event-recorder'], - maxConcurrentTestRunners: 2, - logLevel: 'info', - fileLogLevel: 'info' - }); -}; +module.exports = { + mutate: [ + 'src/*.js' + ], + testFramework: 'mocha', + testRunner: 'mocha', + coverageAnalysis: 'off', + mutator: 'javascript', + transpilers: [ + 'babel' + ], + timeoutMS: 60000, + reporters: ['clear-text', 'html', 'event-recorder'], + maxConcurrentTestRunners: 2, + logLevel: 'info', + fileLogLevel: 'info' +} From 9cda1308be78ddccc66f6958963ee7ed4f39b5d1 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 11 Mar 2020 16:07:28 +0100 Subject: [PATCH 8/9] docs(readme): update readme's --- packages/babel-transpiler/README.md | 2 +- packages/jasmine-framework/README.md | 11 ++++---- packages/jasmine-runner/README.md | 22 ++++++++-------- packages/javascript-mutator/README.md | 2 +- packages/jest-runner/README.md | 12 ++++----- packages/karma-runner/README.md | 24 ++++++++---------- packages/mocha-framework/README.md | 16 ++++++------ packages/mocha-runner/README.md | 36 +++++++++++++-------------- packages/typescript/README.md | 6 ++--- packages/vue-mutator/README.md | 2 +- packages/webpack-transpiler/README.md | 4 +-- 11 files changed, 63 insertions(+), 74 deletions(-) diff --git a/packages/babel-transpiler/README.md b/packages/babel-transpiler/README.md index 6b7e9ae3ee..d8b220d05e 100644 --- a/packages/babel-transpiler/README.md +++ b/packages/babel-transpiler/README.md @@ -24,7 +24,7 @@ Next, install this package: npm install --save-dev @stryker-mutator/babel-transpiler @babel/core ``` -Next, open up your `stryker.conf.js` file and add the following properties: +Next, open up your `stryker.conf.js` (or `stryker.conf.json`) file and add the following properties: ```javascript babel: { diff --git a/packages/jasmine-framework/README.md b/packages/jasmine-framework/README.md index 28a21e2c84..9105238271 100644 --- a/packages/jasmine-framework/README.md +++ b/packages/jasmine-framework/README.md @@ -7,6 +7,7 @@ ![Stryker](https://github.com/stryker-mutator/stryker/raw/master/stryker-80x80.png) # Stryker Jasmine + A plugin to use the Jasmine test framework in [Stryker](https://stryker-mutator.io), the JavaScript mutation testing framework. This plugin provides beforeEach, afterEach and filter hooks to Stryker, so you are able to use `coverageAnalysis: 'perTest'` with jasmine. @@ -19,7 +20,7 @@ Install `@stryker-mutator/jasmine-framework` and `jasmine-core` into your projec $ npm install @stryker-mutator/jasmine-framework jasmine-core --save-dev ``` -*Note: @stryker-mutator/jasmine-framework only works with jasmine-core >= v2* +_Note: @stryker-mutator/jasmine-framework only works with jasmine-core >= v2_ Since @stryker-mutator/jasmine-framework is a plugin for Stryker, you likely have it installed already, but in case you don't: @@ -32,11 +33,9 @@ $ npm install @stryker-mutator/core --save-dev Set the `testFramework` setting to `'jasmine'` in your stryker config file. ```javascript -// stryker.conf.js -module.exports = function(config) { - config.set({ - testFramework: 'jasmine', - }); +// `stryker.conf.js` (or stryker.conf.json) +module.exports = { + testFramework: 'jasmine' }; ``` diff --git a/packages/jasmine-runner/README.md b/packages/jasmine-runner/README.md index 8757fdb979..378bdd52ab 100644 --- a/packages/jasmine-runner/README.md +++ b/packages/jasmine-runner/README.md @@ -26,21 +26,19 @@ As such, you should make sure you have the correct versions of its dependencies ## Configuring -You can configure the jasmine test runner in the `stryker.conf.js` file. +You can configure the jasmine test runner in the `stryker.conf.js` (or `stryker.conf.json`) file. ```javascript // stryker.conf.js -module.exports = function (config) { - config.set({ - // ... - // not required, but boosts performance - coverageAnalysis: 'perTest', - // not required, but will allow you to use coverageAnalysis "perTest". Note: This requires `stryker-jasmine` to also be installed. - testFramework: 'jasmine', - testRunner: 'jasmine', - jasmineConfigFile: 'spec/support/jasmine.json' - // ... - }); +module.exports = { + // ... + // not required, but boosts performance + coverageAnalysis: 'perTest', + // not required, but will allow you to use coverageAnalysis "perTest". Note: This requires `stryker-jasmine` to also be installed. + testFramework: 'jasmine', + testRunner: 'jasmine', + jasmineConfigFile: 'spec/support/jasmine.json' + // ... } ``` diff --git a/packages/javascript-mutator/README.md b/packages/javascript-mutator/README.md index 16b62fa5f3..6de53957f8 100644 --- a/packages/javascript-mutator/README.md +++ b/packages/javascript-mutator/README.md @@ -20,7 +20,7 @@ Next, install this package: npm install --save-dev @stryker-mutator/javascript-mutator ``` -Now open up your stryker.conf.js file and add the following components: +Now open up your `stryker.conf.js` (or `stryker.conf.json`) file and add the following components: ```javascript mutator: 'javascript', diff --git a/packages/jest-runner/README.md b/packages/jest-runner/README.md index ed32c6cc17..1e7546a1a2 100644 --- a/packages/jest-runner/README.md +++ b/packages/jest-runner/README.md @@ -61,13 +61,11 @@ The @stryker-mutator/jest-runner also provides a couple of configurable options The following is an example stryker.conf.js file: ```javascript -module.exports = function(config) { - config.set({ - testRunner: "jest", - mutator: "javascript", - coverageAnalysis: "off", - mutate: ["src/**/*.js"] - }); +module.exports = { + testRunner: "jest", + mutator: "javascript", + coverageAnalysis: "off", + mutate: ["src/**/*.js"] }; ``` diff --git a/packages/karma-runner/README.md b/packages/karma-runner/README.md index e395dc1e0c..b68c65890f 100644 --- a/packages/karma-runner/README.md +++ b/packages/karma-runner/README.md @@ -26,23 +26,21 @@ uses *your very own karma* version. It can also work with `@angular/cli`, see [C ## Configuring -You can configure the `@stryker-mutator/karma-runner` using the `stryker.conf.js` config file. +You can configure the `@stryker-mutator/karma-runner` using the `stryker.conf.js` (or `stryker.conf.json`) config file. ```javascript // Stryker.conf.js -module.exports = function (config) { - config.set({ - // ... - testRunner: 'karma', - // ... - karma: { - projectType: 'custom', // or 'angular-cli' - configFile: 'path/to/karma.conf.js' // default `undefined` - config: { // default `undefined` - browsers: ['ChromeHeadless'] // override config settings - } +module.exports = { + // ... + testRunner: 'karma', + // ... + karma: { + projectType: 'custom', // or 'angular-cli' + configFile: 'path/to/karma.conf.js' // default `undefined` + config: { // default `undefined` + browsers: ['ChromeHeadless'] // override config settings } - }); + } } ``` diff --git a/packages/mocha-framework/README.md b/packages/mocha-framework/README.md index 89820eb205..a6d9ecaad9 100644 --- a/packages/mocha-framework/README.md +++ b/packages/mocha-framework/README.md @@ -29,16 +29,14 @@ As such, you should make sure you have the correct versions of its dependencies ## Configuring You can either configure the mocha test framework using the command line or by providing it in the `stryker.conf.js` file. -This README describes how to use the `stryker.conf.js` config file: +This README describes how to use the `stryker.conf.js` (or `stryker.conf.json`) config file: ```javascript -// Stryker.conf.js -module.exports = function (config) { - config.set({ - ... - testFramework: 'mocha', - coverageAnalysis: 'perTest' - ... - }); +// stryker.conf.js +module.exports = { + // ... + testFramework: 'mocha', + coverageAnalysis: 'perTest' + // ... } ``` diff --git a/packages/mocha-runner/README.md b/packages/mocha-runner/README.md index 1c5b2c6f8a..f33deff95b 100644 --- a/packages/mocha-runner/README.md +++ b/packages/mocha-runner/README.md @@ -25,28 +25,26 @@ As such, you should make sure you have the correct versions of its dependencies ## Configuring -You can configure the mocha test runner in the `stryker.conf.js` file. +You can configure the mocha test runner in the `stryker.conf.js` (or `stryker.conf.json`) file. ```javascript // stryker.conf.js -module.exports = function (config) { - config.set({ - // ... - testRunner: 'mocha', - // ... - mochaOptions: { - // Optional mocha options - spec: [ 'test/**/*.js' ], - config: 'path/to/mocha/config/.mocharc.json', - package: 'path/to/custom/package/package.json', - opts: 'path/to/custom/mocha.opts', - ui: 'bdd', - timeout: 3000, - require: [ /*'babel-register' */], - asyncOnly: false, - grep: /.*/ - } - }); +module.exports = { + // ... + testRunner: 'mocha', + // ... + mochaOptions: { + // Optional mocha options + spec: [ 'test/**/*.js' ], + config: 'path/to/mocha/config/.mocharc.json', + package: 'path/to/custom/package/package.json', + opts: 'path/to/custom/mocha.opts', + ui: 'bdd', + timeout: 3000, + require: [ /*'babel-register' */], + asyncOnly: false, + grep: /.*/ + } } ``` diff --git a/packages/typescript/README.md b/packages/typescript/README.md index e2af2cc2b9..a19db58838 100644 --- a/packages/typescript/README.md +++ b/packages/typescript/README.md @@ -20,7 +20,7 @@ Next, install this package: npm install --save-dev @stryker-mutator/typescript ``` -Now open up your stryker.conf.js file and add the following components: +Now open up your `stryker.conf.js` (or `stryker.conf.json`) file and add the following components: ```javascript coverageAnalysis: 'off', // Coverage analysis with a transpiler is not supported a.t.m. @@ -90,7 +90,7 @@ The `TypescriptMutator` is a plugin to mutate typescript code. It builds a Types See [test code](https://github.com/stryker-mutator/stryker/tree/master/packages/typescript/test/unit/mutator) to know which mutations are supported. -Configure the Typescript mutator in your stryker.conf.js file: +Configure the Typescript mutator in your `stryker.conf.js` (or `stryker.conf.json`) file: ```javascript // stryker.conf.js @@ -105,7 +105,7 @@ The `TypescriptTranspiler` is a plugin to transpile typescript source code befor Given your Typescript configuration (see **TypescriptConfigEditor**) it generates the javascript output. This is also used to transpile each mutant to javascript. Internally, it uses the same method as Typescript's watch mode (`tsc -w`), so it can transpile mutants fairly efficiently. -Configure the Typescript transpiler in your stryker.conf.js file: +Configure the Typescript transpiler in your `stryker.conf.js` (or `stryker.conf.json`) file: ```javascript // stryker.conf.js diff --git a/packages/vue-mutator/README.md b/packages/vue-mutator/README.md index 6894e49c65..7cf29c53e3 100644 --- a/packages/vue-mutator/README.md +++ b/packages/vue-mutator/README.md @@ -57,7 +57,7 @@ If you write JavaScript code please install this package: npm install --save-dev @stryker-mutator/javascript-mutator ``` -These plugins need no additional configuration to work with the `Vue Mutator`. Please leave the config setting in your stryker.conf.js file at `mutator: 'vue',`. +These plugins need no additional configuration to work with the `Vue Mutator`. Please leave the config setting in your `stryker.conf.js` (or `stryker.conf.json`) file at `mutator: 'vue',`. ## Peer dependencies diff --git a/packages/webpack-transpiler/README.md b/packages/webpack-transpiler/README.md index 20aa7a7b28..3a44cb8be4 100644 --- a/packages/webpack-transpiler/README.md +++ b/packages/webpack-transpiler/README.md @@ -18,7 +18,7 @@ Next, install this package: npm install --save-dev @stryker-mutator/webpack-transpiler ``` -Open up your `stryker.conf.js` file and add the following properties: +Open up your `stryker.conf.js` (or `stryker.conf.json`) file and add the following properties: ```javascript webpack: { @@ -32,7 +32,7 @@ transpilers: [ **Note:** if the webpack config is absent from your stryker configuration, the above values are used by default. -If you initialize stryker using `stryker init`, the webpack property will be added to your `stryker.conf.js` automatically. +If you initialize stryker using `stryker init`, the webpack property will be added to your `stryker.conf.js` (or `stryker.conf.json`) automatically. Now give it a go: From 81f58c442a0b6ad82b163da236922fb7fe92ca65 Mon Sep 17 00:00:00 2001 From: Simon de Lang Date: Wed, 11 Mar 2020 16:20:11 +0100 Subject: [PATCH 9/9] test: fix incorrect config file path --- e2e/test/command/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/test/command/package.json b/e2e/test/command/package.json index 959ab54ad4..a27063545e 100644 --- a/e2e/test/command/package.json +++ b/e2e/test/command/package.json @@ -6,7 +6,7 @@ "main": "index.js", "scripts": { "pretest": "rimraf \"reports\" \"stryker.log\"", - "test": "stryker run stryker.conf.js", + "test": "stryker run", "mocha": "mocha", "posttest": "mocha --require ts-node/register verify/*.ts" },