skip to content

Your data grid passes every Cypress component test but breaks in the app. Why?

level: seniorimportance: must knowfreq 58%

answer

  1. The engine is real, the page is not
  2. Check what the mount is rendered into
  3. Ancestors create clipping and stacking contexts
  4. Component runs default to a small square
  5. Five hundred by five hundred, not ten-sixty

basics

~20 s

The mount renders into an almost-empty index page, not the real one. Missing ancestors, siblings, real data and the 500x500 default component viewport mean the grid is correct in an environment your application never builds.

solid answer

~40 s

Cypress mounts into `cypress/support/component-index.html` — a near-empty document — so the browser engine is real but the page around the component is not. What is absent breaks things: ancestors whose `overflow`, `transform` or stacking context clip and cover the grid, siblings such as a sticky header competing for the same space, a router and providers the real tree supplies, and fixture data that lacks the nulls and long strings a real payload carries. The one most teams miss is size: component testing defaults to a **500 x 500** viewport against 1000 x 660 for end-to-end, so a responsive grid renders its narrow breakpoint in every test ever written. Reproduce at the real width with `cy.viewport()` first, then look at clipping, composition and data shape.

code

javascript · 11 lines
javascript
import rows from '../fixtures/grid-rows.json'
import { DataGrid } from './DataGrid'

describe('<DataGrid />', () => {
  it('keeps its sticky column visible at the real page width', () => {
    cy.viewport(1440, 900)
    cy.mount(<DataGrid rows={rows} />)

    cy.get('[data-cy=grid-col-name]').should('be.visible')
  })
})

go deeper

for a junior

Be ready to say a component test renders the component on its own page, so anything the real application wraps around it is simply not there during the test.

for a middle

Explain the specific absences — ancestry, siblings, providers, data shape and the default component viewport — rather than saying the test is 'isolated'.

for a senior

Show a diagnosis order: reproduce at the real width, then look for clipping and stacking ancestors, then composition, then data shape. Demonstrate you have chased one of these in production.

for a principal

Own where the gap is covered instead: decide what thin layer of higher-level coverage exists so the mount's blind spot is a stated boundary, not an assumption.

A green component run is evidence about a mount, not about a page. Cypress renders your component in a real browser — which is exactly why the gap surprises people, because the usual explanation ("it was only a fake DOM") does not apply here. The engine is real. The *page around the component* is not. ## What the mount actually renders into Cypress serves `cypress/support/component-index.html` from its dev server and mounts the component into it. That file is essentially an empty document with a mount root and whatever you put in it. Compared with the page your component ships into, it is missing: - **Ancestry.** No app shell, no sidebar, no layout grid — and therefore none of the ancestors whose `overflow`, `contain`, `transform`, `filter` or `position` create the clipping and stacking contexts that break real layouts. - **Siblings.** No sticky header, no modal root, no cookie banner competing for the same z-index. - **Global state.** No router, no theme provider higher in the tree than the one your mount wraps, no feature flags. - **Real data.** Rows come from a fixture, not from the shape your API actually returns. - **Real size.** This is the one people miss most. ## The viewport trap Component testing defaults to a **500 x 500** viewport, where end-to-end testing defaults to 1000 x 660. That default is sensible for a rating widget and actively misleading for a data grid: at 500 pixels wide, a responsive grid renders its narrow-breakpoint layout in every test you ever write. The wide layout — the one your users see, with the sticky first column, the horizontal scroller and the column-overflow menu — is never rendered, never asserted on, and never regressed against. Fixing it is one command: call `cy.viewport()` before the mount, or set `viewportWidth` and `viewportHeight` under the `component` key in your Cypress config. Note that as of Cypress 16 you cannot set `viewportWidth` or `viewportHeight` through `Cypress.config()` during test execution — use `cy.viewport()` or a suite-level test config object instead. ## Reading a "passes in the mount, breaks in the app" failure Work down this list, because the causes are roughly ordered by how often they bite: 1. **Size.** Did every test run at 500 x 500 while the bug reproduces at 1440? Reproduce at the real width first. 2. **Clipping and stacking.** Does an ancestor in the real page set `overflow: hidden`, a `transform`, or a stacking context that traps the toast your component portals? A mount has no such ancestor to trap it. 3. **Composition.** Is the component correct alone and wrong beside a sibling — a sticky header covering the first grid row, two components claiming the same z-index? 4. **Data shape.** Does the real payload carry a null, a very long string, or a missing field the fixture never had? 5. **Server-supplied props.** For a framework page, did the data the component depends on come from server code that a mount never executes? ## What a green component run does and does not license | Claim | Supported by a component run? | | --- | --- | | The component renders its states correctly | yes | | Its callbacks fire with the right payloads | yes | | It is visible and clickable in its own layout | yes | | It survives the real page's ancestors | no | | It works at the widths users actually have | only if you set them | | The page composing it is correct | no | The honest sentence to say in an interview is: *a component test proves the component is correct in the environment the test builds; it says nothing about the environment the application builds.* That is not a criticism of the mount — it is the definition of an isolated test, and the reason the level exists. ## Narrowing the gap without rebuilding the app You cannot close the gap from inside a component spec, but you can narrow it cheaply: - Set the viewports your product actually supports, and mount the wide case as well as the narrow one. - Mount the component **inside a minimal, realistic ancestor** when the ancestor is the risk — a sticky header, a scroll container — rather than bare. - Build fixtures from the real payload shape, including its nulls and its longest strings. - Keep one thin layer of end-to-end coverage over the composed page, so the gap is covered by something rather than assumed away. The last point is the one that turns this from a complaint into a plan: the mount's blind spot is not a defect to fix in the mount, it is a boundary to cover somewhere else.

  • The grid is clipped in the app but not in the Cypress mount. What is the fastest way to reproduce it under the mount?
    Mount the grid inside a minimal version of the ancestor you suspect — a scroll container with the same `overflow`, or a wrapper with the same `transform` — at the width the bug appears at. If the clipping reproduces, the ancestor is the cause and the component itself is fine.
  • How do you set the viewport for a whole Cypress component suite rather than per test?
    Set `viewportWidth` and `viewportHeight` under the `component` key in your Cypress config, or pass a test-configuration object to a `describe` block. As of Cypress 16 you cannot change them with `Cypress.config()` during test execution; use `cy.viewport()` inside a test instead.

saying these in an interview costs you the question

  • Blames a fake DOM when the mount uses a real browser
  • Does not know component runs default to 500x500
  • Treats a green component suite as page-level evidence
  • Ignores ancestors that clip or cover the component
  • Builds fixtures that never contain nulls or long strings