Skip to content

Early Adopter Offer:Get 40% off Core & Scale for your first year with code EARLYQFView pricing

Cypress test reporting

Keep HTML for reading a run, JSON for tools and JUnit XML for CI integrations. When you need shared results, Qualflare adds hosted, historical reporting alongside those files. The native Cypress reporter captures screenshots, command steps and per-attempt retry history; XML and Mochawesome remain options when you only need the evidence those files contain.

How to generate a Cypress report

Cypress runs on Mocha, so a “Cypress report” is just a Mocha reporter writing your run’s results somewhere — the terminal, an HTML page, or a structured file. Start with the output you need:

  • Built-in spec reporter (default). npx cypress run prints a per-spec summary. Your CI can retain that output in its job logs.
  • Mochawesome (JSON and HTML). Keep a separate JSON file for each spec, then merge them and generate an HTML report:
# 1. Install the reporter and its HTML generator
npm i -D mochawesome mochawesome-merge mochawesome-report-generator

# 2. Write distinct per-spec JSON files to the directory we will merge
npx cypress run --reporter mochawesome \
  --reporter-options "reportDir=cypress/results,overwrite=false,html=false,json=true"

# 3. Merge the per-spec JSON, then build one HTML report
npx mochawesome-merge "cypress/results/*.json" > cypress-results.json
npx marge cypress-results.json --reportDir mochawesome-report --reportFilename index
# Open mochawesome-report/index.html

Start with an empty cypress/results directory, or archive its previous files first: overwrite=false preserves specs but also leaves older runs available to the merge. Run the merge and HTML-generation steps even when tests fail, provided fresh JSON was written. These options follow Cypress’s reporter guide.

  • JUnit XML (for CI & dashboards). Cypress bundles the JUnit reporter — no install. It emits machine-readable XML that CI systems and reporting tools parse:
# Cypress bundles the JUnit reporter — no extra install
# Start with an empty results directory; archive previous XML first
npx cypress run \
  --reporter junit \
  --reporter-options "mochaFile=results/cypress-[hash].xml"

Rule of thumb: reach for mochawesome when a human reads the report and JUnit for CI integrations. Keep either as a local file or a CI artifact. Retention depends on where you save it.

Keep local reports. Add shared history when you need it.

An individual file describes a run. A shared reporting service can keep those runs together so you can compare failures, durations and later outcomes without searching separate job artifacts. You can keep your local reports and existing CI integrations while evaluating that workflow.

Three Cypress reporting choices: native JSON with retries, steps and images; Mochawesome per-spec JSON merged for JSON and HTML reports; or JUnit XML for CI. For an optional Qualflare upload, gather the chosen route’s files from one run and collect once into one launch.
Choose one collection route for the same tests to avoid duplicate results. With @qualflare/cypress, retries must be enabled to capture retry history; steps and available screenshots come from the final attempt. For Mochawesome, upload the merged JSON, not the generated HTML. XML and JSON imports retain only supported evidence present in those files. For parallel jobs, gather that run’s reports and attachments before one collect command; native jobs need a shared run ID and distinct shard indexes. CLI login and setup follow below.

Send Cypress results to Qualflare

1. Install qf and save a project login

Start with a Qualflare project, a project access token with upload permission and an existing environment’s Identifier. Replace staging below with that Identifier, not the environment’s display name. Install qf separately:

# qf is installed separately from your project's Cypress dependencies
npm install -g @qualflare/cli

# Enter your project access token at the hidden prompt
qf login my-project

my-project is a saved local login alias; the token selects the project. See CLI installation and authentication.

2. Choose the native reporter or an existing report

Install the native reporter as a dev dependency:

npm install --save-dev @qualflare/cypress

Register it in two places — the plugin in setupNodeEvents, and the support file so in-test hooks are active. Add these to your existing configuration and support file; keep your application settings and other event hooks:

// cypress.config.ts
import { defineConfig } from 'cypress';
import { qualflareCypress } from '@qualflare/cypress/plugin';

