diff --git a/src/config.model.test.ts b/src/config.model.test.ts index 6c7a9cf..8891cbd 100644 --- a/src/config.model.test.ts +++ b/src/config.model.test.ts @@ -2,7 +2,7 @@ import { makeCompleteConfiguration } from "./config.model" describe("makeCompleteConfiguration", () => { const base = { - coveragePath: "./coverage/coverage-summary.json", + coveragePaths: ["./coverage/coverage-summary.json"], reportFileSet: "all", reportMode: "message", entrySortMethod: "alphabetically", @@ -20,6 +20,13 @@ describe("makeCompleteConfiguration", () => { expect(output).toEqual(base) }) + it("overrides coveragePaths with the value from coveragePath", () => { + const output = makeCompleteConfiguration({ + coveragePath: "some-other-path", + }) + expect(output).toEqual({ ...base, coveragePaths: ["some-other-path"] }) + }) + it("overrides a specific value from the default", () => { const output = makeCompleteConfiguration({ reportMode: "warn", diff --git a/src/config.model.ts b/src/config.model.ts index a8948d5..97f23dc 100644 --- a/src/config.model.ts +++ b/src/config.model.ts @@ -20,7 +20,8 @@ export interface Config { customFailureMessage?: string numberOfEntries: number entrySortMethod: SortMethod - coveragePath: string + coveragePath?: string + coveragePaths: string[] reportFileSet: ReportFileSet threshold: CoverageThreshold reportMode: ReportMode @@ -33,7 +34,7 @@ export interface Config { */ export function makeCompleteConfiguration(config?: Partial): Config { const defaults: Config = { - coveragePath: "./coverage/coverage-summary.json", + coveragePaths: [], reportFileSet: "all", reportMode: "message", entrySortMethod: "alphabetically", @@ -45,5 +46,10 @@ export function makeCompleteConfiguration(config?: Partial): Config { lines: 100, }, } - return config ? { ...defaults, ...config } : defaults + + const combined = config ? { ...defaults, ...config } : defaults + const coveragePath = combined.coveragePath ? combined.coveragePath : "./coverage/coverage-summary.json" + const coveragePaths = combined.coveragePaths.length === 0 ? [coveragePath] : combined.coveragePaths + delete combined.coveragePath + return { ...combined, coveragePaths } } diff --git a/src/index.test.ts b/src/index.test.ts index 4f9c9bf..eca538a 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -46,11 +46,12 @@ function setupGitService() { }) } -function setupCoverageFile(coverage?: string) { +function setupCoverageFile(coverages: string[] = []) { ;(FilesystemService as any).mockImplementation(() => { return { - exists: p => coverage !== undefined, + exists: p => coverages.length !== 0, read: p => { + const coverage = coverages.pop() return coverage !== undefined ? Buffer.from(coverage, "utf8") : undefined }, } @@ -70,14 +71,16 @@ describe("istanbulCoverage()", () => { }, } setupGitService() - setupCoverageFile(`{ + setupCoverageFile([ + `{ ${makeEntry("total", 50, 50, 50, 50)}, ${makeEntry(`${__dirname}/src/modified-file1.ts`, 66, 25, 25, 25)}, ${makeEntry(`${__dirname}/src/modified-file2.ts`, 99, 50, 75, 50)}, ${makeEntry(`${__dirname}/src/created-file1.ts`, 66, 100, 25, 50)}, ${makeEntry(`${__dirname}/src/created-file2.ts`, 99, 75, 50, 25)}, ${makeEntry(`${__dirname}/src/unmodified-field.ts`, 25, 25, 25, 25)} - }`) + }`, + ]) }) afterEach(() => { @@ -103,6 +106,36 @@ Total | (165/200) 83% | (175/200) 88% | (75/200) 38% | (75/200) 38% ) }) + it("can combine multiple coverage files", async () => { + setupCoverageFile([ + `{ + ${makeEntry("total", 50, 50, 50, 50)}, + ${makeEntry(`${__dirname}/src/modified-file1.ts`, 66, 25, 25, 25)}, + ${makeEntry(`${__dirname}/src/modified-file2.ts`, 99, 50, 75, 50)} + }`, + `{ + ${makeEntry("total", 50, 50, 50, 50)}, + ${makeEntry(`${__dirname}/src/created-file1.ts`, 66, 100, 25, 50)}, + ${makeEntry(`${__dirname}/src/created-file2.ts`, 99, 75, 50, 25)} + }`, + ]) + await istanbulCoverage({ + reportFileSet: "createdOrModified", + coveragePaths: ["coverage-path-1", "coverage-path-2"], + }) + expect(global.markdown).toHaveBeenCalledWith( + `## Coverage in Created or Modified Files +File | Line Coverage | Statement Coverage | Function Coverage | Branch Coverage +---- | ------------: | -----------------: | ----------------: | --------------: +[src/created\\-file1.ts](../blob/master/src/created\\-file1.ts) | (66/100) 66% | (100/100) 100% | (25/100) 25% | (50/100) 50% +[src/created\\-file2.ts](../blob/master/src/created\\-file2.ts) | (99/100) 99% | (75/100) 75% | (50/100) 50% | (25/100) 25% +[src/modified\\-file1.ts](../blob/master/src/modified\\-file1.ts) | (66/100) 66% | (25/100) 25% | (25/100) 25% | (25/100) 25% +[src/modified\\-file2.ts](../blob/master/src/modified\\-file2.ts) | (99/100) 99% | (50/100) 50% | (75/100) 75% | (50/100) 50% +Total | (330/400) 83% | (250/400) 63% | (175/400) 44% | (150/400) 38% +` + ) + }) + it('will only report on modified files when reportFileSet is set to "modified"', async () => { await istanbulCoverage({ reportFileSet: "modified", @@ -256,7 +289,7 @@ Total | (355/500) 71% | (275/500) 55% | (200/500) 40% | (175/500) 35% expect(global.message).not.toBeCalled() }) it("doesn't output anything when the coverage data is empty", async () => { - setupCoverageFile("{}") + setupCoverageFile(["{}"]) await istanbulCoverage({ reportMode: "fail", }) @@ -265,14 +298,14 @@ Total | (355/500) 71% | (275/500) 55% | (200/500) 40% | (175/500) 35% expect(global.message).not.toBeCalled() }) it("outputs a warning when it can't find the coverage file", async () => { - setupCoverageFile(undefined) + setupCoverageFile([]) await istanbulCoverage({ reportMode: "warn", }) expect(global.warn).toBeCalled() }) it("outputs a warning when coverage file is invalidly formatted", async () => { - setupCoverageFile("{") + setupCoverageFile(["{"]) await istanbulCoverage({ reportMode: "fail", }) diff --git a/src/index.ts b/src/index.ts index 86e6b10..62db75d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -138,21 +138,36 @@ File | Line Coverage | Statement Coverage | Function Coverage | Branch Coverage return [header, ...lines, ellided, total, ""].filter(part => part !== undefined).join("\n") } +function getCoveragePaths(coveragePaths: string[]): string[] { + return coveragePaths.map(singleCoveragePath => { + if (!process.mainModule) { + return singleCoveragePath + } + const appDir = `${process.mainModule.paths[0].split("node_modules")[0].slice(0, -1)}/` + return path.resolve(appDir, singleCoveragePath) + }) +} + +function getCombinedCoverageCollection(coveragePaths: string[]): CoverageCollection { + return coveragePaths + .map(coveragePath => { + const collection = parseCoverageCollection(coveragePath) + return collection ? collection : {} + }) + .reduce((previous, current) => ({ ...previous, ...current }), {}) +} + /** * Danger.js plugin for monitoring code coverage on changed files. */ export function istanbulCoverage(config?: Partial): Promise { const combinedConfig = makeCompleteConfiguration(config) - let coveragePath = combinedConfig.coveragePath - if (process.mainModule) { - const appDir = `${process.mainModule.paths[0].split("node_modules")[0].slice(0, -1)}/` + const coveragePaths = getCoveragePaths(combinedConfig.coveragePaths) - coveragePath = path.resolve(appDir, combinedConfig.coveragePath) - } let coverage: CoverageCollection try { - const parsedCoverage = parseCoverageCollection(coveragePath) + const parsedCoverage = getCombinedCoverageCollection(coveragePaths) if (!parsedCoverage) { return Promise.resolve() }