# What Are Cypress Reporters? A Technical Guide to Test Output and Reporting

> Understand Cypress reporters and how they convert test events into readable output and stats. Enhance your test reporting with this technical guide.

- Repository: [Cypress.io/cypress](https://github.com/cypress-io/cypress)
- Tags: deep-dive
- Published: 2026-06-16

---

**Cypress reporters transform raw test execution events into human-readable output, statistics, and external file formats like JUnit XML by bridging Cypress internals with Mocha's reporting infrastructure.**

Cypress reporters form the output subsystem of the cypress-io/cypress testing framework. They handle the translation of internal test events into structured reports, console output, and machine-readable artifacts essential for CI/CD integration. The reporter architecture lives primarily in [`packages/server/lib/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/reporter.ts) and interfaces directly with Mocha's reporter ecosystem to normalize test results.

## How Cypress Reporters Process Test Events

The reporter system acts as a bridge between Cypress's internal event bus and the final output destination. Understanding this pipeline is crucial for customizing test output or debugging reporter issues.

### The Event Translation Pipeline

When Cypress runs tests, the **Reporter** class orchestrates a four-stage event flow:

1. **Instantiation**: The Cypress server creates a `Reporter` instance with the configured reporter name (e.g., `spec`, `junit`, or a custom module).

2. **Mocha Runner Creation**: The `Reporter` class constructs a Mocha test runner using `new Mocha({ reporter })` and wires it to the selected reporter implementation.

3. **Event Translation**: As tests execute, Cypress emits internal events such as `test:before:run`, `pass`, and `fail`. The `Reporter.emit()` method (defined at lines 22-40 in [`packages/server/lib/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/reporter.ts)) translates these into Mocha-compatible event shapes and forwards them via `this.runner.emit`.

4. **Results Finalization**: When the run completes, `Reporter.end()` (lines 68-86) resolves a `ReporterResults` object containing normalized statistics, test records, and hook data.

### Core Implementation in [`packages/server/lib/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/reporter.ts)

The `Reporter` class serves as the central abstraction. Key methods include:

- **`loadReporter()`** (lines 55-79): Resolves reporter modules by checking built-in Cypress reporters, Mocha's built-in reporters, or requiring custom modules from `node_modules` or local paths.
- **`emit()`** and **`parseArgs()`**: Convert Cypress proprietary events into the format expected by Mocha reporters while filtering private properties.
- **`normalizeTest()`** and **`normalizeHook()`** (lines 98-134): Transform Mocha's internal objects into the standardized shapes required by Cypress Cloud and the UI, defined in [`packages/types/src/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/types/src/reporter.ts).

## Built-in, Mocha, and Custom Reporter Types

Cypress supports three distinct categories of reporters, selectable via the `reporter` configuration field or the `--reporter` CLI flag.

### Built-in Cypress Reporters

Cypress ships with three first-party reporters optimized for different environments:

- **`spec`** (default): The standard console output showing nested suites, test titles, and duration.
- **`teamcity`**: Formats output for TeamCity CI integration.
- **`junit`**: Generates JUnit XML files for test result aggregation.

### Third-Party Mocha Reporters

Because Cypress uses Mocha under the hood, any Mocha reporter (such as `dot`, `nyan`, or `json`) works by name. The `loadReporter()` method detects these via the code path `if (mochaReporters[reporterName])` and instantiates them within the Cypress context.

### Custom Reporter Modules

If the specified name matches neither built-in nor Mocha reporters, Cypress attempts to `require()` a local file or npm module. Custom reporters must extend `Mocha.reporters.Base` and handle events like `pass`, `fail`, and `end`.

## Configuring and Loading Cypress Reporters

