Skip to content

feat: merge nyc options from multiple files #205

New issue

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

By clicking “No 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? No Sign in to your account

Merged
merged 5 commits into from
Apr 20, 2020
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
5 changes: 4 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ workflows:
store_artifacts: true
post-steps:
- run: cat examples/exclude-files/.nyc_output/out.json
- run: cat examples/exclude-files/coverage/coverage-final.json
# store the created coverage report folder
# you can click on it in the CircleCI UI
# to see live static HTML site
Expand All @@ -380,9 +381,11 @@ workflows:
working_directory: examples/exclude-files
- run:
name: Check code coverage 📈
# we will check the final coverage report
# to make sure it only has files we are interested in
command: |
../../node_modules/.bin/check-coverage main.js
../../node_modules/.bin/only-covered main.js
../../node_modules/.bin/only-covered --from coverage/coverage-final.json main.js
working_directory: examples/exclude-files

- cypress/run:
Expand Down
6 changes: 6 additions & 0 deletions .nycrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"exclude": [
"support-utils.js",
"task-utils.js"
]
}
66 changes: 66 additions & 0 deletions cypress/integration/combine-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const { combineNycOptions, defaultNycOptions } = require('../../task-utils')
describe('Combine NYC options', () => {
it('overrides defaults', () => {
const pkgNycOptions = {
extends: '@istanbuljs/nyc-config-typescript',
all: true
}
const combined = combineNycOptions({
pkgNycOptions,
defaultNycOptions
})
cy.wrap(combined).should('deep.equal', {
extends: '@istanbuljs/nyc-config-typescript',
all: true,
'report-dir': './coverage',
reporter: ['lcov', 'clover', 'json'],
extension: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx'],
excludeAfterRemap: true
})
})

it('allows to specify reporter, but changes to array', () => {
const pkgNycOptions = {
reporter: 'text'
}
const combined = combineNycOptions({
pkgNycOptions,
defaultNycOptions
})
cy.wrap(combined).should('deep.equal', {
'report-dir': './coverage',
reporter: ['text'],
extension: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx'],
excludeAfterRemap: true
})
})

it('combines multiple options', () => {
const pkgNycOptions = {
all: true,
extension: '.js'
}
const nycrc = {
include: ['foo.js']
}
const nycrcJson = {
exclude: ['bar.js'],
reporter: ['json']
}
const combined = combineNycOptions({
pkgNycOptions,
nycrc,
nycrcJson,
defaultNycOptions
})
cy.wrap(combined).should('deep.equal', {
all: true,
'report-dir': './coverage',
reporter: ['json'],
extension: ['.js'],
excludeAfterRemap: true,
include: ['foo.js'],
exclude: ['bar.js']
})
})
})
15 changes: 12 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 1 addition & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"@cypress/webpack-preprocessor": "5.1.2",
"babel-loader": "8.1.0",
"babel-plugin-istanbul": "6.0.0",
"check-code-coverage": "1.0.1",
"check-code-coverage": "1.1.0",
"console-log-div": "0.6.3",
"cypress": "4.4.0",
"express": "4.17.1",
Expand All @@ -72,10 +72,5 @@
"typescript": "3.8.3",
"webpack": "4.42.1",
"webpack-cli": "3.3.11"
},
"nyc": {
"exclude": [
"utils.js"
]
}
}
65 changes: 64 additions & 1 deletion task-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,66 @@ const { readFileSync, writeFileSync, existsSync } = require('fs')
const { isAbsolute, resolve, join } = require('path')
const debug = require('debug')('code-coverage')

function combineNycOptions({
pkgNycOptions,
nycrc,
nycrcJson,
defaultNycOptions
}) {
// last option wins
const nycOptions = Object.assign(
{},
defaultNycOptions,
nycrc,
nycrcJson,
pkgNycOptions
)

if (typeof nycOptions.reporter === 'string') {
nycOptions.reporter = [nycOptions.reporter]
}
if (typeof nycOptions.extension === 'string') {
nycOptions.extension = [nycOptions.extension]
}

return nycOptions
}

const defaultNycOptions = {
'report-dir': './coverage',
reporter: ['lcov', 'clover', 'json'],
extension: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx'],
excludeAfterRemap: true
}