export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      return qualflareCypress(on, config, { environment: 'staging' });
    },
  },
});

// cypress/support/e2e.ts
import '@qualflare/cypress';

Then run Cypress as usual. The reporter writes files without uploading them; qf performs the upload. Run collect even after failed tests when a fresh report exists:

npx cypress run                        # writes ./qualflare-results
qf my-project collect ./qualflare-results --environment staging

Requires Cypress 12 or later and qf 0.1.24 or later for attachments. Use a Node.js version supported by your Cypress release. Screenshots upload by default. For video, enable recording in Cypress and add --upload-artifacts video to collect; the reporter attaches videos of failing specs by default, subject to its size limit.

Without the reporter: XML or mochawesome

For results, durations and available errors, use the bundled JUnit reporter without adding a native plugin. It does not provide the native screenshot/command-step workflow or full attempt history. The [hash] placeholder keeps distinct spec reports:

# Cypress bundles the JUnit reporter — no extra install
# Start with an empty results directory; archive previous XML first
npx cypress run \
  --reporter junit \
  --reporter-options "mochaFile=results/cypress-[hash].xml"

Start each XML run with an empty results directory, or archive the previous XML first. The glob below collects every matching file, including stale reports if you leave them there. After Cypress writes fresh XML, one command uploads every spec:

# Upload every spec's results (globs are supported)
qf my-project collect "results/cypress-*.xml" --format junit --environment staging

Already on mochawesome? Upload the merged JSON from the first example:

# Upload the merged JSON generated above
qf my-project collect cypress-results.json --format cypress --environment staging

For the native route, add the steps below to an existing GitHub Actions job after checkout, Node setup, dependency installation and starting the application under test. Commit the native reporter dependency and configuration first. Save the project token as the QF_TOKEN Actions secret. The same upload pattern works in other CI systems; see the CLI docs.

# Steps in your existing Cypress job, after checkout, Node setup,
# npm ci and making the application under test ready
- name: Prepare a fresh reporter directory
  run: |
    node -e "require('node:fs').rmSync('qualflare-results', { recursive: true, force: true })"

- name: Run Cypress
  env:
    QUALFLARE_RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }}
  run: npx cypress run

- name: Upload results to Qualflare
  if: ${{ !cancelled() && hashFiles('qualflare-results/*.json') != '' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}
  env:
    QF_TOKEN: ${{ secrets.QF_TOKEN }}
    QF_BRANCH: ${{ github.head_ref || github.ref_name }}
    QF_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
  run: |
    npm install -g @qualflare/cli
    qf login ci --force
    qf ci collect ./qualflare-results --environment staging

The upload runs after failed tests only when a fresh report exists, and skips cancellations and fork pull requests. Keep the test step’s failure status: a successful upload must not turn a failed job green. The CI login alias is ci; branch and commit refer to the pull request’s head. Repository secrets are unavailable to fork pull requests and may be restricted for other events. Use these authenticated steps only in a workflow trusted to receive the project token.

XML alternative. Keep your existing Cypress setup; replace the three steps above with these. The example owns the results directory and clears it before testing; choose a dedicated path if that directory holds other files. It needs no native reporter:

# XML alternative: replace the prepare, test and upload steps above
- name: Prepare a fresh XML directory
  run: |
    node -e "require('node:fs').rmSync('results', { recursive: true, force: true })"

- name: Run Cypress with JUnit XML
  run: npx cypress run --reporter junit --reporter-options "mochaFile=results/cypress-[hash].xml"

- name: Upload XML to Qualflare
  if: ${{ !cancelled() && hashFiles('results/cypress-*.xml') != '' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}
  env:
    QF_TOKEN: ${{ secrets.QF_TOKEN }}
    QF_BRANCH: ${{ github.head_ref || github.ref_name }}
    QF_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
  run: |
    npm install -g @qualflare/cli
    qf login ci --force
    qf ci collect "results/cypress-*.xml" --format junit --environment staging

Gather parallel jobs, then upload once

Per-spec reports and CI-machine shards are different. For separate jobs, save each job’s reports and attachments as a distinct CI artifact, download them into one results directory, then authenticate and run collect once in a final job. Separate collect calls create separate launches; uploading from every machine does not join them automatically.

Native reports must share a run ID for that workflow attempt. Assign each matrix job a distinct, zero-based shard index; Cypress does not provide one to the reporter. Use the same run ID across all jobs, and rerun all shards together rather than mixing earlier attempts:

# Environment on each native-reporter test job in your CI matrix
# No explicit runId/shardIndex option should override these values
env:
  QUALFLARE_RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }}
  QUALFLARE_SHARD_INDEX: ${{ matrix.shard }}

