skip to content

Cypress has no built-in cy.mount(): how do you make it available to every component spec?

level: juniorimportance: must knowfreq 82%

answer

  1. Some commands you install yourself
  2. Look in the component support file
  3. One adapter package per UI framework
  4. Registered once, not imported per spec
  5. The launchpad scaffolds it for you

basics

~10 s

Cypress ships no cy.mount command. You import mount from a framework adapter - cypress/react, cypress/vue, cypress/angular or cypress/svelte - and register it once with Cypress.Commands.add('mount', mount) in cypress/support/component.js, which loads before every spec.

solid answer

~40 s

Component testing is the one Cypress mode with a command you install yourself. Each framework renders differently, so Cypress publishes one adapter per framework - `cypress/react`, `cypress/vue`, `cypress/angular`, `cypress/svelte` - and each exports a `mount` function. In `cypress/support/component.js` you write `import { mount } from 'cypress/react'` and then `Cypress.Commands.add('mount', mount)`. That file is bundled and evaluated before every component spec, so `cy.mount` is global from then on: a spec for the design system's rating widget just calls `cy.mount(<RatingWidget />)` with no import of its own. Configuring component testing through the Cypress launchpad scaffolds that file with the registration already written. Registering rather than importing `mount` per spec is the documented recommendation, because it also gives you a single place to wrap every component in whatever context the library needs.

code

javascript · 12 lines
javascript
// cypress/support/component.js
import { mount } from 'cypress/svelte'

Cypress.Commands.add('mount', mount)

// cypress/component/Toast.cy.js
import Toast from '../../src/Toast.svelte'

it('renders the design system toast', () => {
  cy.mount(Toast)
  cy.get('[data-cy=toast]').should('be.visible')
})

go deeper

for a junior

Be ready to say plainly that cy.mount is not built in, name the adapter package for your framework, and point at cypress/support/component.js as the file that registers it.

for a middle

Explain why the support file is the right home: it is bundled and evaluated before every component spec, so one Cypress.Commands.add call makes cy.mount global with no per-spec import.

for a senior

Expect to be asked what your registered mount does beyond calling the adapter, and to justify keeping it thin enough that a spec still reveals what the component depends on.

for a principal

Own the standard for a whole library: one registration per Cypress project, what a two-framework monorepo therefore costs, and how you migrate every spec when an adapter's entry point changes.

## Why the runner cannot ship one mount Every Cypress command works against a document. `cy.get()` queries what the browser is showing, `.click()` dispatches a real event into it, `.should()` retries until the DOM agrees. Nothing in that model knows what a *component* is. Turning a `RatingWidget` module into DOM is framework work, and the four supported frameworks do it four different ways: React creates a root and renders into it, Angular boots Angular's `TestBed`, Vue goes through Vue Test Utils, Svelte calls Svelte's own `mount`. Rather than guess, Cypress ships one small adapter per framework and asks you to wire up the one your project uses. | Framework | Import path | Renders through | |---|---|---| | React | `cypress/react` | React's `createRoot` and `root.render` | | Vue | `cypress/vue` | Vue Test Utils' `mount` | | Angular | `cypress/angular` | Angular's `TestBed` | | Svelte | `cypress/svelte` | Svelte's own `mount` | All four export a function named `mount` with the same shape - the component first, an options object second - and all four return a Cypress chain. That sameness is why the registration is a one-liner. ## The registration For component testing, `supportFile` defaults to `cypress/support/component.js`. Cypress compiles and bundles that file and evaluates it before every component spec in the run, which makes it the natural home for anything all of them need: ```js // cypress/support/component.js import { mount } from 'cypress/react' Cypress.Commands.add('mount', mount) ``` `Cypress.Commands.add(name, fn)` attaches `name` to the `cy` object for the rest of the run. From that point a spec for the design system's rating widget is ordinary Cypress: ```jsx import RatingWidget from './RatingWidget' describe('<RatingWidget />', () => { it('reports the star the reviewer picked', () => { cy.mount(<RatingWidget />) cy.get('[data-cy=star-4]').click() cy.get('[data-cy=rating-value]').should('have.text', '4') }) }) ``` Notice what is **not** in that spec: no import of `mount`, no render helper, no teardown. Only the component and the same commands an end-to-end spec would use. ## Register once, or import per spec? Importing `mount` straight into a spec and calling it does work. Registering it is still the documented recommendation, for two reasons: - **No per-spec import.** `cy.mount` is global once the support file has run, so two hundred component specs carry no setup import between them. - **One place to grow.** The registered function is yours. Wrapping every component in the library's theme provider, or defaulting an option, becomes an edit in one file rather than two hundred. ## The TypeScript half `Cypress.Commands.add` is a runtime call, so TypeScript has to be told about the new command separately or `cy.mount` is a type error. The scaffolded TypeScript support file merges the declaration in place: ```ts import { mount } from 'cypress/react' declare global { namespace Cypress { interface Chainable { mount: typeof mount } } } Cypress.Commands.add('mount', mount) ``` Typing it as `typeof mount` rather than a hand-written signature keeps the adapter's own props and options checked, and keeps working when the adapter's signature changes. The same block can live in a `cypress.d.ts` at the project root, as long as your `tsconfig.json` includes it. ## What the launchpad writes for you Configuring component testing through the Cypress app detects the framework, fills in the `component` block of the config file, and scaffolds three things: 1. `cypress/support/component.js` - the registration above, plus an import of the shared commands file. 2. `cypress/support/component-index.html` - the page components are rendered into. 3. The `component` section of `cypress.config.js`, including `devServer`. Most teams therefore never type the registration; they meet it the first time they want to change it. Knowing that `cy.mount` is *just* a custom command is what makes that change unintimidating. ## When the wiring is wrong - **`cy.mount is not a function`** - the registration never ran. Usually it was put in the end-to-end support file, or `supportFile` is set to `false`. - **The adapter import path does not match the framework** - importing `mount` from `cypress/vue` in a React project fails at bundle time, not at assert time. - **As of Cypress 16, the four adapters above are the complete official set.** The separate `cypress/angular-zoneless` entry point was merged into `cypress/angular` in that release and is no longer shipped with the binary, so an Angular project upgraded from an older major must change that import to `cypress/angular`.

  • Can you skip the registration and import mount directly in a spec?
    Yes, and it runs. You lose the two things registration buys: `cy.mount` available in every spec with no import, and a single place to change how every component is mounted. The Cypress docs recommend registering for exactly that reason, and the launchpad scaffolds it that way.
  • What does the TypeScript registration need that the JavaScript one does not?
    A declaration merge. `Cypress.Commands.add` is a runtime call, so the `Chainable` interface has to learn about `mount` separately - `declare global { namespace Cypress { interface Chainable { mount: typeof mount } } }` - in the support file or in a `cypress.d.ts` that your `tsconfig.json` includes.

saying these in an interview costs you the question

  • Says cy.mount is a built-in Cypress command like cy.get
  • Imports mount into every spec instead of registering it once
  • Cannot name which package the framework adapter comes from
  • Puts the registration in the end-to-end support file instead