Skip to content

Commit 443029b

Browse files
fvclausmschilecacieprins
authoredOct 25, 2023
fix: code coverage incomplete on redirect (#660)
Co-authored-by: Matt Schile <mschile@gmail.com> Co-authored-by: Cacie Prins <cacieprins@users.noreply.github.com> Co-authored-by: Matthew Schile <mschile@cypress.io>
1 parent 3fc4872 commit 443029b

File tree

13 files changed

+105
-8
lines changed

13 files changed

+105
-8
lines changed
 

‎.circleci/config.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
docker:
1212
- image: cimg/node:20.8.0
1313
environment:
14-
# we don't need Cypress to check code styl
14+
# we don't need Cypress to check code style
1515
CYPRESS_INSTALL_BINARY: '0'
1616
steps:
1717
- attach_workspace:
@@ -158,6 +158,7 @@ workflows:
158158
- ts-example
159159
- unit-tests-js
160160
- use-webpack
161+
- redirect
161162
- windows_test
162163
- publish:
163164
filters:
@@ -184,4 +185,5 @@ workflows:
184185
- test-ts-example
185186
- test-unit-tests-js
186187
- test-use-webpack
188+
- test-redirect
187189
- windows_test

‎.nycrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"exclude": [
3-
"support-utils.js",
3+
"support.js",
44
"task-utils.js"
55
]
66
}

‎support.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,15 @@ const registerHooks = () => {
7272
return
7373
}
7474

75-
if (
76-
Cypress._.find(windowCoverageObjects, {
77-
coverage: applicationSourceCoverage
78-
})
79-
) {
75+
const existingCoverage = Cypress._.find(windowCoverageObjects, {
76+
coverage: applicationSourceCoverage
77+
})
78+
if (existingCoverage) {
8079
// this application code coverage object is already known
81-
// which can happen when combining `window:load` and `before` callbacks
80+
// which can happen when combining `window:load` and `before` callbacks,
81+
// it can also happen when the user navigates away and then returns to the page
82+
// in which case we need to use new applicationSourceCoverage, because the old will not be updated anymore.
83+
existingCoverage.coverage = applicationSourceCoverage
8284
return
8385
}
8486

‎test-apps/redirect/.babelrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"plugins": ["istanbul"]
3+
}

‎test-apps/redirect/.nycrc.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"exclude": [
3+
"app.js"
4+
]
5+
}

‎test-apps/redirect/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# example: redirect
2+
3+
Tests a frontend app that redirects, through un-instrumented code, back to itself.

‎test-apps/redirect/app.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// This redirect code needs to be un-instrumented (excluded in .nycrc.json)
2+
// - If the redirect code is instrumented, Cypress would then treat them as different coverage objects and merge the code coverage (not testing what we want).
3+
// - If the redirect code is un-instrumented, Cypress can't tell them apart and will update the existing coverage object to point to the correct one (testing what we want).
4+
5+
import { returnToApp } from './utils'
6+
7+
// Timeouts are necessary to allow cypress to pick up the "initial" coverage object and compare it to the existing coverage objects.
8+
new Promise((resolve) => {
9+
if (window.location.port === '1234' && !localStorage.getItem('visited')) {
10+
localStorage.setItem('visited', true)
11+
console.log('Not visited. Redirecting')
12+
setTimeout(() => {
13+
window.location.href = 'http://localhost:1235'
14+
}, 500)
15+
} else if (window.location.port === '1235') {
16+
console.log('Redirecting back.')
17+
setTimeout(() => {
18+
window.location.href = 'http://localhost:1234'
19+
}, 500)
20+
} else {
21+
console.log('Visited');
22+
setTimeout(() => {
23+
resolve()
24+
}, 500)
25+
}
26+
}).then(() => {
27+
returnToApp()
28+
})

‎test-apps/redirect/cypress.config.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const { defineConfig } = require('cypress')
2+
3+
module.exports = defineConfig({
4+
fixturesFolder: false,
5+
e2e: {
6+
setupNodeEvents(on, config) {
7+
require('@cypress/code-coverage/task')(on, config)
8+
return config
9+
},
10+
baseUrl: 'http://localhost:1234',
11+
env: {
12+
codeCoverage: {
13+
exclude: ['cypress/**/*.*']
14+
}
15+
},
16+
chromeWebSecurity: false
17+
}
18+
})
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// enables intelligent code completion for Cypress commands
2+
// https://on.cypress.io/intelligent-code-completion
3+
/// <reference types="Cypress" />
4+
5+
context('Page test', () => {
6+
it('redirects back to the app', function() {
7+
cy.clearLocalStorage()
8+
cy.visit("http://localhost:1234")
9+
cy.contains("Returned to app")
10+
})
11+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '@cypress/code-coverage/support'

‎test-apps/redirect/index.html

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<body>
2+
<h2>Test page</h2>
3+
<script src="app.js"></script>
4+
</body>

‎test-apps/redirect/package.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "example-redirect",
3+
"description": "Tests a frontend app that redirects, through un-instrumented code, back to itself.",
4+
"devDependencies": {
5+
"@babel/core": "^7.12.0"
6+
},
7+
"scripts": {
8+
"cy:run": "cypress run",
9+
"start:app": "parcel serve -p 1234 index.html",
10+
"start:other-app": "parcel serve -p 1235 index.html",
11+
"pretest": "rimraf .nyc_output .cache coverage dist",
12+
"test": "start-test start:app http://localhost:1234 start:other-app http://localhost:1235 cy:run",
13+
"coverage:verify": "npx nyc report --check-coverage true --lines 100",
14+
"coverage:check-files": "check-coverage utils.js && only-covered utils.js"
15+
}
16+
}

‎test-apps/redirect/utils.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const returnToApp = () => {
2+
document.body
3+
.appendChild(document.createTextNode('Returned to app'))
4+
}

0 commit comments

Comments
 (0)
Please sign in to comment.