Skip to content

Commit f9c0f24

Browse files
committed
feat: output separate coverage information for each test in addition to combined one
1 parent 4cfcc9a commit f9c0f24

File tree

3 files changed

+162
-92
lines changed

3 files changed

+162
-92
lines changed

package-lock.json

+68-68
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

support.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ dayjs.extend(duration)
1111
* Sends collected code coverage object to the backend code
1212
* via "cy.task".
1313
*/
14-
const sendCoverage = (coverage, pathname = '/') => {
14+
const sendCoverage = (coverage, pathname = '/', testName = '') => {
1515
logMessage(`Saving code coverage for **${pathname}**`)
1616

1717
const withoutSpecs = filterSpecsFromCoverage(coverage)
1818
const appCoverageOnly = filterSupportFilesFromCoverage(withoutSpecs)
1919

2020
// stringify coverage object for speed
21-
cy.task('combineCoverage', JSON.stringify(appCoverageOnly), {
21+
cy.task('combineCoverage', JSON.stringify({coverage: appCoverageOnly, testName}), {
2222
log: false
2323
})
2424
}
@@ -131,7 +131,7 @@ const registerHooks = () => {
131131
// save coverage after the test
132132
// because now the window coverage objects have been updated
133133
windowCoverageObjects.forEach((cover) => {
134-
sendCoverage(cover.coverage, cover.pathname)
134+
sendCoverage(cover.coverage, cover.pathname, Cypress.spec.name)
135135
})
136136

137137
if (!hasE2ECoverage()) {

task.js

+91-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @ts-check
22
const istanbul = require('istanbul-lib-coverage')
3-
const { join, resolve } = require('path')
4-
const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('fs')
3+
const { join, resolve, dirname } = require('path')
4+
const { existsSync, mkdirSync, readFileSync, writeFileSync, rmdirSync, readdirSync } = require('fs')
55
const execa = require('execa')
66
const {
77
showNycInfo,
@@ -57,15 +57,17 @@ const nycReportOptions = (function getNycOption() {
5757
return nycReportOptions
5858
})()
5959

60-
const nycFilename = join(nycReportOptions['temp-dir'], 'out.json')
60+
const globalNycFilename = 'out.json'
61+
const nycFilename = join(nycReportOptions.tempDir, globalNycFilename)
6162

62-
function saveCoverage(coverage) {
63-
if (!existsSync(nycReportOptions.tempDir)) {
64-
mkdirSync(nycReportOptions.tempDir, { recursive: true })
63+
function saveCoverage(coverage, fileName = 'out.json') {
64+
const outputLocation = join(nycReportOptions.tempDir, fileName)
65+
if (!existsSync(dirname(outputLocation))) {
66+
mkdirSync(dirname(outputLocation), { recursive: true })
6567
debug('created folder %s for output coverage', nycReportOptions.tempDir)
6668
}
6769

68-
writeFileSync(nycFilename, JSON.stringify(coverage, null, 2))
70+
writeFileSync(outputLocation, JSON.stringify(coverage))
6971
}
7072

7173
function maybePrintFinalCoverageFiles(folder) {
@@ -124,6 +126,7 @@ const tasks = {
124126
debug('reset code coverage in interactive mode')
125127
const coverageMap = istanbul.createCoverageMap({})
126128
saveCoverage(coverageMap)
129+
rmdirSync(join(nycReportOptions.tempDir, 'specific'), { recursive: true })
127130
}
128131
/*
129132
Else:
@@ -143,26 +146,39 @@ const tasks = {
143146
* @returns {null} Nothing is returned from this task
144147
*/
145148
combineCoverage(sentCoverage) {
146-
const coverage = JSON.parse(sentCoverage)
149+
const {coverage, testName} = JSON.parse(sentCoverage)
147150
debug('parsed sent coverage')
151+
console.log('coverage for '+testName)
148152

149153
fixSourcePaths(coverage)
150154

151-
const previousCoverage = existsSync(nycFilename)
152-
? JSON.parse(readFileSync(nycFilename, 'utf8'))
153-
: {}
155+
const handleCoverage = (fileName) => {
154156

155-
// previous code coverage object might have placeholder entries
156-
// for files that we have not seen yet,
157-
// but the user expects to include in the coverage report
158-
// the merge function messes up, so we should remove any placeholder entries
159-
// and re-insert them again when creating the report
160-
removePlaceholders(previousCoverage)
157+
const fullPath = join(nycReportOptions.tempDir, fileName)
158+
console.log('saving to', fullPath)
161159

162-
const coverageMap = istanbul.createCoverageMap(previousCoverage)
163-
coverageMap.merge(coverage)
164-
saveCoverage(coverageMap)
165-
debug('wrote coverage file %s', nycFilename)
160+
const previousCoverage = existsSync(fullPath)
161+
? JSON.parse(readFileSync(fullPath, 'utf8'))
162+
: {}
163+
164+
// previous code coverage object might have placeholder entries
165+
// for files that we have not seen yet,
166+
// but the user expects to include in the coverage report
167+
// the merge function messes up, so we should remove any placeholder entries
168+
// and re-insert them again when creating the report
169+
removePlaceholders(previousCoverage)
170+
171+
const coverageMap = istanbul.createCoverageMap(previousCoverage)
172+
coverageMap.merge(coverage)
173+
saveCoverage(coverageMap, fileName)
174+
debug('wrote coverage file %s', fileName)
175+
}
176+
177+
console.log("handle global")
178+
handleCoverage(globalNycFilename)
179+
const slug = testName.replace(/[\/]+/g, '--')
180+
console.log('handle specific for '+slug)
181+
handleCoverage(join('specific', slug, 'out.json'))
166182

167183
return null
168184
},
@@ -220,6 +236,60 @@ const tasks = {
220236

221237
return reportFolder
222238
}
239+
240+
const specificFiles = readdirSync(join(nycReportOptions.tempDir, 'specific'))
241+
console.log(specificFiles)
242+
specificFiles.forEach(async fileName => {
243+
const fullCoverageMap = await nyc.getCoverageMapFromAllCoverageFiles(join(nycReportOptions.tempDir, 'specific', fileName))
244+
245+
const writeFile = join(nycReportOptions.reportDir, 'specific', fileName.slice(fileName.lastIndexOf('--')+2).replace(/\.spec\.[jt]{1}s$/, '')+'.json')
246+
mkdirSync(dirname(writeFile), { recursive: true })
247+
writeFileSync(writeFile, JSON.stringify(Object.values(fullCoverageMap.data).map(data => {
248+
const mapData = data.data
249+
//console.log('mapdata', mapData)
250+
const b = {}
251+
Object.entries(mapData.b).forEach(([index, value]) => {
252+
if (value.some(i => i > 0)) {
253+
if (!mapData.branchMap[index].loc || !mapData.branchMap[index].loc.start) {
254+
console.log('not found ', index, ' in ', mapData.branchMap)
255+
}
256+
const lineNr = mapData.branchMap[index].loc.start.line
257+
b[lineNr] = value
258+
}
259+
})
260+
const s = {}
261+
Object.entries(mapData.s).forEach(([index, value]) => {
262+
if (value > 0) {
263+
if (!mapData.statementMap[index] || !mapData.statementMap[index].start) {
264+
console.log('not found ', index, ' in ', mapData.statementMap)
265+
}
266+
const lineNr = mapData.statementMap[index].start.line
267+
s[lineNr] = value
268+
}
269+
})
270+
const f = {}
271+
Object.entries(mapData.f).forEach(([index, value]) => {
272+
if (value > 0) {
273+
if (!mapData.fnMap[index].loc || !mapData.fnMap[index].loc.start) {
274+
console.log('not found ', index, ' in ', mapData.fnMap)
275+
}
276+
const lineNr = mapData.fnMap[index].loc.start.line
277+
f[lineNr] = value
278+
}
279+
})
280+
281+
if (Object.keys(b).length > 0 || Object.keys(s).length > 0 || Object.keys(f).length > 0) {
282+
return {
283+
path: mapData.path.replace(process.cwd()+'/', ''),
284+
b,
285+
s,
286+
f
287+
}
288+
}
289+
return undefined
290+
}).filter(i => i)))
291+
})
292+
223293
return nyc.report().then(returnReportFolder)
224294
}
225295
}

0 commit comments

Comments
 (0)