# In ONE final job, after downloading all reports and attachments:
# npm install -g @qualflare/cli
# qf login ci --force   (with QF_TOKEN from your CI secret)
# qf ci collect ./qualflare-results --environment staging

Keep the JSON files directly in the gathered directory and preserve attachment paths. The CLI selects only the newest native run ID by default. Follow the existing gather-and-upload guide for artifact transfer and failure-safe final jobs.

For XML, keep every job’s filenames distinct and collect all files in one command. --shard assigns an index per input file, starting at zero; a per-spec XML glob is not a reliable mapping of CI machines. Use explicit file order only when each file represents a complete shard. See run selection and shard numbering.

Know which retry evidence your report retains

Enable test retries in your existing Cypress configuration if you want retry evidence:

// Add to your existing defineConfig(...) options
// Keep the reporter and setupNodeEvents configuration above
  retries: { runMode: 2, openMode: 0 },
Upload routeEvidence available
Native reporterEach attempt’s status, duration and error. Command steps, metadata and attachments come from the final attempt.
Mochawesome JSONResults and final errors. qf derives retry count from attempts or _retries when present; it does not import those attempts as full native error history.
JUnit XMLResults, durations, errors and available captured output. Retry count depends on supported testcase properties in the XML, not simply on retries being enabled in Cypress.

A final pass after recorded retries is evidence of a flaky outcome in that launch. It is not a root-cause diagnosis. Historical case classification uses multiple launches and configured thresholds; it is separate from retry counts. See supported input formats and flaky-test analytics.

What you get on top of Cypress

  • Failure clustering. Related failures can be grouped for investigation when clustering is enabled and its plan and evidence requirements are met. Treat a cluster’s explanation as a lead to check against the failures, not proof of their cause.
  • Every retry attempt, with its own error. Cypress has built-in test retries, and the reporter records each attempt's status, duration and error rather than only the one the run ended on — so a test that passed on its third try is visibly flaky in that launch, not just across weeks of history. Steps, labels and attachments come from the final attempt.
  • Parallel-run aggregation. Gather the jobs’ files and collect once to review the suite in one launch.
  • Launch analysis. Eligible uploads can receive a pass-rate-based risk badge, summary and recommendations. This supports investigation; it is not a release-safety verdict.
  • History, trends & defects. Pass rate, slowest specs, and flakiness over time across branches — plus a defect you can open straight from a failing run.

AI analysis requires project AI enabled, an active subscription and available analysis allowance. Starter includes 50 report uploads and 10 AI report analyses per month, counted separately. Uploaded results remain available if analysis is skipped. Clustering runs separately, so a new pattern may not have a named cluster when launch analysis finishes. Check analysis states and limits.

How it compares to Cypress Cloud

Cypress Cloud provides Cypress-native Test Replay, recording, orchestration and flaky-test features, subject to recording and plan requirements. If those capabilities are your priority, evaluate that workflow directly. Qualflare is a cross-framework alternative: it ingests Cypress alongside Playwright, pytest, Jest, JUnit and other supported formats for shared results and history. It does not replace Cypress Cloud’s test orchestration or Test Replay. Compare the evidence each route retains and the plan allowances your team needs.

Review your own Cypress results

Choose a reporting route, save a project login, upload your results and open the launch. Compare its results with your source report; use later runs to evaluate history. AI analysis depends on your project settings and workspace allowance.