function readNycOptions(workingDirectory) {
const pkgFilename = join(workingDirectory, 'package.json')
const pkg = existsSync(pkgFilename)
? JSON.parse(readFileSync(pkgFilename, 'utf8'))
: {}
const pkgNycOptions = pkg.nyc || {}

const nycrcFilename = join(workingDirectory, '.nycrc')
const nycrc = existsSync(nycrcFilename)
? JSON.parse(readFileSync(nycrcFilename, 'utf8'))
: {}

const nycrcJsonFilename = join(workingDirectory, '.nycrc.json')
const nycrcJson = existsSync(nycrcJsonFilename)
? JSON.parse(readFileSync(nycrcJsonFilename, 'utf8'))
: {}

const nycOptions = combineNycOptions({
pkgNycOptions,
nycrc,
nycrcJson,
defaultNycOptions
})
debug('combined NYC options %o', nycOptions)

return nycOptions
}

function checkAllPathsNotFound(nycFilename) {
const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8'))

Expand Down Expand Up @@ -198,5 +258,8 @@ module.exports = {
showNycInfo,
resolveRelativePaths,
checkAllPathsNotFound,
tryFindingLocalFiles
tryFindingLocalFiles,
readNycOptions,
combineNycOptions,
defaultNycOptions
}
77 changes: 48 additions & 29 deletions task.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const {
showNycInfo,
resolveRelativePaths,
checkAllPathsNotFound,
tryFindingLocalFiles
tryFindingLocalFiles,
readNycOptions
} = require('./task-utils')
const { fixSourcePaths } = require('./support-utils')
const NYC = require('nyc')
Expand All @@ -28,7 +29,6 @@ const pkgFilename = join(processWorkingDirectory, 'package.json')
const pkg = existsSync(pkgFilename)
? JSON.parse(readFileSync(pkgFilename, 'utf8'))
: {}
const nycOptions = pkg.nyc || {}
const scripts = pkg.scripts || {}
const DEFAULT_CUSTOM_COVERAGE_SCRIPT_NAME = 'coverage:report'
const customNycReportScript = scripts[DEFAULT_CUSTOM_COVERAGE_SCRIPT_NAME]
Expand All @@ -42,6 +42,37 @@ function saveCoverage(coverage) {
writeFileSync(nycFilename, JSON.stringify(coverage, null, 2))
}

function maybePrintFinalCoverageFiles(folder) {
const jsonReportFilename = join(folder, 'coverage-final.json')
if (!existsSync) {
debug('Did not find final coverage file %s', jsonReportFilename)
return
}

debug('Final coverage in %s', jsonReportFilename)
const finalCoverage = JSON.parse(readFileSync(jsonReportFilename, 'utf8'))
Object.keys(finalCoverage).forEach(key => {
const s = finalCoverage[key].s || {}
const statements = Object.keys(s)
const totalStatements = statements.length
let coveredStatements = 0
statements.forEach(statementKey => {
if (s[statementKey]) {
coveredStatements += 1
}
})

const allCovered = coveredStatements === totalStatements
debug(
'%s %s statements covered %d/%d',
allCovered ? '✅' : '⚠️',
key,
coveredStatements,
totalStatements
)
})
}

const tasks = {
/**
* Clears accumulated code coverage information.
Expand Down Expand Up @@ -122,41 +153,29 @@ const tasks = {
})
}

const reportFolder = nycOptions['report-dir'] || './coverage'
const reportDir = resolve(reportFolder)
const reporter = nycOptions['reporter'] || ['lcov', 'clover', 'json']

// TODO we could look at how NYC is parsing its CLI arguments
// I am mostly worried about additional NYC options that are stored in
// package.json and .nycrc resource files.
// for now let's just camel case all options
// https://github.com/istanbuljs/nyc#common-configuration-options
const nycReportOptions = {
reportDir,
tempDir: coverageFolder,
reporter: [].concat(reporter), // make sure this is a list
include: nycOptions.include,
exclude: nycOptions.exclude,
// from working with TypeScript code seems we need these settings too
excludeAfterRemap: true,
extension: nycOptions.extension || [
'.js',
'.cjs',
'.mjs',
'.ts',
'.tsx',
'.jsx'
],
all: nycOptions.all
const nycReportOptions = readNycOptions(processWorkingDirectory)

// override a couple of options
nycReportOptions.tempDir = coverageFolder
if (nycReportOptions['report-dir']) {
nycReportOptions['report-dir'] = resolve(nycReportOptions['report-dir'])
}

debug('calling NYC reporter with options %o', nycReportOptions)
debug('current working directory is %s', process.cwd())
const nyc = new NYC(nycReportOptions)

const returnReportFolder = () => {
debug('after reporting, returning the report folder name %s', reportDir)
return reportDir
const reportFolder = nycReportOptions['report-dir']
debug(
'after reporting, returning the report folder name %s',
reportFolder
)

maybePrintFinalCoverageFiles(reportFolder)

return reportFolder
}
return nyc.report().then(returnReportFolder)
}
Expand Down