[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(coverage): expose profiling timers (#7820)

authored by

Ari Perkkiö and committed by
GitHub
(Apr 11, 2025, 8:24 AM +0300) 5652bf92 b1942636

+92 -2
+4
docs/guide/coverage.md
··· 215 215 216 216 To see all configurable options for coverage, see the [coverage Config Reference](https://vitest.dev/config/#coverage). 217 217 218 + ## Coverage performance 219 + 220 + If code coverage generation is slow on your project, see [Profiling Test Performance | Code coverage](/guide/profiling-test-performance.html#code-coverage). 221 + 218 222 ## Vitest UI 219 223 220 224 You can check your coverage report in [Vitest UI](/guide/ui).
+26
docs/guide/profiling-test-performance.md
··· 178 178 _src_prime-number_ts-525172412.js 179 179 ``` 180 180 181 + ## Code coverage 182 + 183 + If code coverage generation is slow on your project you can use `DEBUG=vitest:coverage` environment variable to enable performance logging. 184 + 185 + ```bash 186 + $ DEBUG=vitest:coverage vitest --run --coverage 187 + 188 + RUN v3.1.1 /x/vitest-example 189 + 190 + vitest:coverage Reading coverage results 2/2 191 + vitest:coverage Converting 1/2 192 + vitest:coverage 4 ms /x/src/multiply.ts 193 + vitest:coverage Converting 2/2 194 + vitest:coverage 552 ms /x/src/add.ts 195 + vitest:coverage Uncovered files 1/2 196 + vitest:coverage File "/x/src/large-file.ts" is taking longer than 3s # [!code error] 197 + vitest:coverage 3027 ms /x/src/large-file.ts 198 + vitest:coverage Uncovered files 2/2 199 + vitest:coverage 4 ms /x/src/untested-file.ts 200 + vitest:coverage Generate coverage total time 3521 ms 201 + ``` 202 + 203 + This profiling approach is great for detecting large files that are accidentally picked by coverage providers. 204 + For example if your configuration is accidentally including large built minified Javascript files in code coverage, they should appear in logs. 205 + In these cases you might want to adjust your [`coverage.include`](/config/#coverage-include) and [`coverage.exclude`](/config/#coverage-exclude) options. 206 + 181 207 ## Inspecting profiling records 182 208 183 209 You can inspect the contents of `*.cpuprofile` and `*.heapprofile` with various tools. See list below for examples.
+23 -1
packages/coverage-istanbul/src/provider.ts
··· 89 89 } 90 90 91 91 async generateCoverage({ allTestsRun }: ReportContext): Promise<CoverageMap> { 92 + const start = debug.enabled ? performance.now() : 0 93 + 92 94 const coverageMap = this.createCoverageMap() 93 95 let coverageMapByTransformMode = this.createCoverageMap() 94 96 ··· 118 120 119 121 if (this.options.excludeAfterRemap) { 120 122 coverageMap.filter(filename => this.testExclude.shouldInstrument(filename)) 123 + } 124 + 125 + if (debug.enabled) { 126 + debug('Generate coverage total time %d ms', (performance.now() - start!).toFixed()) 121 127 } 122 128 123 129 return coverageMap ··· 182 188 // Note that these cannot be run parallel as synchronous instrumenter.lastFileCoverage 183 189 // returns the coverage of the last transformed file 184 190 for (const [index, filename] of uncoveredFiles.entries()) { 185 - debug('Uncovered file %s %d/%d', filename, index, uncoveredFiles.length) 191 + let timeout: ReturnType<typeof setTimeout> | undefined 192 + let start: number | undefined 193 + 194 + if (debug.enabled) { 195 + start = performance.now() 196 + timeout = setTimeout(() => debug(c.bgRed(`File "${filename}" is taking longer than 3s`)), 3_000) 197 + 198 + debug('Uncovered file %d/%d', index, uncoveredFiles.length) 199 + } 186 200 187 201 // Make sure file is not served from cache so that instrumenter loads up requested file coverage 188 202 await transform(`${filename}?v=${cacheKey}`) 189 203 const lastCoverage = this.instrumenter.lastFileCoverage() 190 204 coverageMap.addFileCoverage(lastCoverage) 205 + 206 + if (debug.enabled) { 207 + clearTimeout(timeout) 208 + 209 + const diff = performance.now() - start! 210 + const color = diff > 500 ? c.bgRed : c.bgGreen 211 + debug(`${color(` ${diff.toFixed()} ms `)} ${filename}`) 212 + } 191 213 } 192 214 193 215 return coverageMap
+38
packages/coverage-v8/src/provider.ts
··· 65 65 } 66 66 67 67 async generateCoverage({ allTestsRun }: ReportContext): Promise<CoverageMap> { 68 + const start = debug.enabled ? performance.now() : 0 69 + 68 70 const coverageMap = this.createCoverageMap() 69 71 let merged: RawCoverage = { result: [] } 70 72 ··· 108 110 109 111 if (this.options.excludeAfterRemap) { 110 112 coverageMap.filter(filename => this.testExclude.shouldInstrument(filename)) 113 + } 114 + 115 + if (debug.enabled) { 116 + debug(`Generate coverage total time ${(performance.now() - start!).toFixed()} ms`) 111 117 } 112 118 113 119 return coverageMap ··· 189 195 } 190 196 191 197 await Promise.all(chunk.map(async (filename) => { 198 + let timeout: ReturnType<typeof setTimeout> | undefined 199 + let start: number | undefined 200 + 201 + if (debug.enabled) { 202 + start = performance.now() 203 + timeout = setTimeout(() => debug(c.bgRed(`File "${filename.pathname}" is taking longer than 3s`)), 3_000) 204 + } 205 + 192 206 const sources = await this.getSources( 193 207 filename.href, 194 208 transformResults, ··· 225 239 } 226 240 227 241 coverageMap.merge(converter.toIstanbul()) 242 + 243 + if (debug.enabled) { 244 + clearTimeout(timeout) 245 + 246 + const diff = performance.now() - start! 247 + const color = diff > 500 ? c.bgRed : c.bgGreen 248 + debug(`${color(` ${diff.toFixed()} ms `)} ${filename.pathname}`) 249 + } 228 250 })) 229 251 } 230 252 ··· 344 366 345 367 await Promise.all( 346 368 chunk.map(async ({ url, functions, startOffset }) => { 369 + let timeout: ReturnType<typeof setTimeout> | undefined 370 + let start: number | undefined 371 + 372 + if (debug.enabled) { 373 + start = performance.now() 374 + timeout = setTimeout(() => debug(c.bgRed(`File "${fileURLToPath(url)}" is taking longer than 3s`)), 3_000) 375 + } 376 + 347 377 const sources = await this.getSources( 348 378 url, 349 379 transformResults, ··· 368 398 } 369 399 370 400 coverageMap.merge(converter.toIstanbul()) 401 + 402 + if (debug.enabled) { 403 + clearTimeout(timeout) 404 + 405 + const diff = performance.now() - start! 406 + const color = diff > 500 ? c.bgRed : c.bgGreen 407 + debug(`${color(` ${diff.toFixed()} ms `)} ${fileURLToPath(url)}`) 408 + } 371 409 }), 372 410 ) 373 411 }
+1 -1
packages/vitest/src/node/coverage.ts
··· 217 217 for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) { 218 218 if (onDebug.enabled) { 219 219 index += chunk.length 220 - onDebug('Covered files %d/%d', index, total) 220 + onDebug(`Reading coverage results ${index}/${total}`) 221 221 } 222 222 223 223 await Promise.all(chunk.map(async (filename) => {