Get Started Free

More reporting guides, with their own setup and evidence details: Playwright, pytest, Jest, JUnit and 20+ more frameworks. Testing a mobile app too? See our Android (Espresso), iOS (XCTest), and Maestro guides. Weighing tools? See how it compares to other test management platforms, or browse all framework reporting guides. Fighting intermittent specs? Read our guide to detecting and fixing flaky Cypress tests.

Frequently asked questions

How do I generate a Cypress report?

Use the default spec reporter for terminal output, Mochawesome for JSON and HTML, or the bundled JUnit reporter for XML. For Mochawesome, configure reportDir=cypress/results, overwrite=false, html=false and json=true before running Cypress; merge the per-spec JSON with mochawesome-merge and generate HTML with marge. Use a fresh results directory or archive previous files before each run. For XML, use npx cypress run --reporter junit with a mochaFile path containing [hash] to keep distinct spec reports.

How do I send Cypress results to Qualflare?

Install qf separately, then save a project login with qf login my-project. Install @qualflare/cypress, register its plugin and support file, and configure your environment Identifier. Run npx cypress run, then qf my-project collect ./qualflare-results --environment staging, replacing staging with your Identifier. my-project is a saved login alias. The reporter writes files without uploading them; qf uploads them. Alternatively, collect JUnit XML with --format junit or merged Mochawesome JSON with --format cypress. Set branch and commit on the CI upload. AI analysis depends on project settings, an active subscription and the separate analysis allowance.

JUnit XML or JSON — which should I use?

JUnit XML needs no extra reporting plugin; collect it with --format junit. If you already use Mochawesome, collect its merged JSON with --format cypress. Retry evidence depends on what the file contains: the Cypress parser reads attempts or _retries, while the JUnit parser reads supported retry properties. Neither can recover omitted attempts or provide the native reporter’s full per-attempt error history. Choose @qualflare/cypress when you need that history, command steps and attachments.

Do I need the reporter, or is JUnit XML enough?

JUnit XML is enough for results, durations and available errors or captured output. The native @qualflare/cypress reporter adds each attempt’s status, duration and error, command steps, screenshots and metadata. Steps, labels, tags and attachments come from the final attempt. It requires Cypress 12 or later and qf 0.1.24 or later for attachments. Screenshots upload by default; video recording must be enabled in Cypress, and video upload requires --upload-artifacts video. Keep local HTML or XML alongside either upload route.

Does Qualflare detect flaky Cypress tests?

Enable Cypress retries, for example retries: { runMode: 2, openMode: 0 }. With the native reporter, a test that fails and then passes on retry is marked flaky in that launch. Imported XML or Mochawesome JSON must contain retry fields that qf supports. Historical case classification is a separate calculation that needs multiple launches and the project’s configured evidence thresholds; one retry does not establish a historical score or a root cause.

Does it work with Cypress parallelization and CI?

Yes. Save every job’s results as a distinct artifact, gather all reports and attachments in a final job, authenticate there and run collect once. Separate collect calls create separate launches. Native reports from the same workflow attempt should share QUALFLARE_RUN_ID and use a distinct QUALFLARE_SHARD_INDEX per job. For XML, preserve distinct filenames and collect all files together; --shard assigns indexes by input file, not by the machine that originally wrote a spec report.

How is this different from Cypress Cloud?

Cypress Cloud provides Cypress-specific recording, Test Replay, orchestration and flaky-test features; check its recording and plan requirements. Qualflare accepts Cypress alongside other supported frameworks for shared results and history. It does not replace Cypress Cloud’s test orchestration or Test Replay. Qualflare’s free Starter plan has separate upload and analysis allowances, and failure clustering has its own eligibility requirements. Compare the evidence and workflow you need, not just the number of supported frameworks.

Recent updates

All updates on the Qualflare changelog

Setup reflects the Qualflare CLI (docs.qualflare.com) and Cypress’s reporter documentation, checked November 2026. Written by İbrahim Süren, Qualflare.