From 2c1bf095d21d383f15de1a07215b427dbbbadd52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Sch=C3=A4tzle?= Date: Fri, 23 Oct 2020 04:49:09 +0200 Subject: [PATCH 1/6] feat: add json-reporter --- packages/api/schema/stryker-core.json | 21 +++++++ packages/core/README.md | 8 ++- packages/core/src/reporters/index.ts | 2 + packages/core/src/reporters/json-reporter.ts | 62 ++++++++++++++++++++ 4 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 packages/core/src/reporters/json-reporter.ts diff --git a/packages/api/schema/stryker-core.json b/packages/api/schema/stryker-core.json index 6c7528a82f..cae07a049f 100644 --- a/packages/api/schema/stryker-core.json +++ b/packages/api/schema/stryker-core.json @@ -133,6 +133,23 @@ } } }, + "jsonReporterOptions": { + "title": "JsonReporterOptions", + "additionalProperties": false, + "type": "object", + "properties": { + "baseDir": { + "description": "The output folder for the json report.", + "type": "string", + "default": "reports/mutation" + }, + "spacing": { + "description": "The number of spaces used for indenion.", + "type": "number", + "default": 0 + } + } + }, "mutationScoreThresholds": { "title": "MutationScoreThresholds", "additionalProperties": false, @@ -349,6 +366,10 @@ "description": "The options for the html reporter", "$ref": "#/definitions/htmlReporterOptions" }, + "jsonReporter": { + "description": "The options for the json reporter", + "$ref": "#/definitions/jsonReporterOptions" + }, "disableTypeChecks": { "description": "Configure a pattern that matches the files of which type checking has to be disabled. This is needed because Stryker will create (typescript) type errors when inserting the mutants in your code. Stryker disables type checking by inserting `// @ts-nocheck` atop those files and removing other `// @ts-xxx` directives (so they won't interfere with `@ts-nocheck`). The default setting allows these directives to be stripped from all JavaScript and friend files in `lib`, `src` and `test` directories. You can specify a different glob expression or set it to `false` to completely disable this behavior.", "anyOf": [ diff --git a/packages/core/README.md b/packages/core/README.md index bbbf2a0bc8..b5bd89c54f 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -301,17 +301,19 @@ you can consult [npm](https://www.npmjs.com/search?q=stryker-plugin) or ### `reporters` [`string[]`] Default: `['clear-text', 'progress', 'html']` -Command line: `--reporters clear-text,progress,dots,dashboard,html` -Config file: `reporters: ['clear-text', 'progress', 'dots', 'dashboard', 'html']` +Command line: `--reporters clear-text,progress,dots,dashboard,html,json` +Config file: `reporters: ['clear-text', 'progress', 'dots', 'dashboard', 'html', 'json']` With `reporters`, you can set the reporters for stryker to use. -These reporters can be used out of the box: `html`, `progress`, `clear-text`, `dots`, `dashboard` and `event-recorder`. +These reporters can be used out of the box: `html`, `json`, `progress`, `clear-text`, `dots`, `dashboard` and `event-recorder`. By default, `clear-text`, `progress`, `html` are active if no reporters are configured. You can load additional plugins to get more reporters. See [stryker-mutator.io](https://stryker-mutator.io) for an up-to-date list of supported reporter plugins and a description on each reporter. The `html` reporter allows you to specify an output folder. This defaults to `reports/mutation/html`. The config for your config file is: `htmlReporter: { baseDir: 'mypath/reports/stryker' }` +The `json` reporter also allows specifying an output folder and additionally provides a parameter for the indention (called `spacing`) which is 0 spaces by default, meaning no indention at all. The config for your config file is: `jsonReporter: { baseDir: 'mypath/reports/stryker', spacing: 2 }` + The `clear-text` reporter supports three additional config options: * `allowColor` to use cyan and yellow in printing source file names and positions. This defaults to `true`, so specify as `clearTextReporter: { allowColor: false },` to disable if you must. * `logTests` to log the names of unit tests that were run to allow mutants. By default, only the first three are logged. The config for your config file is: `clearTextReporter: { logTests: true },` diff --git a/packages/core/src/reporters/index.ts b/packages/core/src/reporters/index.ts index 4ad89dceb8..cc878dd912 100644 --- a/packages/core/src/reporters/index.ts +++ b/packages/core/src/reporters/index.ts @@ -7,6 +7,7 @@ import EventRecorderReporter from './event-recorder-reporter'; import ProgressAppendOnlyReporter from './progress-append-only-reporter'; import ProgressReporter from './progress-reporter'; import HtmlReporter from './html/html-reporter'; +import JsonReporter from './json-reporter'; export const strykerPlugins = [ declareClassPlugin(PluginKind.Reporter, 'clear-text', ClearTextReporter), @@ -15,5 +16,6 @@ export const strykerPlugins = [ declareClassPlugin(PluginKind.Reporter, 'dots', DotsReporter), declareClassPlugin(PluginKind.Reporter, 'event-recorder', EventRecorderReporter), declareClassPlugin(PluginKind.Reporter, 'html', HtmlReporter), + declareClassPlugin(PluginKind.Reporter, 'json', JsonReporter), declareFactoryPlugin(PluginKind.Reporter, 'dashboard', dashboardReporterFactory), ]; diff --git a/packages/core/src/reporters/json-reporter.ts b/packages/core/src/reporters/json-reporter.ts new file mode 100644 index 0000000000..247851cce4 --- /dev/null +++ b/packages/core/src/reporters/json-reporter.ts @@ -0,0 +1,62 @@ +import * as path from 'path'; + +import { StrykerOptions } from '@stryker-mutator/api/core'; +import { Logger } from '@stryker-mutator/api/logging'; +import { commonTokens, tokens } from '@stryker-mutator/api/plugin'; +import { mutationTestReportSchema, Reporter } from '@stryker-mutator/api/report'; + +import fileUrl = require('file-url'); + +import * as HtmlReporterUtil from './html/html-reporter-util'; + +const DEFAULT_BASE_FOLDER = path.normalize('reports/mutation'); +const DEFAULT_INDENTION = 0; +export const RESOURCES_DIR_NAME = 'strykerResources'; + +export default class JsonReporter implements Reporter { + private _baseDir!: string; + private mainPromise: Promise | undefined; + + constructor(private readonly options: StrykerOptions, private readonly log: Logger) {} + + public static readonly inject = tokens(commonTokens.options, commonTokens.logger); + + public onMutationTestReportReady(report: mutationTestReportSchema.MutationTestResult) { + this.mainPromise = this.generateReport(report); + } + + public wrapUp() { + return this.mainPromise; + } + + private async generateReport(report: mutationTestReportSchema.MutationTestResult) { + const jsonReportFile = path.resolve(this.baseDir, 'mutation.json'); + await this.cleanBaseFolder(); + let indent = DEFAULT_INDENTION + if (this.options.jsonReporter && this.options.jsonReporter.spacing) { + indent = this.options.jsonReporter.spacing + } + await HtmlReporterUtil.writeFile(jsonReportFile, JSON.stringify(report, null, indent)); + this.log.info(`Your report can be found at: ${fileUrl(jsonReportFile)}`); + } + + private get baseDir(): string { + if (!this._baseDir) { + if (this.options.jsonReporter && this.options.jsonReporter.baseDir) { + this._baseDir = this.options.jsonReporter.baseDir; + this.log.debug(`Using configured output folder ${this._baseDir}`); + } else { + this.log.debug( + `No base folder configuration found (using configuration: jsonReporter: { baseDir: 'output/folder' }), using default ${DEFAULT_BASE_FOLDER}` + ); + this._baseDir = DEFAULT_BASE_FOLDER; + } + } + return this._baseDir; + } + + private async cleanBaseFolder(): Promise { + await HtmlReporterUtil.deleteDir(this.baseDir); + await HtmlReporterUtil.mkdir(this.baseDir); + } +} From 289043b0b5584060fbefb54e0c4433019240ae23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Sch=C3=A4tzle?= Date: Fri, 23 Oct 2020 23:08:05 +0200 Subject: [PATCH 2/6] fix: lint issues --- packages/core/src/index.ts | 1 + packages/core/src/reporters/json-reporter.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 77df1ef56a..c1a0cfc77c 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,4 +1,5 @@ import Stryker from './stryker'; import StrykerCli from './stryker-cli'; + export { Stryker, StrykerCli }; export default Stryker; diff --git a/packages/core/src/reporters/json-reporter.ts b/packages/core/src/reporters/json-reporter.ts index 247851cce4..5ae6c4fa46 100644 --- a/packages/core/src/reporters/json-reporter.ts +++ b/packages/core/src/reporters/json-reporter.ts @@ -32,9 +32,9 @@ export default class JsonReporter implements Reporter { private async generateReport(report: mutationTestReportSchema.MutationTestResult) { const jsonReportFile = path.resolve(this.baseDir, 'mutation.json'); await this.cleanBaseFolder(); - let indent = DEFAULT_INDENTION + let indent = DEFAULT_INDENTION; if (this.options.jsonReporter && this.options.jsonReporter.spacing) { - indent = this.options.jsonReporter.spacing + indent = this.options.jsonReporter.spacing; } await HtmlReporterUtil.writeFile(jsonReportFile, JSON.stringify(report, null, indent)); this.log.info(`Your report can be found at: ${fileUrl(jsonReportFile)}`); From 1d0c9bf89ba65d8ef6e12b13cd069c5122f27836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Sch=C3=A4tzle?= Date: Wed, 4 Nov 2020 20:13:54 +0100 Subject: [PATCH 3/6] test: add unit tests, add filename option, remove indention option --- packages/api/schema/stryker-core.json | 11 +-- packages/core/README.md | 2 +- .../core/src/reporters/html/html-reporter.ts | 14 ++-- packages/core/src/reporters/json-reporter.ts | 42 +++-------- ...html-reporter-util.ts => reporter-util.ts} | 4 +- .../unit/reporters/html/html-reporter.spec.ts | 10 +-- .../test/unit/reporters/json-reporter.spec.ts | 71 +++++++++++++++++++ 7 files changed, 103 insertions(+), 51 deletions(-) rename packages/core/src/reporters/{html/html-reporter-util.ts => reporter-util.ts} (89%) create mode 100644 packages/core/test/unit/reporters/json-reporter.spec.ts diff --git a/packages/api/schema/stryker-core.json b/packages/api/schema/stryker-core.json index cae07a049f..ee4e1d55f7 100644 --- a/packages/api/schema/stryker-core.json +++ b/packages/api/schema/stryker-core.json @@ -143,10 +143,10 @@ "type": "string", "default": "reports/mutation" }, - "spacing": { - "description": "The number of spaces used for indenion.", - "type": "number", - "default": 0 + "filename": { + "description": "The filename for the json report.", + "type": "string", + "default": "mutation.json" } } }, @@ -368,7 +368,8 @@ }, "jsonReporter": { "description": "The options for the json reporter", - "$ref": "#/definitions/jsonReporterOptions" + "$ref": "#/definitions/jsonReporterOptions", + "default": {} }, "disableTypeChecks": { "description": "Configure a pattern that matches the files of which type checking has to be disabled. This is needed because Stryker will create (typescript) type errors when inserting the mutants in your code. Stryker disables type checking by inserting `// @ts-nocheck` atop those files and removing other `// @ts-xxx` directives (so they won't interfere with `@ts-nocheck`). The default setting allows these directives to be stripped from all JavaScript and friend files in `lib`, `src` and `test` directories. You can specify a different glob expression or set it to `false` to completely disable this behavior.", diff --git a/packages/core/README.md b/packages/core/README.md index b5bd89c54f..e953a6c645 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -312,7 +312,7 @@ for an up-to-date list of supported reporter plugins and a description on each r The `html` reporter allows you to specify an output folder. This defaults to `reports/mutation/html`. The config for your config file is: `htmlReporter: { baseDir: 'mypath/reports/stryker' }` -The `json` reporter also allows specifying an output folder and additionally provides a parameter for the indention (called `spacing`) which is 0 spaces by default, meaning no indention at all. The config for your config file is: `jsonReporter: { baseDir: 'mypath/reports/stryker', spacing: 2 }` +Analogously, the `json` reporter allows specifying an output folder but also the filename. The config for your config file is: `jsonReporter: { baseDir: 'mypath/reports/stryker', filename: 'mutation.json'}` The `clear-text` reporter supports three additional config options: * `allowColor` to use cyan and yellow in printing source file names and positions. This defaults to `true`, so specify as `clearTextReporter: { allowColor: false },` to disable if you must. diff --git a/packages/core/src/reporters/html/html-reporter.ts b/packages/core/src/reporters/html/html-reporter.ts index 9de853bee6..f34f3bcb32 100644 --- a/packages/core/src/reporters/html/html-reporter.ts +++ b/packages/core/src/reporters/html/html-reporter.ts @@ -7,8 +7,8 @@ import { mutationTestReportSchema, Reporter } from '@stryker-mutator/api/report' import fileUrl = require('file-url'); +import * as ReporterUtil from '../reporter-util'; import { bindMutationTestReport } from './templates/bind-mutation-test-report'; -import * as HtmlReporterUtil from './html-reporter-util'; const DEFAULT_BASE_FOLDER = path.normalize('reports/mutation/html'); export const RESOURCES_DIR_NAME = 'strykerResources'; @@ -33,13 +33,13 @@ export default class HtmlReporter implements Reporter { const indexFileName = path.resolve(this.baseDir, 'index.html'); await this.cleanBaseFolder(); await Promise.all([ - HtmlReporterUtil.copyFile( + ReporterUtil.copyFile( require.resolve('mutation-testing-elements/dist/mutation-test-elements.js'), path.resolve(this.baseDir, 'mutation-test-elements.js') ), - HtmlReporterUtil.copyFile(path.resolve(__dirname, 'templates', 'stryker-80x80.png'), path.resolve(this.baseDir, 'stryker-80x80.png')), - HtmlReporterUtil.copyFile(path.resolve(__dirname, 'templates', 'index.html'), path.resolve(this.baseDir, 'index.html')), - HtmlReporterUtil.writeFile(path.resolve(this.baseDir, 'bind-mutation-test-report.js'), bindMutationTestReport(report)), + ReporterUtil.copyFile(path.resolve(__dirname, 'templates', 'stryker-80x80.png'), path.resolve(this.baseDir, 'stryker-80x80.png')), + ReporterUtil.copyFile(path.resolve(__dirname, 'templates', 'index.html'), path.resolve(this.baseDir, 'index.html')), + ReporterUtil.writeFile(path.resolve(this.baseDir, 'bind-mutation-test-report.js'), bindMutationTestReport(report)), ]); this.log.info(`Your report can be found at: ${fileUrl(indexFileName)}`); } @@ -60,7 +60,7 @@ export default class HtmlReporter implements Reporter { } private async cleanBaseFolder(): Promise { - await HtmlReporterUtil.deleteDir(this.baseDir); - await HtmlReporterUtil.mkdir(this.baseDir); + await ReporterUtil.deleteDir(this.baseDir); + await ReporterUtil.mkdir(this.baseDir); } } diff --git a/packages/core/src/reporters/json-reporter.ts b/packages/core/src/reporters/json-reporter.ts index 5ae6c4fa46..f0432b6704 100644 --- a/packages/core/src/reporters/json-reporter.ts +++ b/packages/core/src/reporters/json-reporter.ts @@ -7,17 +7,18 @@ import { mutationTestReportSchema, Reporter } from '@stryker-mutator/api/report' import fileUrl = require('file-url'); -import * as HtmlReporterUtil from './html/html-reporter-util'; +import * as ReporterUtil from './reporter-util'; -const DEFAULT_BASE_FOLDER = path.normalize('reports/mutation'); -const DEFAULT_INDENTION = 0; +const INDENTION_LEVEL = 0; export const RESOURCES_DIR_NAME = 'strykerResources'; export default class JsonReporter implements Reporter { - private _baseDir!: string; + private readonly _filePath: string; private mainPromise: Promise | undefined; - constructor(private readonly options: StrykerOptions, private readonly log: Logger) {} + constructor(private readonly options: StrykerOptions, private readonly log: Logger) { + this._filePath = path.resolve(this.options.jsonReporter.baseDir, this.options.jsonReporter.filename); + } public static readonly inject = tokens(commonTokens.options, commonTokens.logger); @@ -30,33 +31,12 @@ export default class JsonReporter implements Reporter { } private async generateReport(report: mutationTestReportSchema.MutationTestResult) { - const jsonReportFile = path.resolve(this.baseDir, 'mutation.json'); - await this.cleanBaseFolder(); - let indent = DEFAULT_INDENTION; - if (this.options.jsonReporter && this.options.jsonReporter.spacing) { - indent = this.options.jsonReporter.spacing; - } - await HtmlReporterUtil.writeFile(jsonReportFile, JSON.stringify(report, null, indent)); - this.log.info(`Your report can be found at: ${fileUrl(jsonReportFile)}`); - } - - private get baseDir(): string { - if (!this._baseDir) { - if (this.options.jsonReporter && this.options.jsonReporter.baseDir) { - this._baseDir = this.options.jsonReporter.baseDir; - this.log.debug(`Using configured output folder ${this._baseDir}`); - } else { - this.log.debug( - `No base folder configuration found (using configuration: jsonReporter: { baseDir: 'output/folder' }), using default ${DEFAULT_BASE_FOLDER}` - ); - this._baseDir = DEFAULT_BASE_FOLDER; - } - } - return this._baseDir; + await ReporterUtil.writeFile(this.filePath, JSON.stringify(report, null, INDENTION_LEVEL)); + this.log.info(`Your report can be found at: ${fileUrl(this.filePath)}`); } - private async cleanBaseFolder(): Promise { - await HtmlReporterUtil.deleteDir(this.baseDir); - await HtmlReporterUtil.mkdir(this.baseDir); + private get filePath(): string { + this.log.debug(`Using path ${this._filePath}`); + return this._filePath; } } diff --git a/packages/core/src/reporters/html/html-reporter-util.ts b/packages/core/src/reporters/reporter-util.ts similarity index 89% rename from packages/core/src/reporters/html/html-reporter-util.ts rename to packages/core/src/reporters/reporter-util.ts index 4f2f69fd68..2e6746fcc2 100644 --- a/packages/core/src/reporters/html/html-reporter-util.ts +++ b/packages/core/src/reporters/reporter-util.ts @@ -1,4 +1,4 @@ -import * as path from 'path'; +import * as ReporterUtil from 'path'; import { promisify } from 'util'; import { createReadStream, createWriteStream, promises as fs } from 'fs'; @@ -20,6 +20,6 @@ export const deleteDir = promisify(rimraf); export const mkdir = mkdirp; export async function writeFile(fileName: string, content: string) { - await mkdirp(path.dirname(fileName)); + await mkdirp(ReporterUtil.dirname(fileName)); await fs.writeFile(fileName, content, 'utf8'); } diff --git a/packages/core/test/unit/reporters/html/html-reporter.spec.ts b/packages/core/test/unit/reporters/html/html-reporter.spec.ts index 5bc6a4440c..8a81878280 100644 --- a/packages/core/test/unit/reporters/html/html-reporter.spec.ts +++ b/packages/core/test/unit/reporters/html/html-reporter.spec.ts @@ -6,7 +6,7 @@ import { expect } from 'chai'; import * as sinon from 'sinon'; import HtmlReporter from '../../../../src/reporters/html/html-reporter'; -import * as HtmlReporterUtil from '../../../../src/reporters/html/html-reporter-util'; +import * as ReporterUtil from '../../../../src/reporters/reporter-util'; import { bindMutationTestReport } from '../../../../src/reporters/html/templates/bind-mutation-test-report'; describe(HtmlReporter.name, () => { @@ -17,10 +17,10 @@ describe(HtmlReporter.name, () => { let sut: HtmlReporter; beforeEach(() => { - copyFileStub = sinon.stub(HtmlReporterUtil, 'copyFile'); - writeFileStub = sinon.stub(HtmlReporterUtil, 'writeFile'); - deleteDirStub = sinon.stub(HtmlReporterUtil, 'deleteDir'); - mkdirStub = sinon.stub(HtmlReporterUtil, 'mkdir'); + copyFileStub = sinon.stub(ReporterUtil, 'copyFile'); + writeFileStub = sinon.stub(ReporterUtil, 'writeFile'); + deleteDirStub = sinon.stub(ReporterUtil, 'deleteDir'); + mkdirStub = sinon.stub(ReporterUtil, 'mkdir'); sut = testInjector.injector.injectClass(HtmlReporter); }); diff --git a/packages/core/test/unit/reporters/json-reporter.spec.ts b/packages/core/test/unit/reporters/json-reporter.spec.ts new file mode 100644 index 0000000000..a8a1e6a1e5 --- /dev/null +++ b/packages/core/test/unit/reporters/json-reporter.spec.ts @@ -0,0 +1,71 @@ +import * as path from 'path'; + +import { mutationTestReportSchema } from '@stryker-mutator/api/report'; +import { testInjector } from '@stryker-mutator/test-helpers'; +import { expect } from 'chai'; +import * as sinon from 'sinon'; + +import JsonReporter from '../../../src/reporters/json-reporter'; +import * as JsonReporterUtil from '../../../src/reporters/reporter-util'; + +describe(JsonReporter.name, () => { + let writeFileStub: sinon.SinonStub; + let mkdirStub: sinon.SinonStub; + let sut: JsonReporter; + + beforeEach(() => { + writeFileStub = sinon.stub(JsonReporterUtil, 'writeFile'); + mkdirStub = sinon.stub(JsonReporterUtil, 'mkdir'); + sut = testInjector.injector.injectClass(JsonReporter); + }); + + describe('onMutationTestReportReady', () => { + it('should use configured file path', async () => { + testInjector.options.jsonReporter = { + baseDir: 'foo/bar', + filename: 'myReport.json', + }; + actReportReady(); + await sut.wrapUp(); + expect(testInjector.logger.debug).calledWith('Using path foo/bar/myReport.json'); + }); + + it('should use default base directory when no override is configured', async () => { + actReportReady(); + await sut.wrapUp(); + expect(testInjector.logger.debug).calledWith('Using output folder reports/mutation/mutation.json'); + }); + + it('should write the mutation report to disk', async () => { + const report: mutationTestReportSchema.MutationTestResult = { + files: {}, + schemaVersion: '1.0', + thresholds: { + high: 80, + low: 60, + }, + }; + sut.onMutationTestReportReady(report); + await sut.wrapUp(); + expect(writeFileStub).calledWith(path.resolve('reports', 'mutation', 'mutation.json'), JSON.stringify(report)); + }); + }); + + describe('wrapUp', () => { + it('should resolve when everything is OK', () => { + actReportReady(); + return expect(sut.wrapUp()).eventually.undefined; + }); + + it('should reject when "writeFile" rejects', () => { + const expectedError = new Error('writeFile'); + writeFileStub.rejects(expectedError); + actReportReady(); + return expect(sut.wrapUp()).rejectedWith(expectedError); + }); + }); + + function actReportReady() { + sut.onMutationTestReportReady({ files: {}, schemaVersion: '', thresholds: { high: 0, low: 0 } }); + } +}); From 829d107928f011166c8eb316ce6e3b6bc78868fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Sch=C3=A4tzle?= Date: Thu, 5 Nov 2020 01:09:16 +0100 Subject: [PATCH 4/6] fix: platform dependant path delimiters --- .../core/src/reporters/html/html-reporter.ts | 1 + packages/core/src/reporters/json-reporter.ts | 16 +++++----------- .../test/unit/reporters/json-reporter.spec.ts | 8 ++++---- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/packages/core/src/reporters/html/html-reporter.ts b/packages/core/src/reporters/html/html-reporter.ts index f34f3bcb32..302435e83c 100644 --- a/packages/core/src/reporters/html/html-reporter.ts +++ b/packages/core/src/reporters/html/html-reporter.ts @@ -8,6 +8,7 @@ import { mutationTestReportSchema, Reporter } from '@stryker-mutator/api/report' import fileUrl = require('file-url'); import * as ReporterUtil from '../reporter-util'; + import { bindMutationTestReport } from './templates/bind-mutation-test-report'; const DEFAULT_BASE_FOLDER = path.normalize('reports/mutation/html'); diff --git a/packages/core/src/reporters/json-reporter.ts b/packages/core/src/reporters/json-reporter.ts index f0432b6704..fd5442d078 100644 --- a/packages/core/src/reporters/json-reporter.ts +++ b/packages/core/src/reporters/json-reporter.ts @@ -13,12 +13,9 @@ const INDENTION_LEVEL = 0; export const RESOURCES_DIR_NAME = 'strykerResources'; export default class JsonReporter implements Reporter { - private readonly _filePath: string; private mainPromise: Promise | undefined; - constructor(private readonly options: StrykerOptions, private readonly log: Logger) { - this._filePath = path.resolve(this.options.jsonReporter.baseDir, this.options.jsonReporter.filename); - } + constructor(private readonly options: StrykerOptions, private readonly log: Logger) {} public static readonly inject = tokens(commonTokens.options, commonTokens.logger); @@ -31,12 +28,9 @@ export default class JsonReporter implements Reporter { } private async generateReport(report: mutationTestReportSchema.MutationTestResult) { - await ReporterUtil.writeFile(this.filePath, JSON.stringify(report, null, INDENTION_LEVEL)); - this.log.info(`Your report can be found at: ${fileUrl(this.filePath)}`); - } - - private get filePath(): string { - this.log.debug(`Using path ${this._filePath}`); - return this._filePath; + const filePath = path.join(this.options.jsonReporter.baseDir, this.options.jsonReporter.filename); + this.log.debug(`Using relative path ${filePath}`); + await ReporterUtil.writeFile(path.resolve(filePath), JSON.stringify(report, null, INDENTION_LEVEL)); + this.log.info(`Your report can be found at: ${fileUrl(filePath)}`); } } diff --git a/packages/core/test/unit/reporters/json-reporter.spec.ts b/packages/core/test/unit/reporters/json-reporter.spec.ts index a8a1e6a1e5..59d0912738 100644 --- a/packages/core/test/unit/reporters/json-reporter.spec.ts +++ b/packages/core/test/unit/reporters/json-reporter.spec.ts @@ -10,12 +10,10 @@ import * as JsonReporterUtil from '../../../src/reporters/reporter-util'; describe(JsonReporter.name, () => { let writeFileStub: sinon.SinonStub; - let mkdirStub: sinon.SinonStub; let sut: JsonReporter; beforeEach(() => { writeFileStub = sinon.stub(JsonReporterUtil, 'writeFile'); - mkdirStub = sinon.stub(JsonReporterUtil, 'mkdir'); sut = testInjector.injector.injectClass(JsonReporter); }); @@ -25,15 +23,17 @@ describe(JsonReporter.name, () => { baseDir: 'foo/bar', filename: 'myReport.json', }; + const expectedPath = path.normalize('foo/bar/myReport.json'); actReportReady(); await sut.wrapUp(); - expect(testInjector.logger.debug).calledWith('Using path foo/bar/myReport.json'); + expect(testInjector.logger.debug).calledWith(`Using relative path ${expectedPath}`); }); it('should use default base directory when no override is configured', async () => { + const expectedPath = path.normalize('reports/mutation/mutation.json'); actReportReady(); await sut.wrapUp(); - expect(testInjector.logger.debug).calledWith('Using output folder reports/mutation/mutation.json'); + expect(testInjector.logger.debug).calledWith(`Using relative path ${expectedPath}`); }); it('should write the mutation report to disk', async () => { From 53153b649c3b8e197443e9b4365400e5dacb2698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Sch=C3=A4tzle?= Date: Thu, 5 Nov 2020 14:22:48 +0100 Subject: [PATCH 5/6] fix: only use one option, called fileName --- packages/api/schema/stryker-core.json | 11 +++-------- packages/core/README.md | 2 +- packages/core/src/reporters/json-reporter.ts | 2 +- .../core/test/unit/reporters/json-reporter.spec.ts | 6 +++--- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/api/schema/stryker-core.json b/packages/api/schema/stryker-core.json index ee4e1d55f7..4c94aa2c6a 100644 --- a/packages/api/schema/stryker-core.json +++ b/packages/api/schema/stryker-core.json @@ -138,15 +138,10 @@ "additionalProperties": false, "type": "object", "properties": { - "baseDir": { - "description": "The output folder for the json report.", - "type": "string", - "default": "reports/mutation" - }, - "filename": { - "description": "The filename for the json report.", + "fileName": { + "description": "The relative filename for the json report.", "type": "string", - "default": "mutation.json" + "default": "reports/mutation/mutation.json" } } }, diff --git a/packages/core/README.md b/packages/core/README.md index e953a6c645..ff8a5033b0 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -312,7 +312,7 @@ for an up-to-date list of supported reporter plugins and a description on each r The `html` reporter allows you to specify an output folder. This defaults to `reports/mutation/html`. The config for your config file is: `htmlReporter: { baseDir: 'mypath/reports/stryker' }` -Analogously, the `json` reporter allows specifying an output folder but also the filename. The config for your config file is: `jsonReporter: { baseDir: 'mypath/reports/stryker', filename: 'mutation.json'}` +The `json` reporter allows specifying an output filename (may also contain a path). The config for your config file is: `jsonReporter: { fileName: 'mypath/reports/mutation.json' }` The `clear-text` reporter supports three additional config options: * `allowColor` to use cyan and yellow in printing source file names and positions. This defaults to `true`, so specify as `clearTextReporter: { allowColor: false },` to disable if you must. diff --git a/packages/core/src/reporters/json-reporter.ts b/packages/core/src/reporters/json-reporter.ts index fd5442d078..e078c114f2 100644 --- a/packages/core/src/reporters/json-reporter.ts +++ b/packages/core/src/reporters/json-reporter.ts @@ -28,7 +28,7 @@ export default class JsonReporter implements Reporter { } private async generateReport(report: mutationTestReportSchema.MutationTestResult) { - const filePath = path.join(this.options.jsonReporter.baseDir, this.options.jsonReporter.filename); + const filePath = path.normalize(this.options.jsonReporter.fileName); this.log.debug(`Using relative path ${filePath}`); await ReporterUtil.writeFile(path.resolve(filePath), JSON.stringify(report, null, INDENTION_LEVEL)); this.log.info(`Your report can be found at: ${fileUrl(filePath)}`); diff --git a/packages/core/test/unit/reporters/json-reporter.spec.ts b/packages/core/test/unit/reporters/json-reporter.spec.ts index 59d0912738..005f2aebe8 100644 --- a/packages/core/test/unit/reporters/json-reporter.spec.ts +++ b/packages/core/test/unit/reporters/json-reporter.spec.ts @@ -19,11 +19,11 @@ describe(JsonReporter.name, () => { describe('onMutationTestReportReady', () => { it('should use configured file path', async () => { + const fileName = 'foo/bar/myReport.json'; + const expectedPath = path.normalize(fileName); testInjector.options.jsonReporter = { - baseDir: 'foo/bar', - filename: 'myReport.json', + fileName, }; - const expectedPath = path.normalize('foo/bar/myReport.json'); actReportReady(); await sut.wrapUp(); expect(testInjector.logger.debug).calledWith(`Using relative path ${expectedPath}`); From 90b6f4d2dcc5ab26f130540c8b6497159971bc08 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Thu, 5 Nov 2020 20:51:38 +0100 Subject: [PATCH 6/6] docs(readme): update filename -> file name --- packages/core/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index ff8a5033b0..c63f8a97db 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -312,7 +312,7 @@ for an up-to-date list of supported reporter plugins and a description on each r The `html` reporter allows you to specify an output folder. This defaults to `reports/mutation/html`. The config for your config file is: `htmlReporter: { baseDir: 'mypath/reports/stryker' }` -The `json` reporter allows specifying an output filename (may also contain a path). The config for your config file is: `jsonReporter: { fileName: 'mypath/reports/mutation.json' }` +The `json` reporter allows specifying an output file name (may also contain a path). The config for your config file is: `jsonReporter: { fileName: 'mypath/reports/mutation.json' }` The `clear-text` reporter supports three additional config options: * `allowColor` to use cyan and yellow in printing source file names and positions. This defaults to `true`, so specify as `clearTextReporter: { allowColor: false },` to disable if you must. @@ -472,4 +472,4 @@ async function main() { } ``` -Stryker is written in TypeScript, so it is recommended to use Stryker as well to get the best developer experience. \ No newline at end of file +Stryker is written in TypeScript, so it is recommended to use Stryker as well to get the best developer experience.