Skip to content

Commit

Permalink
feat: find local files better (#197)
Browse files Browse the repository at this point in the history
* chore: refactor

* adding detecting folder that matches current folder root

* move utility functions

* feat: find matching folder example

* add docker paths example to circleci

* exclude utils file from coverage
  • Loading branch information
bahmutov authored Apr 17, 2020
1 parent 20a2a9a commit dfaed9b
Show file tree
Hide file tree
Showing 16 changed files with 460 additions and 53 deletions.
25 changes: 25 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,30 @@ workflows:
../../node_modules/.bin/only-covered main.js
working_directory: examples/before-all-visit

- cypress/run:
attach-workspace: true
name: example-docker-paths
requires:
- cypress/install
# there are no jobs to follow this one
# so no need to save the workspace files (saves time)
no-workspace: true
working_directory: examples/docker-paths
command: '../../node_modules/.bin/cypress run'
post-steps:
# store the created coverage report folder
# you can click on it in the CircleCI UI
# to see live static HTML site
- store_artifacts:
path: examples/docker-paths/coverage
- run:
name: Check code coverage 📈
command: |
../../node_modules/.bin/check-coverage main.js
../../node_modules/.bin/check-coverage second.js
../../node_modules/.bin/only-covered main.js second.js
working_directory: examples/docker-paths

- cypress/run:
attach-workspace: true
name: example-ts-example
Expand Down Expand Up @@ -395,3 +419,4 @@ workflows:
- example-use-plugins-and-support
- example-one-spec
- example-exclude-files
- example-docker-paths
38 changes: 38 additions & 0 deletions examples/docker-paths/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# example-docker-paths

In this example, the source files are "instrumented" as if they were instrumented inside a Docker container. Still, Cypress code coverage plugin should find the matching current folder where same files exist and update `.nyc_output/out.json` file before generating reports.

Source files from `app` folder were instrumented into `dist` folder with command

```shell
$ npx nyc instrument app dist
```

Then the `index.html` file was copied into `dist` folder.

Then the source paths in [dist/main.js](dist/main.js) and [dist/second.js](dist/second.js) were changed to non-existent prefix folder `/var/www/test/site`.

When Cypress runs, the `.nyc_output/out.json` is updated, so the path is valid local path like:

```
{
"/var/www/test/site/app/main.js": {
"path": "/Users/gleb/git/code-coverage/examples/docker-paths/app/main.js",
"statementMap": {
...
```

And the report has valid HTML with sources

![All files](images/files.png)

![Single file](images/file.png)

**Note:** remember to remove existing `.nyc_output` folder if running Cypress in non-interactive mode `rm -rf .nyc_output/`.

When running with [debug logs](https://github.com/cypress-io/code-coverage#debugging) you should see messages:

```
found common folder /var/www/test/site that matches
current working directory /Users/gleb/git/code-coverage/examples/docker-paths
```
17 changes: 17 additions & 0 deletions examples/docker-paths/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<body>
Page body
<script src="main.js"></script>
<script src="second.js"></script>
<script>
// use functions creates in "main.js"
if (add(2, 3) !== 5) {
throw new Error('wrong addition')
}
if (sub(2, 3) !== -1) {
throw new Error('wrong subtraction')
}
if (reverse('foo') !== 'oof') {
throw new Error('wrong string reverse')
}
</script>
</body>
3 changes: 3 additions & 0 deletions examples/docker-paths/app/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
window.add = (a, b) => a + b

window.sub = (a, b) => a - b
7 changes: 7 additions & 0 deletions examples/docker-paths/app/second.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// this file should be excluded from the final coverage numbers
// using "nyc.exclude" list in package.json
window.reverse = s =>
s
.split('')
.reverse()
.join('')
5 changes: 5 additions & 0 deletions examples/docker-paths/cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"pluginsFile": "../../plugins",
"supportFile": "../../support",
"fixturesFolder": false
}
11 changes: 11 additions & 0 deletions examples/docker-paths/cypress/integration/spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference types="cypress" />
describe('docker-paths', () => {
it('works', () => {
cy.visit('dist/index.html')
cy.contains('Page body')

cy.window()
.invoke('reverse', 'super')
.should('equal', 'repus')
})
})
17 changes: 17 additions & 0 deletions examples/docker-paths/dist/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<body>
Page body
<script src="main.js"></script>
<script src="second.js"></script>
<script>
// use functions creates in "main.js"
if (add(2, 3) !== 5) {
throw new Error('wrong addition')
}
if (sub(2, 3) !== -1) {
throw new Error('wrong subtraction')
}
if (reverse('foo') !== 'oof') {
throw new Error('wrong string reverse')
}
</script>
</body>
58 changes: 58 additions & 0 deletions examples/docker-paths/dist/main.js

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

48 changes: 48 additions & 0 deletions examples/docker-paths/dist/second.js

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

Binary file added examples/docker-paths/images/file.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/docker-paths/images/files.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions examples/docker-paths/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "example-docker-paths",
"private": true,
"version": "1.0.0",
"description": "Instrumented files in Docker container are found locally",
"main": "index.js",
"scripts": {
"cy:open": "../../node_modules/.bin/cypress open",
"cy:run": "../../node_modules/.bin/cypress run"
},
"keywords": [],
"author": "",
"license": "ISC"
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,8 @@
"serve": "11.3.0",
"start-server-and-test": "1.10.11",
"typescript": "3.8.3"
},
"nyc": {
"exclude": ["utils.js"]
}
}
69 changes: 17 additions & 52 deletions task.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
// @ts-check
const istanbul = require('istanbul-lib-coverage')
const { join, resolve, isAbsolute } = require('path')
const { join, resolve } = require('path')
const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('fs')
const execa = require('execa')
const fs = require('fs')
const { fixSourcePathes } = require('./utils')
const {
fixSourcePathes,
showNycInfo,
resolveRelativePaths,
checkAllPathsNotFound,
tryFindingLocalFiles
} = require('./utils')
const NYC = require('nyc')

