Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(coverage): browser mode + coverage.all #7597

Merged
merged 5 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions packages/coverage-v8/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ export class V8CoverageProvider extends BaseCoverageProvider<ResolvedCoverageOpt
const coveredFiles = coverageMap.files()
const untestedCoverage = await this.getUntestedFiles(coveredFiles)

const converted = await this.convertCoverage(untestedCoverage)
coverageMap.merge(await transformCoverage(converted))
coverageMap.merge(await transformCoverage(untestedCoverage))
}

if (this.options.excludeAfterRemap) {
Expand Down Expand Up @@ -158,7 +157,7 @@ export class V8CoverageProvider extends BaseCoverageProvider<ResolvedCoverageOpt
)
}

private async getUntestedFiles(testedFiles: string[]): Promise<RawCoverage> {
private async getUntestedFiles(testedFiles: string[]): Promise<CoverageMap> {
const transformResults = normalizeTransformResults(
this.ctx.vitenode.fetchCache,
)
Expand All @@ -179,56 +178,57 @@ export class V8CoverageProvider extends BaseCoverageProvider<ResolvedCoverageOpt
.map(file => pathToFileURL(file))
.filter(file => !testedFiles.includes(file.pathname))

let merged: RawCoverage = { result: [] }
let index = 0

const coverageMap = this.createCoverageMap()

for (const chunk of this.toSlices(uncoveredFiles, this.options.processingConcurrency)) {
if (debug.enabled) {
index += chunk.length
debug('Uncovered files %d/%d', index, uncoveredFiles.length)
}

const coverages = await Promise.all(
chunk.map(async (filename) => {
const { originalSource } = await this.getSources(
filename.href,
transformResults,
transform,
)
await Promise.all(chunk.map(async (filename) => {
const sources = await this.getSources(
filename.href,
transformResults,
transform,
)

const converter = v8ToIstanbul(
filename.href,
0,
sources,
undefined,
this.options.ignoreEmptyLines,
)

const coverage = {
url: filename.href,
scriptId: '0',
// Create a made up function to mark whole file as uncovered. Note that this does not exist in source maps.
functions: [
await converter.load()

try {
// Create a made up function to mark whole file as uncovered. Note that this does not exist in source maps.
converter.applyCoverage([{
ranges: [
{
ranges: [
{
startOffset: 0,
endOffset: originalSource.length,
count: 0,
},
],
isBlockCoverage: true,
// This is magical value that indicates an empty report: https://github.com/istanbuljs/v8-to-istanbul/blob/fca5e6a9e6ef38a9cdc3a178d5a6cf9ef82e6cab/lib/v8-to-istanbul.js#LL131C40-L131C40
functionName: '(empty-report)',
startOffset: 0,
endOffset: sources.originalSource.length,
count: 0,
},
],
}

return { result: [coverage] }
}),
)
isBlockCoverage: true,
// This is magical value that indicates an empty report: https://github.com/istanbuljs/v8-to-istanbul/blob/fca5e6a9e6ef38a9cdc3a178d5a6cf9ef82e6cab/lib/v8-to-istanbul.js#LL131C40-L131C40
functionName: '(empty-report)',
}])
}
catch (error) {
this.ctx.logger.error(`Failed to convert coverage for uncovered ${filename.href}.\n`, error)
}

merged = mergeProcessCovs([
merged,
...coverages.filter(
(cov): cov is NonNullable<typeof cov> => cov != null,
),
])
coverageMap.merge(converter.toIstanbul())
}))
}

return merged
return coverageMap
}

private async getSources<TransformResult extends (FetchResult | Awaited<ReturnType<typeof this.ctx.vitenode.transformRequest>>)>(
Expand Down
2 changes: 1 addition & 1 deletion packages/vite-node/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ export class ViteNodeRunner {
}

protected importExternalModule(path: string): Promise<any> {
return import(path)
return import(/* @vite-ignore */ path)
}

/**
Expand Down
16 changes: 13 additions & 3 deletions packages/vitest/src/node/coverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,20 +552,30 @@ export class BaseCoverageProvider<Options extends ResolvedCoverageOptions<'istan
const servers = [
...ctx.projects.map(project => ({
root: project.config.root,
isBrowserEnabled: project.isBrowserEnabled(),
vitenode: project.vitenode,
})),
// Check core last as it will match all files anyway
{ root: ctx.config.root, vitenode: ctx.vitenode },
{ root: ctx.config.root, vitenode: ctx.vitenode, isBrowserEnabled: ctx.getRootProject().isBrowserEnabled() },
]

return async function transformFile(filename: string): Promise<TransformResult | null | undefined> {
let lastError

for (const { root, vitenode } of servers) {
if (!filename.startsWith(root)) {
for (const { root, vitenode, isBrowserEnabled } of servers) {
// On Windows root doesn't start with "/" while filenames do
if (!filename.startsWith(root) && !filename.startsWith(`/${root}`)) {
continue
}

if (isBrowserEnabled) {
const result = await vitenode.transformRequest(filename, undefined, 'web').catch(() => null)

if (result) {
return result
}
}

try {
return await vitenode.transformRequest(filename)
}
Expand Down
19 changes: 19 additions & 0 deletions test/coverage-test/fixtures/configs/vitest.config.conditional.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { join, resolve } from 'node:path'
import { defineConfig } from 'vitest/config'

export default defineConfig({
resolve: {
alias: [
{
find: /fixtures\/src\/conditional/,
replacement: "$1",
customResolver(_, __, options) {
if ('ssr' in options && options.ssr) {
return { id: resolve('fixtures/src/conditional/node.ts') }
}
return { id: resolve('fixtures/src/conditional/browser.ts') }
},
},
],
},
})
3 changes: 3 additions & 0 deletions test/coverage-test/fixtures/src/conditional/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function browser() {
return "This is for browsers only"
}
3 changes: 3 additions & 0 deletions test/coverage-test/fixtures/src/conditional/node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function node() {
return "This is for node only"
}

This file was deleted.

This file was deleted.

Loading