diff --git a/docs/guide/coverage.md b/docs/guide/coverage.md index 19ab602b4cb6..e09a2e21034c 100644 --- a/docs/guide/coverage.md +++ b/docs/guide/coverage.md @@ -169,7 +169,9 @@ To see all configurable options for coverage, see the [coverage Config Reference Since Vitest 0.31.0, you can check your coverage report in [Vitest UI](./ui). -If you have configured coverage reporters, don't forget to add `html` reporter to the list, Vitest UI will only enable html coverage report if it is present. +Vitest UI will enable coverage report when it is enabled explicitly and the html coverage reporter is present, otherwise it will not be available: +- enable `coverage.enabled=true` in your configuration or run Vitest with `--coverage.enabled=true` flag +- add `html` to the `coverage.reporters` list: you can also enable `subdir` option to put coverage report in a subdirectory html coverage activation in Vitest UI html coverage activation in Vitest UI diff --git a/packages/ui/client/composables/navigation.ts b/packages/ui/client/composables/navigation.ts index cb6fd3186cfc..a459969e6618 100644 --- a/packages/ui/client/composables/navigation.ts +++ b/packages/ui/client/composables/navigation.ts @@ -21,7 +21,15 @@ export const coverageUrl = computed(() => { if (coverageEnabled.value) { const url = `${window.location.protocol}//${window.location.hostname}:${config.value!.api!.port!}` const idx = coverage.value!.reportsDirectory.lastIndexOf('/') - return `${url}/${coverage.value!.reportsDirectory.slice(idx + 1)}/index.html` + const htmlReporter = coverage.value!.reporter.find((reporter) => { + if (reporter[0] !== 'html') + return undefined + + return reporter + }) + return htmlReporter && 'subdir' in htmlReporter[1] + ? `${url}/${coverage.value!.reportsDirectory.slice(idx + 1)}/${htmlReporter[1].subdir}/index.html` + : `${url}/${coverage.value!.reportsDirectory.slice(idx + 1)}/index.html` } return undefined diff --git a/packages/ui/node/index.ts b/packages/ui/node/index.ts index 1ca2f972213c..c00bab66b350 100644 --- a/packages/ui/node/index.ts +++ b/packages/ui/node/index.ts @@ -13,11 +13,11 @@ export default (ctx: Vitest) => { const uiOptions = ctx.config const base = uiOptions.uiBase const coverageFolder = resolveCoverageFolder(ctx) - const coveragePath = coverageFolder ? `/${basename(coverageFolder)}/` : undefined + const coveragePath = coverageFolder ? coverageFolder[1] : undefined if (coveragePath && base === coveragePath) throw new Error(`The ui base path and the coverage path cannot be the same: ${base}, change coverage.reportsDirectory`) - coverageFolder && server.middlewares.use(coveragePath!, sirv(coverageFolder, { + coverageFolder && server.middlewares.use(coveragePath!, sirv(coverageFolder[0], { single: true, dev: true, setHeaders: (res) => { @@ -35,20 +35,30 @@ export default (ctx: Vitest) => { function resolveCoverageFolder(ctx: Vitest) { const options = ctx.config - const enabled = options.api?.port - && options.coverage?.enabled - && options.coverage.reporter.some((reporter) => { + const htmlReporter = (options.api?.port && options.coverage?.enabled) + ? options.coverage.reporter.find((reporter) => { if (typeof reporter === 'string') return reporter === 'html' - return reporter.length && reporter.includes('html') + return reporter[0] === 'html' }) + : undefined + + if (!htmlReporter) + return undefined // reportsDirectory not resolved yet - return enabled - ? resolve( - ctx.config?.root || options.root || process.cwd(), - options.coverage.reportsDirectory || coverageConfigDefaults.reportsDirectory, - ) + const root = resolve( + ctx.config?.root || options.root || process.cwd(), + options.coverage.reportsDirectory || coverageConfigDefaults.reportsDirectory, + ) + + const subdir = (Array.isArray(htmlReporter) && htmlReporter.length > 1 && 'subdir' in htmlReporter[1]) + ? htmlReporter[1].subdir : undefined + + if (!subdir) + return [root, `/${basename(root)}/`] + + return [resolve(root, subdir), `/${basename(root)}/${subdir}/`] }