CI Workflows
Upload strategies
When you run tests and create recordings, they are stored locally. You can opt to upload them automatically or define your own uploading strategy. All uploaded recordings become accessible in the Replay App.
While uploading just failed test is good for saving resources, our recommendation is to upload both failed and passed tests so that you can compare them. This can be really useful for debugging purposes.
Upload failed tests only
By default, all test replays are uploaded no matter the result. If you want to upload only the failed recordings, you can use the filter
property in the plugin configuration:
export default defineConfig({
e2e: {
setupNodeEvents(cyOn, config) {
const on = wrapOn(cyOn)
replayPlugin(on, config, {
upload: true,
apiKey: process.env.REPLAY_API_KEY,
filter: function (recording) {
// upload runtime crashes and any failed tests
return (
recording.status === 'crashed' ||
recording.metadata.test.result === 'failed'
)
},
})
return config
},
},
})
Upload failed and flaky Cypress tests
By default, all test replays are uploaded no matter the result. If you want to upload failed and flaky tests, you can use the filter
property in the plugin configuration:
export default defineConfig({
e2e: {
setupNodeEvents(cyOn, config) {
const on = wrapOn(cyOn)
replayPlugin(on, config, {
upload: true,
apiKey: process.env.REPLAY_API_KEY,
filter: function (recording) {
// upload runtime crashes and recordings with any tests that failed
return (
recording.status === 'crashed' ||
recording.metadata.test.tests.some(
(test) => test.result === 'failed',
)
)
},
})
return config
},
},
})
Upload only for the primary branch
The recording metadata includes some details about the source control including the repository and branch name which can also be used to filter your uploads. The example below uploads all recordings from the main
branch:
export default defineConfig({
e2e: {
setupNodeEvents(cyOn, config) {
const on = wrapOn(cyOn)
replayPlugin(on, config, {
upload: true,
apiKey: process.env.REPLAY_API_KEY,
filter: function (recording) {
return recording.metadata.source.branch === 'main'
},
})
return config
},
},
})
Upload some passing runs
If you've adopted one the configurations above but would also like to periodically upload all replays for a test run, you can add a condition to the filter that returns true
for a given test run id. This is only one possible implementation of this approach and you're welcome to adopt others such as using external environment variables.
const convertStringToInt = (string) =>
string.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
export default defineConfig({
e2e: {
setupNodeEvents(cyOn, config) {
const on = wrapOn(cyOn)
replayPlugin(on, config, {
upload: true,
apiKey: process.env.REPLAY_API_KEY,
filter: function (recording) {
// randomly upload 10% of all test runs
if (convertStringToInt(r.metadata.test.run.id) % 10 === 1) {
return true
}
// upload runtime crashes and any failed tests
return (
recording.status === 'crashed' ||
recording.metadata.test.result === 'failed'
)
},
})
return config
},
},
})
Using GitHub Action
Alternatively, you can upload your replays in a separate step using our GitHub upload action. To filter which replays to upload, you can use JSONata filtering functions.
.github/workflows/e2e.yml
1name: Replay tests2on:3 pull_request:4 push:5 branches: [main]6jobs:7 cypress-run:8 runs-on: ubuntu-22.049 steps:10 - name: Checkout11 uses: actions/checkout@v412 - name: Install dependencies13 run: npm ci14 - name: Install Replay Chromium15 run: npx replayio install16 - name: Run Playwright tests with Replay Browser17 run: npx playwright test --project replay-chromium --reporter=@replayio/playwright/reporter,line18 - name: Upload replays19 if: ${{ always() }}20 uses: replayio/action-upload@v0.5.121 with:22 api-key: ${{ secrets.REPLAY_API_KEY }}23 filter: ${{ 'function($v) { $v.metadata.test.result = "failed" }' }}