const debug = require('debug')('code-coverage')
Expand All @@ -20,8 +25,8 @@ const nycFilename = join(coverageFolder, 'out.json')
// potentially there might be "nyc" options in other configuration files
// it allows, but for now ignore those options
const pkgFilename = join(processWorkingDirectory, 'package.json')
const pkg = fs.existsSync(pkgFilename)
? JSON.parse(fs.readFileSync(pkgFilename, 'utf8'))
const pkg = existsSync(pkgFilename)
? JSON.parse(readFileSync(pkgFilename, 'utf8'))
: {}
const nycOptions = pkg.nyc || {}
const scripts = pkg.scripts || {}
Expand All @@ -37,52 +42,6 @@ function saveCoverage(coverage) {
writeFileSync(nycFilename, JSON.stringify(coverage, null, 2))
}

/**
* Looks at all coverage objects in the given JSON coverage file
* and if the file is relative, and exists, changes its path to
* be absolute.
*/
function resolvePaths(nycFilename) {
const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8'))

const coverageKeys = Object.keys(nycCoverage)
if (!coverageKeys.length) {
console.error('⚠️ file %s has no coverage information', nycFilename)
return
}
debug('NYC file %s has %d key(s)', nycFilename, coverageKeys.length)

let changed
const maxPrintKeys = 3

Object.keys(nycCoverage).forEach((key, k) => {
const coverage = nycCoverage[key]

// printing a few found keys and file paths from the coverage file
// will make debugging any problems much much easier
if (k < maxPrintKeys) {
debug('%d key %s file path %s', k + 1, key, coverage.path)
}

if (coverage.path && !isAbsolute(coverage.path)) {
if (existsSync(coverage.path)) {
debug('resolving path %s', coverage.path)
coverage.path = resolve(coverage.path)
changed = true
}
}
})

if (changed) {
debug('saving updated file %s', nycFilename)
writeFileSync(
nycFilename,
JSON.stringify(nycCoverage, null, 2) + '\n',
'utf8'
)
}
}

const tasks = {
/**
* Clears accumulated code coverage information.
Expand Down Expand Up @@ -143,7 +102,13 @@ const tasks = {
return null
}

resolvePaths(nycFilename)
showNycInfo(nycFilename)
const allSourceFilesMissing = checkAllPathsNotFound(nycFilename)
if (allSourceFilesMissing) {
tryFindingLocalFiles(nycFilename)
}

resolveRelativePaths(nycFilename)

if (customNycReportScript) {
debug(
Expand Down
Loading

0 comments on commit dfaed9b

Please sign in to comment.