···11+import { cdp } from '@vitest/browser/context'
22+import type { V8CoverageProvider } from './provider'
33+import { loadProvider } from './load-provider'
44+55+const session = cdp()
66+77+type ScriptCoverage = Awaited<ReturnType<typeof session.send<'Profiler.takePreciseCoverage'>>>
88+99+export default {
1010+ async startCoverage() {
1111+ await session.send('Profiler.enable')
1212+ await session.send('Profiler.startPreciseCoverage', {
1313+ callCount: true,
1414+ detailed: true,
1515+ })
1616+ },
1717+1818+ async takeCoverage(): Promise<{ result: any[] }> {
1919+ const coverage = await session.send('Profiler.takePreciseCoverage')
2020+ const result: typeof coverage.result = []
2121+2222+ // Reduce amount of data sent over rpc by doing some early result filtering
2323+ for (const entry of coverage.result) {
2424+ if (filterResult(entry)) {
2525+ result.push({
2626+ ...entry,
2727+ url: decodeURIComponent(entry.url.replace(window.location.origin, '')),
2828+ })
2929+ }
3030+ }
3131+3232+ return { result }
3333+ },
3434+3535+ async stopCoverage() {
3636+ await session.send('Profiler.stopPreciseCoverage')
3737+ await session.send('Profiler.disable')
3838+ },
3939+4040+ async getProvider(): Promise<V8CoverageProvider> {
4141+ return loadProvider()
4242+ },
4343+}
4444+4545+function filterResult(coverage: ScriptCoverage['result'][number]): boolean {
4646+ if (!coverage.url.startsWith(window.location.origin)) {
4747+ return false
4848+ }
4949+5050+ if (coverage.url.includes('/node_modules/')) {
5151+ return false
5252+ }
5353+5454+ if (coverage.url.includes('__vitest_browser__')) {
5555+ return false
5656+ }
5757+5858+ if (coverage.url.includes('__vitest__/assets')) {
5959+ return false
6060+ }
6161+6262+ return true
6363+}
+46-11
packages/coverage-v8/src/index.ts
···11-import type { Profiler } from 'node:inspector'
22-import * as coverage from './takeCoverage'
11+import inspector, { type Profiler } from 'node:inspector'
22+import { provider } from 'std-env'
33import type { V8CoverageProvider } from './provider'
44+import { loadProvider } from './load-provider'
55+66+const session = new inspector.Session()
4758export default {
69 startCoverage(): void {
77- return coverage.startCoverage()
1010+ session.connect()
1111+ session.post('Profiler.enable')
1212+ session.post('Profiler.startPreciseCoverage', {
1313+ callCount: true,
1414+ detailed: true,
1515+ })
816 },
1717+918 takeCoverage(): Promise<{ result: Profiler.ScriptCoverage[] }> {
1010- return coverage.takeCoverage()
1919+ return new Promise((resolve, reject) => {
2020+ session.post('Profiler.takePreciseCoverage', async (error, coverage) => {
2121+ if (error) {
2222+ return reject(error)
2323+ }
2424+2525+ // Reduce amount of data sent over rpc by doing some early result filtering
2626+ const result = coverage.result.filter(filterResult)
2727+2828+ resolve({ result })
2929+ })
3030+3131+ if (provider === 'stackblitz') {
3232+ resolve({ result: [] })
3333+ }
3434+ })
1135 },
3636+1237 stopCoverage(): void {
1313- return coverage.stopCoverage()
3838+ session.post('Profiler.stopPreciseCoverage')
3939+ session.post('Profiler.disable')
4040+ session.disconnect()
1441 },
4242+1543 async getProvider(): Promise<V8CoverageProvider> {
1616- // to not bundle the provider
1717- const name = './provider.js'
1818- const { V8CoverageProvider } = (await import(
1919- name
2020- )) as typeof import('./provider')
2121- return new V8CoverageProvider()
4444+ return loadProvider()
2245 },
2346}
4747+4848+function filterResult(coverage: Profiler.ScriptCoverage): boolean {
4949+ if (!coverage.url.startsWith('file://')) {
5050+ return false
5151+ }
5252+5353+ if (coverage.url.includes('/node_modules/')) {
5454+ return false
5555+ }
5656+5757+ return true
5858+}
+8
packages/coverage-v8/src/load-provider.ts
···11+// to not bundle the provider
22+const name = './provider.js'
33+44+export async function loadProvider() {
55+ const { V8CoverageProvider } = (await import(/* @vite-ignore */ name)) as typeof import('./provider')
66+77+ return new V8CoverageProvider()
88+}
···33import { afterAll, beforeAll, expect } from 'vitest'
44import { readCoverageMap, runVitest, test } from '../utils'
5566+// Note that this test may fail if you have new files in "vitest/test/coverage/src"
77+// and have not yet committed those
88+const SKIP = !!process.env.ECOSYSTEM_CI || !process.env.GITHUB_ACTIONS
99+610const FILE_TO_CHANGE = resolve('./fixtures/src/file-to-change.ts')
711const NEW_UNCOVERED_FILE = resolve('./fixtures/src/new-uncovered-file.ts')
812···39434044 const coverageMap = await readCoverageMap()
41454242- // Note that this test may fail if you have new files in "vitest/test/coverage/src"
4343- // and have not yet committed those
4446 expect(coverageMap.files()).toMatchInlineSnapshot(`
4547 [
4648 "<process-cwd>/fixtures/src/file-to-change.ts",
···53555456 const changedFile = coverageMap.fileCoverageFor('<process-cwd>/fixtures/src/file-to-change.ts').toSummary()
5557 expect(changedFile.lines.pct).toBeGreaterThanOrEqual(50)
5656-}, !!process.env.ECOSYSTEM_CI)
5858+}, SKIP)