Skip to content

Commit dfaed9b

Browse files
authored
feat: find local files better (#197)
* 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
1 parent 20a2a9a commit dfaed9b

File tree

16 files changed

+460
-53
lines changed

16 files changed

+460
-53
lines changed

Diff for: .circleci/config.yml

+25
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,30 @@ workflows:
194194
../../node_modules/.bin/only-covered main.js
195195
working_directory: examples/before-all-visit
196196

197+
- cypress/run:
198+
attach-workspace: true
199+
name: example-docker-paths
200+
requires:
201+
- cypress/install
202+
# there are no jobs to follow this one
203+
# so no need to save the workspace files (saves time)
204+
no-workspace: true
205+
working_directory: examples/docker-paths
206+
command: '../../node_modules/.bin/cypress run'
207+
post-steps:
208+
# store the created coverage report folder
209+
# you can click on it in the CircleCI UI
210+
# to see live static HTML site
211+
- store_artifacts:
212+
path: examples/docker-paths/coverage
213+
- run:
214+
name: Check code coverage 📈
215+
command: |
216+
../../node_modules/.bin/check-coverage main.js
217+
../../node_modules/.bin/check-coverage second.js
218+
../../node_modules/.bin/only-covered main.js second.js
219+
working_directory: examples/docker-paths
220+
197221
- cypress/run:
198222
attach-workspace: true
199223
name: example-ts-example
@@ -395,3 +419,4 @@ workflows:
395419
- example-use-plugins-and-support
396420
- example-one-spec
397421
- example-exclude-files
422+
- example-docker-paths

Diff for: examples/docker-paths/README.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# example-docker-paths
2+
3+
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.
4+
5+
Source files from `app` folder were instrumented into `dist` folder with command
6+
7+
```shell
8+
$ npx nyc instrument app dist
9+
```
10+
11+
Then the `index.html` file was copied into `dist` folder.
12+
13+
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`.
14+
15+
When Cypress runs, the `.nyc_output/out.json` is updated, so the path is valid local path like:
16+
17+
```
18+
{
19+
"/var/www/test/site/app/main.js": {
20+
"path": "/Users/gleb/git/code-coverage/examples/docker-paths/app/main.js",
21+
"statementMap": {
22+
...
23+
```
24+
25+
And the report has valid HTML with sources
26+
27+
![All files](images/files.png)
28+
29+
![Single file](images/file.png)
30+
31+
**Note:** remember to remove existing `.nyc_output` folder if running Cypress in non-interactive mode `rm -rf .nyc_output/`.
32+
33+
When running with [debug logs](https://github.com/cypress-io/code-coverage#debugging) you should see messages:
34+
35+
```
36+
found common folder /var/www/test/site that matches
37+
current working directory /Users/gleb/git/code-coverage/examples/docker-paths
38+
```

Diff for: examples/docker-paths/app/index.html

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<body>
2+
Page body
3+
<script src="main.js"></script>
4+
<script src="second.js"></script>
5+
<script>
6+
// use functions creates in "main.js"
7+
if (add(2, 3) !== 5) {
8+
throw new Error('wrong addition')
9+
}
10+
if (sub(2, 3) !== -1) {
11+
throw new Error('wrong subtraction')
12+
}
13+
if (reverse('foo') !== 'oof') {
14+
throw new Error('wrong string reverse')
15+
}
16+
</script>
17+
</body>

Diff for: examples/docker-paths/app/main.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
window.add = (a, b) => a + b
2+
3+
window.sub = (a, b) => a - b

Diff for: examples/docker-paths/app/second.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// this file should be excluded from the final coverage numbers
2+
// using "nyc.exclude" list in package.json
3+
window.reverse = s =>
4+
s
5+
.split('')
6+
.reverse()
7+
.join('')

Diff for: examples/docker-paths/cypress.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"pluginsFile": "../../plugins",
3+
"supportFile": "../../support",
4+
"fixturesFolder": false
5+
}

Diff for: examples/docker-paths/cypress/integration/spec.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference types="cypress" />
2+
describe('docker-paths', () => {
3+
it('works', () => {
4+
cy.visit('dist/index.html')
5+
cy.contains('Page body')
6+
7+
cy.window()
8+
.invoke('reverse', 'super')
9+
.should('equal', 'repus')
10+
})
11+
})

Diff for: examples/docker-paths/dist/index.html

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<body>
2+
Page body
3+
<script src="main.js"></script>
4+
<script src="second.js"></script>
5+
<script>
6+
// use functions creates in "main.js"
7+
if (add(2, 3) !== 5) {
8+
throw new Error('wrong addition')
9+
}
10+
if (sub(2, 3) !== -1) {
11+
throw new Error('wrong subtraction')
12+
}
13+
if (reverse('foo') !== 'oof') {
14+
throw new Error('wrong string reverse')
15+
}
16+
</script>
17+
</body>

Diff for: examples/docker-paths/dist/main.js

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

Diff for: examples/docker-paths/dist/second.js

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

Diff for: examples/docker-paths/images/file.png

69.3 KB
Loading

Diff for: examples/docker-paths/images/files.png

86.1 KB
Loading

Diff for: examples/docker-paths/package.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "example-docker-paths",
3+
"private": true,
4+
"version": "1.0.0",
5+
"description": "Instrumented files in Docker container are found locally",
6+
"main": "index.js",
7+
"scripts": {
8+
"cy:open": "../../node_modules/.bin/cypress open",
9+
"cy:run": "../../node_modules/.bin/cypress run"
10+
},
11+
"keywords": [],
12+
"author": "",
13+
"license": "ISC"
14+
}

Diff for: package.json

+3
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,8 @@
6666
"serve": "11.3.0",
6767
"start-server-and-test": "1.10.11",
6868
"typescript": "3.8.3"
69+
},
70+
"nyc": {
71+
"exclude": ["utils.js"]
6972
}
7073
}

Diff for: task.js

+17-52
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
// @ts-check
22
const istanbul = require('istanbul-lib-coverage')
3-
const { join, resolve, isAbsolute } = require('path')
3+
const { join, resolve } = require('path')
44
const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('fs')
55
const execa = require('execa')
6-
const fs = require('fs')
7-
const { fixSourcePathes } = require('./utils')
6+
const {
7+
fixSourcePathes,
8+
showNycInfo,
9+
resolveRelativePaths,
10+
checkAllPathsNotFound,
11+
tryFindingLocalFiles
12+
} = require('./utils')
813
const NYC = require('nyc')
914

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

40-
/**
41-
* Looks at all coverage objects in the given JSON coverage file
42-
* and if the file is relative, and exists, changes its path to
43-
* be absolute.
44-
*/
45-
function resolvePaths(nycFilename) {
46-
const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8'))
47-
48-
const coverageKeys = Object.keys(nycCoverage)
49-
if (!coverageKeys.length) {
50-
console.error('⚠️ file %s has no coverage information', nycFilename)
51-
return
52-
}
53-
debug('NYC file %s has %d key(s)', nycFilename, coverageKeys.length)
54-
55-
let changed
56-
const maxPrintKeys = 3
57-
58-
Object.keys(nycCoverage).forEach((key, k) => {
59-
const coverage = nycCoverage[key]
60-
61-
// printing a few found keys and file paths from the coverage file
62-
// will make debugging any problems much much easier
63-
if (k < maxPrintKeys) {
64-
debug('%d key %s file path %s', k + 1, key, coverage.path)
65-
}
66-
67-
if (coverage.path && !isAbsolute(coverage.path)) {
68-
if (existsSync(coverage.path)) {
69-
debug('resolving path %s', coverage.path)
70-
coverage.path = resolve(coverage.path)
71-
changed = true
72-
}
73-
}
74-
})
75-
76-
if (changed) {
77-
debug('saving updated file %s', nycFilename)
78-
writeFileSync(
79-
nycFilename,
80-
JSON.stringify(nycCoverage, null, 2) + '\n',
81-
'utf8'
82-
)
83-
}
84-
}
85-
8645
const tasks = {
8746
/**
8847
* Clears accumulated code coverage information.
@@ -143,7 +102,13 @@ const tasks = {
143102
return null
144103
}
145104

146-
resolvePaths(nycFilename)
105+
showNycInfo(nycFilename)
106+
const allSourceFilesMissing = checkAllPathsNotFound(nycFilename)
107+
if (allSourceFilesMissing) {
108+
tryFindingLocalFiles(nycFilename)
109+
}
110+
111+
resolveRelativePaths(nycFilename)
147112

148113
if (customNycReportScript) {
149114
debug(

0 commit comments

Comments
 (0)