# Reporting from CI with Cypress

> Create the app token the Probara Cypress reporter signs in with, register it in your Cypress configuration and see what it sends.

The **Cypress** app sends your Cypress test results to Probara from any CI pipeline, with the
Probara reporter for Cypress. Each Cypress run becomes an automated test run with its results, the
test cases it names and their attachments.

The reporter signs in with an **app token**: a token that belongs to the organization, not to a
person. It uses no seat, and it keeps working when the person who created it leaves. This guide
covers the card in Probara and the setup; the
[reporter's documentation](https://docs.probara.net/en/developers/ci-integrations/cypress/) covers every
[reporter option](https://docs.probara.net/en/developers/ci-integrations/cypress/configuration/) and test helper.

## Before you start

| You need                                              | Why                                                                                                                         |
| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| A paid plan (**Pro** or **Enterprise**, or any trial) | Reporting from CI is not part of the Free plan. On Free, its dialog shows **See plans** instead of **Create an app token**. |
| A Probara **owner** or **admin**                      | Only owners and admins can create and manage app tokens. Other members see the card without its tokens.                     |
| A Cypress project that runs in CI                     | The reporter runs with your specs, in the same `npx cypress run` command.                                                   |

## Set it up

1. In **Workspace › Integrations**, select the **Cypress** card. The dialog lists what the app can do
   and links to this guide.
2. Open the **Access tokens** tab and select **Create an app token**.
3. Enter a **Token name** and select **Create token**. Name it after what uses it — the repository
   or the pipeline — so you know which one to revoke later.
4. Select **Copy token** in **Copy your new token**. This is the only time Probara shows it: store it
   in your CI as a secret named `PROBARA_API_TOKEN` before you select **Done**.
5. Install the reporter in your Cypress project:

   ```bash
   npm install --save-dev @probara/cypress-reporter
   ```

6. Add it to `cypress.config.js` as the `e2e` reporter and give it the `setupNodeEvents` helper,
   replacing `<PROJECT_CODE>` with your project's Project ID, such as `SHOP`:

   ```js
   // cypress.config.js
   const { defineConfig } = require('cypress');
   const { probaraNodeEvents } = require('@probara/cypress-reporter/setup');

   module.exports = defineConfig({
     e2e: {
       reporter: '@probara/cypress-reporter',
       reporterOptions: { projectId: '<PROJECT_CODE>' },
       setupNodeEvents(on, config) {
         return probaraNodeEvents(on, config);
       },
     },
   });
   ```

7. Import the reporter's support file once, at the top of `cypress/support/e2e.js`, so every spec
   can use its test helpers:

   ```js
   // cypress/support/e2e.js
   import '@probara/cypress-reporter/support';
   ```

8. Pass the secret to your tests as the `PROBARA_API_TOKEN` environment variable and run them. For
   example, in GitHub Actions:

   ```yaml
   - name: Run Cypress tests
     run: npx cypress run
     env:
       PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
   ```

The token never goes in `cypress.config.js`: the reporter reads it from the environment. The card on
the Integrations page shows how many active tokens the app has.

## What the reporter sends

| What                        | How Probara records it                                                                                                                                                                                                                                    |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Results                     | One result per attempt: every Cypress retry of a test sends its own result, in order, and the run case keeps the last outcome. Every attempt stays in the case's history.                                                                                 |
| Skipped tests               | Skipped tests, including a test the spec itself skips with `it.skip`, are recorded as skipped.                                                                                                                                                            |
| Errors                      | The error of a failed attempt, in the notes of its result.                                                                                                                                                                                                |
| Steps                       | The steps an attempt ran with `probara.step()`, as a tree with their status, duration and error, shown under the result.                                                                                                                                  |
| Attachments                 | The files an attempt attached with `probara.attach()`, on its result — or on the step they were attached in — and the screenshot of each failed test the reporter attaches by default.                                                                    |
| Links                       | The links an attempt added with `probara.link()`, shown with the result. The issues it named with `probara.issue()` become links only when the reporter's `issueUrlTemplate` option, a URL with `%s` where the issue id goes, turns their ids into links. |
| Parameters                  | The browser the spec ran in, such as `chrome`, as a parameter of the result. It selects a run case only when the case declares a `browser` parameter; otherwise it is shown with the result only, as context.                                             |
| New test cases              | A test with no case yet creates one, in a suite named after its spec, under the `describe` blocks that wrap it.                                                                                                                                           |
| Existing test cases         | An archived case the test reports to is restored. A case found by its automation key moves to the suite the test is in now; a case linked by its ID keeps its suite. Its title, steps and fields are never changed.                                       |
| Assignees of failed results | With the reporter's `assignFailedTo` option, a failed result is assigned to the people it names, in turn — only when its run case has no assignee yet, and only to members who can work in the project. An existing assignee is never replaced.           |

A field or option Probara does not know, or one deleted while the report runs, is skipped and
answered as a warning, never a failure: the report still records every result. A field with an
empty value is skipped without a warning. An email in `assignFailedTo` that matches no member who
can work in the project is skipped too, with a warning that says only how many were skipped. The
helpers are available inside a `cypress` spec:

```js
it('adds an item to the cart', () => {
  probara.step('open the product page', () => {
    cy.visit('/products/boots');
  });
  probara.attach({ name: 'cart', path: 'reports/cart.json' });
  probara.link('https://shop.example.com/cart', 'Cart page');
});
```

## Same cases as a JUnit import

If you already send Cypress results with `probara import junit` on the report of `cypress-junit`, the
reporter finds the same test cases: for the same suite, its automation keys equal the keys of that
import — the spec's path relative to the project root plus the test's full title. Switching to the
reporter therefore keeps each test linked to its case and its history. One difference is worth
knowing: the reporter sends **every attempt**, while the import keeps only the last one.

## Run only the tests of a run

To run only the tests of a run created in Probara, add the reporter option `runCasesOnly` to the
`reporterOptions` of `cypress.config.js`:

```js
// cypress.config.js
const { defineConfig } = require('cypress');
const { probaraNodeEvents } = require('@probara/cypress-reporter/setup');

module.exports = defineConfig({
  e2e: {
    reporter: '@probara/cypress-reporter',
    reporterOptions: { projectId: '<PROJECT_CODE>', runCasesOnly: true },
    setupNodeEvents(on, config) {
      return probaraNodeEvents(on, config);
    },
  },
});
```

Then, only in the job that runs that run's tests, set `PROBARA_RUN_ULID` to the run's ULID. For
example, in a GitHub Actions workflow you start by hand with a `run_ulid` input:

```yaml
- name: Run the tests of a Probara run
  run: npx cypress run
  env:
    PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
    PROBARA_RUN_ULID: ${{ inputs.run_ulid }}
```

The reporter sends the results into that run and leaves it open.

To get the ULID, open the run, select **Run actions** (the menu in the run's header), and choose
**Copy run ULID**; the same item is in each run's menu in the runs list. The option turns the same
selection on for every spec run: while it reports, each job without a ULID then warns and runs and
reports every test.

Before the specs run, the reporter reads the run's cases. A test belongs to the run when its
automation key is the key of one of the run's cases, or when its title or one of its `describe`
blocks names one of the run's cases, such as `SHOP-12`. A `probara.id()` call does not count: it
runs with the test, after the selection. Reading the case keys is the one read an app token can
make.

A test the run does not include is skipped: it does not run, and it is not reported. Its spec file
is still loaded, so the file's top-level code runs. When the support file is missing from
`cypress/support/e2e.js`, the reporter cannot skip tests: every test runs and is reported, with one
warning. The [run selection reference](https://docs.probara.net/en/developers/ci-integrations/cypress/run-selection/)
covers the matching rules and every fallback.

To report several jobs into one run, create it first with `probara run create`, pass its ULID to
every job in `PROBARA_RUN_ULID`, and close it at the end with `probara run close`. In GitHub Actions
the jobs of one workflow run already share a run: the parallel jobs set `PROBARA_CLOSE_RUN: false`,
and a final job runs `probara run close`
([parallel jobs](https://docs.probara.net/en/developers/ci-integrations/cypress/ci-providers/#parallel-jobs-one-run-closed-by-the-final-job)).
The
[CLI](https://docs.probara.net/en/developers/cli/) can also send back the results a reporter kept when a report could not be
sent, with `probara import results`.

## Manage tokens

Under **App tokens**, the **Access tokens** tab lists each active token with who created it (or
**Created by a removed user**), when, and when it was last used (**Never** until its first report).

**Revoke** a token, and confirm, when it may have leaked or when someone who could read it leaves
your team: pipelines that use it stop reporting at once, and it cannot be undone. Create a new token
for them first. Because an app token outlives the person who created it, rotating it is your call:
Probara never revokes it on its own.

## What an app token can do

Only what the reporter does: create automated runs, send reports (which can create the test cases
and suites they name), add attachments to their results, close runs, and read the case keys of a
run. It cannot read anything else, cannot remove attachments, and cannot be used with
[Probara MCP](https://docs.probara.net/en/developers/mcp/) or for any other API call. For scripts and other API clients, use
a personal [API token](https://docs.probara.net/en/developers/authentication/).

Runs, activity entries and attachments that an app token created show the app's logo and name beside
the token name — for example **Cypress · smoke-ci** — in the runs list, the run and milestone
summaries, [Workspace activity](https://docs.probara.net/en/guides/workspace/activity/) and the attachments list.

## When the plan changes

If your organization moves to the Free plan, its app tokens are kept but Probara refuses them, so
pipelines stop reporting; its dialog says so and offers **See plans**. You can still see and revoke the
tokens. They work again as soon as the organization is back on a paid plan, with nothing to set up
again. Manual test runs are not affected.

## Next step

- [Reporter documentation](https://docs.probara.net/en/developers/ci-integrations/cypress/) —
  [options](https://docs.probara.net/en/developers/ci-integrations/cypress/configuration/),
  [test helpers](https://docs.probara.net/en/developers/ci-integrations/cypress/metadata/), steps and screenshots, and
  [run selection](https://docs.probara.net/en/developers/ci-integrations/cypress/run-selection/).
- [CI integrations](https://docs.probara.net/en/developers/ci-integrations/) — how the Cypress reporter compares with the
  [CLI](https://docs.probara.net/en/developers/cli/), the [Playwright](https://docs.probara.net/en/guides/integrations/playwright/) and the
  [Jest](https://docs.probara.net/en/guides/integrations/jest/) reporters.
- [Run cases API](https://docs.probara.net/en/developers/api/run-cases/#list-a-runs-case-keys) — the case keys the reporter
  reads to run only a run's tests.
- [Reports API](https://docs.probara.net/en/developers/api-reference/#reports) — the endpoint the reporter calls, for
  your own tools.