Reporter selection and configuration occur through multiple interfaces, all processed by the `loadReporter()` method in [`packages/server/lib/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/reporter.ts).

### Configuration File Setup

Specify the reporter and its options in [`cypress.config.js`](https://github.com/cypress-io/cypress/blob/main/cypress.config.js):

```javascript
// cypress.config.js
module.exports = {
  reporter: 'junit',
  reporterOptions: {
    mochaFile: 'cypress/results/[hash].xml',
    toConsole: true,
  },
}

```

When Cypress initializes, the `Reporter` constructor receives `'junit'` as the `reporterName` parameter, and `loadReporter()` resolves it to `require('mocha-junit-reporter')`.

### Command Line Interface

Override config settings using CLI flags:

```bash
cypress run --reporter ./my-reporter.js --reporter-options '{"output":"my-report.json"}'

```

The `loadReporter()` method resolves relative paths against the project root, requiring the module and passing the parsed options to the reporter constructor.

## Creating a Custom Cypress Reporter

Custom reporters extend Mocha's base reporter and integrate with Cypress's event system. Here is a minimal implementation that logs passed and failed tests:

```javascript
// my-reporter.js
const Mocha = require('mocha')

class MyReporter extends Mocha.reporters.Base {
  constructor(runner, options) {
    super(runner)
    
    runner.on('pass', test => {
      console.log(`✅ ${test.fullTitle()}`)
    })
    
    runner.on('fail', (test, err) => {
      console.log(`❌ ${test.fullTitle()} – ${err.message}`)
    })
  }
}

module.exports = MyReporter

```

When invoked via `--reporter ./my-reporter.js`, Cypress instantiates this class inside `Reporter.setRunnables()` and pipes all test events through it.

## Accessing Reporter Results Programmatically

For programmatic test runners, access the finalized results using the `end()` method:

```javascript
const { Reporter } = require('@packages/server/lib/reporter')
const reporter = Reporter.create('spec', {}, process.cwd())

// After emitting all test events...
reporter.end().then(results => {
  console.log('Overall stats:', results.stats)
  console.log('Test list:', results.tests.map(t => t.title))
})

```

The `end()` method returns a promise resolving to a `ReporterResults` object containing:

- **stats**: Summary of suites, tests, passes, failures, and duration.
- **reporter**: The name of the reporter used.
- **reporterStats**: Raw Mocha statistics object.
- **tests**: Array of normalized test records with title, state, error, and attempts.
- **hooks**: Array of normalized hook records.

## Summary

- **Cypress reporters** translate internal test events into consumable output through the `Reporter` class in [`packages/server/lib/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/reporter.ts).
- The **event pipeline** bridges Cypress events with Mocha's reporting system via `emit()` and `normalizeTest()` methods.
- **Three reporter types** are supported: built-in (`spec`, `teamcity`, `junit`), Mocha-native (`dot`, `nyan`), and custom modules extending `Mocha.reporters.Base`.
- **Configuration** occurs via `cypress.config.{js,ts}`, the `--reporter` CLI flag, or the `reporterOptions` object.
- **Programmatic access** to results is available through `Reporter.end()`, which returns a `ReporterResults` object containing stats, tests, and hooks arrays.

## Frequently Asked Questions

### What is the default Cypress reporter?

The **spec** reporter is the default output format. It displays nested test suites, test titles, pass/fail status, and duration in the console. According to the source code in [`packages/server/lib/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/reporter.ts), when no reporter is specified, the system defaults to this built-in implementation.

### How do I configure reporter options in Cypress?

Reporter options are passed via the `reporterOptions` field in [`cypress.config.js`](https://github.com/cypress-io/cypress/blob/main/cypress.config.js) or as a JSON string to the `--reporter-options` CLI flag. The `Reporter.loadReporter()` method parses these options and passes them to the reporter constructor, making them available in the `options` parameter of custom reporter classes.

### Can I use multiple reporters simultaneously in Cypress?

The standard `Reporter` class in [`packages/server/lib/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/server/lib/reporter.ts) instantiates a single reporter per test run. To use multiple reporters, you must either create a custom reporter that composes multiple outputs, or run Cypress multiple times with different `--reporter` flags, as the internal architecture maintains a one-to-one relationship between the `Reporter` instance and the Mocha runner.

### What data is available in the ReporterResults object?

The `ReporterResults` object returned by `Reporter.end()` contains five key properties: **stats** (aggregate counts), **reporter** (name string), **reporterStats** (raw Mocha data), **tests** (normalized array with titles, states, and errors), and **hooks** (hook execution records). These types are defined in [`packages/types/src/reporter.ts`](https://github.com/cypress-io/cypress/blob/main/packages/types/src/reporter.ts) and normalized via `normalizeTest()` and `normalizeHook()` in the server reporter implementation.