Skip to content

Commit

Permalink
Batch coverage data sent to combineCoverage to prevent timeouts (#877)
Browse files Browse the repository at this point in the history
  • Loading branch information
aantes-st authored Oct 2, 2024
1 parent bf696bb commit a5a95d5
Show file tree
Hide file tree
Showing 17 changed files with 814 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ workflows:
jobname:
- all-files
- backend
- batch-send-coverage
- before-all-visit
- before-each-visit
- cra-e2e-and-ct
Expand Down Expand Up @@ -174,6 +175,7 @@ workflows:
- test-code-coverage-plugin
- test-all-files
- test-backend
- test-batch-send-coverage
- test-before-all-visit
- test-before-each-visit
- test-cra-e2e-and-ct
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,21 @@ Deeply nested objects will sometimes have `[object Object]` values printed. You
DEBUG_DEPTH=10 DEBUG=code-coverage npm run dev
```

### Common issues
## Common issues

Common issue: [not instrumenting your application when running Cypress](#instrument-your-application).

If the plugin worked before in version X but stopped after upgrading to version Y, please try the [released versions](https://github.com/cypress-io/code-coverage/releases) between X and Y to see where the breaking change was.

If you decide to open an issue in this repository, please fill in all information the [issue template](https://github.com/cypress-io/code-coverage/blob/master/.github/ISSUE_TEMPLATE/bug_report.md) asks for. The issues most likely to be resolved have debug logs, screenshots, and hopefully public repository links so we can try running the tests ourselves.

### Coverage reporting timeouts

If the plugin times out when sending coverage report data to be merged, this may be due to a very large
report being sent across processes. You can batch the report by setting the `sendCoverageBatchSize` environment
variable in your `cypress.config.js` file's 'env' section. Assign the variable an integer value representing
the number of report keys to send per batch.

## Contributing

You can test changes locally by running tests and confirming that the code coverage has been calculated and saved.
Expand Down
14 changes: 13 additions & 1 deletion support-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,19 @@ function fixSourcePaths(coverage) {
})
}

/**
* Validates and returns the configured batch size for
* sending coverage to the backend
*/
function getSendCoverageBatchSize() {
const batchSize = Cypress.env('sendCoverageBatchSize')
const parsedBatchSize = parseInt(batchSize)
const isValid = !isNaN(parsedBatchSize) && parsedBatchSize > 0
return isValid ? parsedBatchSize : null
}

module.exports = {
fixSourcePaths,
filterFilesFromCoverage
filterFilesFromCoverage,
getSendCoverageBatchSize
}
40 changes: 35 additions & 5 deletions support.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

const dayjs = require('dayjs')
var duration = require('dayjs/plugin/duration')
const { filterFilesFromCoverage } = require('./support-utils')
const {
filterFilesFromCoverage,
getSendCoverageBatchSize
} = require('./support-utils')

dayjs.extend(duration)

Expand All @@ -16,10 +19,37 @@ const sendCoverage = (coverage, pathname = '/') => {

const totalCoverage = filterFilesFromCoverage(coverage)

// stringify coverage object for speed
cy.task('combineCoverage', JSON.stringify(totalCoverage), {
log: false
})
const envBatchSize = getSendCoverageBatchSize()
const keys = Object.keys(totalCoverage)

if (envBatchSize && envBatchSize < keys.length) {
sendBatchCoverage(totalCoverage, envBatchSize)
} else {
cy.task('combineCoverage', JSON.stringify(totalCoverage), {
log: false
})
}
}

/**
* Sends collected code coverage object to the backend code
* in batches via "cy.task".
*/
const sendBatchCoverage = (totalCoverage, batchSize) => {
const keys = Object.keys(totalCoverage)

for (let i = 0; i < keys.length; i += batchSize) {
const batchKeys = keys.slice(i, i + batchSize)
const batchCoverage = {}

batchKeys.forEach((key) => {
batchCoverage[key] = totalCoverage[key]
})

cy.task('combineCoverage', JSON.stringify(batchCoverage), {
log: false
})
}
}

/**
Expand Down
3 changes: 3 additions & 0 deletions test-apps/batch-send-coverage/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": ["istanbul"]
}
4 changes: 4 additions & 0 deletions test-apps/batch-send-coverage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Test Case: Batch Send Coverage
This test app tests that all expected files are covered when using
the `sendCoverageBatchSize` environment variable in the Cypress
configuration file.
14 changes: 14 additions & 0 deletions test-apps/batch-send-coverage/cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const { defineConfig } = require('cypress')

module.exports = defineConfig({
fixturesFolder: false,
env: {
sendCoverageBatchSize: 1
},
e2e: {
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:1234'
}
})
24 changes: 24 additions & 0 deletions test-apps/batch-send-coverage/cypress/e2e/spec.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// <reference types="cypress" />
it('works', () => {
cy.visit('/')
cy.contains('Page body')

cy.window()
.invoke('reverse', 'super')
.should('equal', 'repus')

cy.window()
.invoke('numsTimesTwo', [1, 2, 3])
.should('deep.equal', [2, 4, 6])

cy.window()
.invoke('add', 2, 3)
.should('equal', 5)

cy.window()
.invoke('sub', 5, 2)
.should('equal', 3)

// application's code should be instrumented
cy.window().should('have.property', '__coverage__')
})
4 changes: 4 additions & 0 deletions test-apps/batch-send-coverage/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/batch-send-coverage/cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@cypress/code-coverage/support'
1 change: 1 addition & 0 deletions test-apps/batch-send-coverage/cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require('./commands')
17 changes: 17 additions & 0 deletions test-apps/batch-send-coverage/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 src="third.js"></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 test-apps/batch-send-coverage/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
Loading

0 comments on commit a5a95d5

Please sign in to comment.