Skip to content

Commit

Permalink
feat: support multiple servers from which to gather code coverage (#880)
Browse files Browse the repository at this point in the history
Co-authored-by: Jennifer Shehane <jennifer@cypress.io>
Co-authored-by: Matt Schile <mschile@cypress.io>
  • Loading branch information
3 people authored Sep 16, 2024
1 parent 83bd4fe commit 207b027
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ workflows:
- exclude-files
- frontend
- fullstack
- multiple-backends
- one-spec
- same-folder
- support-files
Expand Down Expand Up @@ -179,6 +180,7 @@ workflows:
- test-exclude-files
- test-frontend
- test-fullstack
- test-multiple-backends
- test-one-spec
- test-same-folder
- test-support-files
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,18 @@ if (global.__coverage__) {
}
```

Or if you have multiple servers from which you are wanting to gather code coverage, you can pass an array to `url` as well:

```json
{
"env": {
"codeCoverage": {
"url": ["http://localhost:3000/__coverage__", "http://localhost:3001/__coverage__"]
}
}
}
```

That should be enough - the code coverage from the server will be requested at the end of the test run and merged with the client-side code coverage, producing a combined report.

### expectBackendCoverageOnly
Expand Down
62 changes: 36 additions & 26 deletions support.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,39 +148,49 @@ const registerHooks = () => {
// we can only request server-side code coverage
// if we are running end-to-end tests,
// otherwise where do we send the request?
const url = Cypress._.get(
const captureUrls = Cypress._.get(
Cypress.env('codeCoverage'),
'url',
'/__coverage__'
)
cy.request({
url,
log: false,
failOnStatusCode: false
})
.then((r) => {
return Cypress._.get(r, 'body.coverage', null)
function captureCoverage(url, suffix = '') {
cy.request({
url,
log: false,
failOnStatusCode: false
})
.then((coverage) => {
if (!coverage) {
// we did not get code coverage - this is the
// original failed request
const expectBackendCoverageOnly = Cypress._.get(
Cypress.env('codeCoverage'),
'expectBackendCoverageOnly',
false
)
if (expectBackendCoverageOnly) {
throw new Error(
`Expected to collect backend code coverage from ${url}`
.then((r) => {
return Cypress._.get(r, 'body.coverage', null)
})
.then((coverage) => {
if (!coverage) {
// we did not get code coverage - this is the
// original failed request
const expectBackendCoverageOnly = Cypress._.get(
Cypress.env('codeCoverage'),
'expectBackendCoverageOnly',
false
)
} else {
// we did not really expect to collect the backend code coverage
return
if (expectBackendCoverageOnly) {
throw new Error(
`Expected to collect backend code coverage from ${url}`
)
} else {
// we did not really expect to collect the backend code coverage
return
}
}
}
sendCoverage(coverage, 'backend')
})
sendCoverage(coverage, `backend${suffix}`)
})
}

if (Array.isArray(captureUrls)) {
for (const [index, url] of captureUrls.entries()) {
captureCoverage(url, `_${index}`)
}
} else {
captureCoverage(captureUrls)
}
}
})

Expand Down
3 changes: 3 additions & 0 deletions test-apps/multiple-backends/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["istanbul"]
}
3 changes: 3 additions & 0 deletions test-apps/multiple-backends/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# example: multiple backends

> Getting code coverage from multiple backends
17 changes: 17 additions & 0 deletions test-apps/multiple-backends/cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const { defineConfig } = require('cypress')

module.exports = defineConfig({
fixturesFolder: false,
env: {
codeCoverage: {
url: ['http://localhost:3003/__coverage__', 'http://localhost:3004/__coverage__'],
expectBackendCoverageOnly: true,
},
},
e2e: {
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:3003',
},
})
6 changes: 6 additions & 0 deletions test-apps/multiple-backends/cypress/e2e/spec.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// <reference types="Cypress" />
it('has multiple backends with code coverage', () => {
cy.visit('/')
cy.request('/hello')
cy.request('http://localhost:3004/world')
})
4 changes: 4 additions & 0 deletions test-apps/multiple-backends/cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = (on, config) => {
require('@cypress/code-coverage/task')(on, config)
return config
}
1 change: 1 addition & 0 deletions test-apps/multiple-backends/cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@cypress/code-coverage/support'
13 changes: 13 additions & 0 deletions test-apps/multiple-backends/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "example-multiple-backends",
"description": "Code coverage for multiple backends",
"private": true,
"scripts": {
"cy:run": "cypress run",
"start": "nyc --silent node server/server-3003 & nyc --silent node server/server-3004",
"pretest": "rimraf .nyc_output .cache coverage dist",
"test": "start-test \"3003|3004\" cy:run",
"coverage:verify": "npx nyc report --check-coverage true --lines 100",
"coverage:check-files": "check-coverage server-3003.js server-3004.js && only-covered server-3003.js server-3004.js"
}
}
3 changes: 3 additions & 0 deletions test-apps/multiple-backends/server/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<body>
test multiple backends
</body>
21 changes: 21 additions & 0 deletions test-apps/multiple-backends/server/server-3003.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const express = require('express')
const app = express()
const port = 3003

// if there is code coverage information
// then expose an endpoint that returns it
/* istanbul ignore next */
if (global.__coverage__) {
console.log('have code coverage, will add middleware for express')
console.log(`to fetch: GET :${port}/__coverage__`)
require('@cypress/code-coverage/middleware/express')(app)
}

app.use(express.static(__dirname))

app.get('/hello', (req, res) => {
console.log('sending hello')
res.send('Hello')
})

app.listen(port, () => console.log(`Example app listening on port ${port}!`))
21 changes: 21 additions & 0 deletions test-apps/multiple-backends/server/server-3004.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const express = require('express')
const app = express()
const port = 3004

// if there is code coverage information
// then expose an endpoint that returns it
/* istanbul ignore next */
if (global.__coverage__) {
console.log('have code coverage, will add middleware for express')
console.log(`to fetch: GET :${port}/__coverage__`)
require('@cypress/code-coverage/middleware/express')(app)
}

app.use(express.static(__dirname))

app.get('/world', (req, res) => {
console.log('sending world')
res.send('World!')
})

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

0 comments on commit 207b027

Please sign in to comment.