Skip to content

Commit

Permalink
feat(coverage): custom reporter support
Browse files Browse the repository at this point in the history
  • Loading branch information
AriPerkkio committed Dec 30, 2023
1 parent 039814b commit a15b7f1
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 20 deletions.
3 changes: 2 additions & 1 deletion packages/coverage-istanbul/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co
this.ctx.logger.log(c.blue(' % ') + c.dim('Coverage report from ') + c.yellow(this.name))

for (const reporter of this.options.reporter) {
reports.create(reporter[0], {
// Type assertion required for custom reporters
reports.create(reporter[0] as Parameters<typeof reports.create>[0], {
skipFull: this.options.skipFull,
projectRoot: this.ctx.config.root,
...reporter[1],
Expand Down
3 changes: 2 additions & 1 deletion packages/coverage-v8/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
this.ctx.logger.log(c.blue(' % ') + c.dim('Coverage report from ') + c.yellow(this.name))

for (const reporter of this.options.reporter) {
reports.create(reporter[0], {
// Type assertion required for custom reporters
reports.create(reporter[0] as Parameters<typeof reports.create>[0], {
skipFull: this.options.skipFull,
projectRoot: this.ctx.config.root,
...reporter[1],
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function resolveCoverageFolder(ctx: Vitest) {
)

const subdir = (Array.isArray(htmlReporter) && htmlReporter.length > 1 && 'subdir' in htmlReporter[1])
? htmlReporter[1].subdir
? htmlReporter[1].subdir as string | undefined
: undefined

if (!subdir)
Expand Down
6 changes: 3 additions & 3 deletions packages/vitest/src/types/coverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ export interface CoverageProviderModule {
stopCoverage?(): unknown | Promise<unknown>
}

export type CoverageReporter = keyof ReportOptions
export type CoverageReporter = keyof ReportOptions | (string & {})

type CoverageReporterWithOptions<ReporterName extends CoverageReporter = CoverageReporter> =
ReporterName extends CoverageReporter
ReporterName extends keyof ReportOptions
? ReportOptions[ReporterName] extends never
? [ReporterName, {}] // E.g. the "none" reporter
: [ReporterName, Partial<ReportOptions[ReporterName]>]
: never
: [ReporterName, Record<string, unknown>]

type Provider = 'v8' | 'istanbul' | 'custom' | undefined

Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions test/coverage-test/coverage-report-tests/generic.report.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ test('lcov report', async () => {
expect(lcovReportFiles).toContain('index.html')
})

test('custom report', async () => {
const coveragePath = resolve('./coverage')
const files = fs.readdirSync(coveragePath)

expect(files).toContain('custom-reporter-output.md')

const content = fs.readFileSync(resolve(coveragePath, 'custom-reporter-output.md'), 'utf-8')
expect(content).toMatchInlineSnapshot(`
"Start of custom coverage report
End of custom coverage report
"
`)
})

test('all includes untested files', () => {
const coveragePath = resolve('./coverage/src')
const files = fs.readdirSync(coveragePath)
Expand Down
25 changes: 25 additions & 0 deletions test/coverage-test/custom-reporter.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Istanbul uses `require`: https://github.com/istanbuljs/istanbuljs/blob/5584b50305a6a17d3573aea25c84e254d4a08b65/packages/istanbul-reports/index.js#L19 */

'use strict'
const { ReportBase } = require('istanbul-lib-report')

module.exports = class CustomReporter extends ReportBase {
constructor(opts) {
super()

if (!opts.file)
throw new Error('File is requried as custom reporter parameter')

this.file = opts.file
}

onStart(root, context) {
this.contentWriter = context.writer.writeFile(this.file)
this.contentWriter.println('Start of custom coverage report')
}

onEnd() {
this.contentWriter.println('End of custom coverage report')
this.contentWriter.close()
}
}
2 changes: 2 additions & 0 deletions test/coverage-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
"devDependencies": {
"@ampproject/remapping": "^2.2.1",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-lib-report": "^3.0.3",
"@vitejs/plugin-vue": "latest",
"@vitest/browser": "workspace:*",
"@vitest/coverage-istanbul": "workspace:*",
"@vitest/coverage-v8": "workspace:*",
"@vue/test-utils": "latest",
"happy-dom": "latest",
"istanbul-lib-coverage": "^3.2.0",
"istanbul-lib-report": "^3.0.1",
"magicast": "^0.3.2",
"vite": "latest",
"vitest": "workspace:*",
Expand Down
22 changes: 8 additions & 14 deletions test/coverage-test/test/configuration-options.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,7 @@ test('reporters, single', () => {
assertType<Coverage>({ reporter: 'text-lcov' })
assertType<Coverage>({ reporter: 'text-summary' })
assertType<Coverage>({ reporter: 'text' })

// @ts-expect-error -- String reporters must be known built-in's
assertType<Coverage>({ reporter: 'unknown-reporter' })
assertType<Coverage>({ reporter: 'custom-reporter' })
})

test('reporters, multiple', () => {
Expand All @@ -173,11 +171,8 @@ test('reporters, multiple', () => {
],
})

// @ts-expect-error -- List of string reporters must be known built-in's
assertType<Coverage>({ reporter: ['unknown-reporter'] })

// @ts-expect-error -- ... and all reporters must be known
assertType<Coverage>({ reporter: ['html', 'json', 'unknown-reporter'] })
assertType<Coverage>({ reporter: ['custom-reporter'] })
assertType<Coverage>({ reporter: ['html', 'json', 'custom-reporter'] })
})

test('reporters, with options', () => {
Expand All @@ -196,6 +191,7 @@ test('reporters, with options', () => {
['text-lcov', { projectRoot: 'string' }],
['text-summary', { file: 'string' }],
['text', { skipEmpty: true, skipFull: true, maxCols: 1 }],
['custom-reporter', { 'someOption': true, 'some-other-custom-option': { width: 123 } }],
],
})

Expand All @@ -209,12 +205,6 @@ test('reporters, with options', () => {

assertType<Coverage>({
reporter: [
// @ts-expect-error -- teamcity report option on html reporter
['html', { blockName: 'string' }],

// @ts-expect-error -- html-spa report option on json reporter
['json', { metricsToShow: ['branches'] }],

// @ts-expect-error -- second value should be object even though TS intellisense prompts types of reporters
['lcov', 'html-spa'],
],
Expand All @@ -225,9 +215,13 @@ test('reporters, mixed variations', () => {
assertType<Coverage>({
reporter: [
'clover',
'custom-reporter-1',
['cobertura'],
['custom-reporter-2'],
['html-spa', {}],
['custom-reporter-3', {}],
['html', { verbose: true, subdir: 'string' }],
['custom-reporter-4', { some: 'option', width: 123 }],
],
})
})
1 change: 1 addition & 0 deletions test/coverage-test/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default defineConfig({
['html'],
['lcov', {}],
['json', { file: 'custom-json-report-name.json' }],
[resolve('./custom-reporter.cjs'), { file: 'custom-reporter-output.md' }],
],

// These will be updated by tests and reseted back by generic.report.test.ts
Expand Down

0 comments on commit a15b7f1

Please sign in to comment.