skip to content

Why does a Cypress component spec matched by `e2e.specPattern` vanish from the component run?

level: seniorimportance: nice to knowfreq 30%

answer

  1. Two patterns over one project tree
  2. The defaults deliberately overlap
  3. One run subtracts the other's pattern
  4. The subtraction runs one way only
  5. Broadening e2e hides component specs

basics

~20 s

Cypress folds the e2e block's specPattern into the ignore list for a component run, so any file the e2e pattern claims is dropped from component discovery. Widening e2e.specPattern therefore hides component specs, with no error naming the cause.

solid answer

~40 s

The two testing types have deliberately overlapping defaults: `e2e.specPattern` is `cypress/e2e/**/*.cy.{js,jsx,ts,tsx}` while `component.specPattern` is `**/*.cy.{js,jsx,ts,tsx}` — project-wide, because component specs live beside their components. Without help, every e2e spec would also be discovered as a component spec, so Cypress resolves a component run with `e2e.specPattern` added as an extra ignore pattern. The subtraction is **one-directional**: an e2e run never excludes files matching `component.specPattern`. The failure mode is quiet. Widen `e2e.specPattern` to something like `src/**/*.cy.tsx` and the component specs under `src/` stop appearing, with no error and no warning — the component run simply reports fewer specs, or none. Diagnose it by putting the two patterns side by side and asking which files both claim, and prevent it by keeping the two namespaces disjoint — separate directories, or separate suffixes such as `*.e2e.cy.ts` against `*.ct.cy.tsx`.

go deeper

for a junior

Know that Cypress discovers specs by a glob and that e2e and component runs use different ones. The interaction between the two patterns is not expected at this level.

for a middle

Explain why the defaults overlap — component specs live beside components, so their pattern spans the project — and what Cypress does about it during a component run.

for a senior

An interviewer wants the diagnosis of a suite that silently shrank: comparing the two patterns, recognising that the failure is by omission, and knowing that no error names the cause.

for a principal

The judgement to own is how a repository keeps e2e and component spec namespaces separable by convention, so that no future edit to one pattern can quietly delete coverage from the other.

## Two spec patterns over one project tree A Cypress project discovers specs from a **per-testing-type** `specPattern`, and the two defaults deliberately overlap: | Testing type | Default `specPattern` | Shape | |---|---|---| | e2e | `cypress/e2e/**/*.cy.{js,jsx,ts,tsx}` | one directory | | component | `**/*.cy.{js,jsx,ts,tsx}` | the whole project | The component default has to be project-wide, because component specs are conventionally kept beside the components they render, anywhere under `src/`. But that pattern also matches every e2e spec under `cypress/e2e`. Left alone, an admin console's tenant-settings e2e specs would be discovered as component specs and fail on the first `cy.visit()`. ## The subtraction, and its direction Cypress resolves this by folding the `e2e` block's `specPattern` into the **ignore list of a component run**. Any file the e2e pattern claims is removed from component discovery. That is a real resolution step, not a convention. The important property is that it is **one-directional**: - a component run excludes everything matching `e2e.specPattern`; - an e2e run does **not** exclude anything matching `component.specPattern`. So a file claimed by both patterns runs as an e2e spec and is invisible to component testing. With the defaults that is exactly what you want. Once someone edits `e2e.specPattern`, it stops being what anyone wants. ## The failure mode The sequence that produces the bug on a real suite: 1. A team keeps the admin console's e2e specs in `cypress/e2e/tenants/` and its component specs in `src/**/*.cy.tsx`. 2. Someone decides a few e2e specs belong nearer the code they exercise and widens `e2e.specPattern` to include `src/**/*.cy.tsx`, or reaches for a broad pattern such as `**/*.cy.{ts,tsx}` to catch specs in both places. 3. Every component spec under `src/` now matches `e2e.specPattern` and is subtracted from the component run. 4. `cypress run --component` reports a shrunken spec list — or none found at all — with **no error and no warning naming the cause**. The specs still exist, still compile, and still open fine in an editor. Nothing in the output points at `e2e.specPattern`, because from the component run's point of view those files were simply never candidates. ## Diagnosing and preventing it - **Put the two patterns side by side** and ask which files both claim. That single comparison is the whole diagnosis; the answer is always the set of missing specs. - **Keep the namespaces disjoint.** Either separate directories (`cypress/e2e/` versus `src/`), or separate suffixes (`*.e2e.cy.ts` versus `*.ct.cy.tsx`) so the two patterns can never claim the same file however either is edited. - **Do not reach for `excludeSpecPattern` first.** That key is your own explicit ignore list per testing type — `*.hot-update.js` by default for e2e, snapshot directories for component. The e2e subtraction is applied on top of it, so a spec can vanish for a reason your `excludeSpecPattern` does not mention, and adding entries there will not bring it back. - **Change one pattern at a time**, and check both spec lists after each change rather than only the one you were editing. ## The other ignore list, and how the two combine It helps to hold both filters in mind at once, because they arrive from different places and only one of them is yours: | Filter | Where it comes from | Applies to | |---|---|---| | `excludeSpecPattern` | you, per testing type — `*.hot-update.js` for e2e, snapshot directories for component | that testing type | | `e2e.specPattern` as an ignore | Cypress, automatically | a component run only | A component run therefore discovers `component.specPattern`, minus `component.excludeSpecPattern`, minus everything matching `e2e.specPattern`. Only the middle term appears anywhere you wrote it, which is why the missing specs look inexplicable: you can read your own configuration end to end and see nothing that excludes them. ## Why it is worth knowing This is a small mechanic with an outsized cost, because it fails by *omission*. A suite that silently stops running twenty component specs is green, fast, and wrong, and it stays that way until someone notices coverage moving in the wrong direction. Any configuration whose effect is "some tests no longer exist" deserves the same suspicion: check the count, not just the colour.

  • Does `component.specPattern` get excluded from a Cypress e2e run as well?
    No, the exclusion runs in one direction only. An e2e run discovers specs from `e2e.specPattern` minus `e2e.excludeSpecPattern`, with no reference to the component block. A file claimed by both patterns therefore runs as an e2e spec and is skipped by component testing, never the reverse.
  • What is `excludeSpecPattern` for, then?
    It is the explicit ignore list you control, declared per testing type — `*.hot-update.js` by default for e2e, and snapshot directories for component. The automatic e2e subtraction is applied on top of it during a component run, which is why a spec can disappear for a reason your own `excludeSpecPattern` never mentions.

saying these in an interview costs you the question

  • Assumes the two spec patterns are independent
  • Says Cypress warns when a spec matches both
  • Thinks excludeSpecPattern is the only ignore list
  • Expects the exclusion to work in both directions