In a Cypress component test of a Next.js page, why are its props undefined?
answer
- Two halves of a page, only one mounts
- No server means no request lifecycle
- Data functions are Node-side by design
- Hand-written props hide the untested half
- Pages belong in an end-to-end test
basics
~20 sA Cypress mount only constructs and renders the page component. Next.js data functions such as getServerSideProps and getStaticProps run on the server, and nothing in a component test calls them, so their props never arrive.
solid answer
~40 s`cy.mount()` imports the page module into the browser page the Cypress dev server serves, then constructs and renders the component. There is no Next.js server in that picture: no request lifecycle, no route match, and so no call to `getServerSideProps` or `getStaticProps`. Those functions are Node-side by design — they read secrets, open database connections and import server-only modules — so Cypress cannot run them in the browser without reimplementing the Next.js server. The page component is therefore constructed with only what you passed to `cy.mount()`, and every server-supplied prop reads as `undefined`. You can hand-write the props, but that leaves the whole data path untested. The Cypress documentation's recommendation is to component-test individual components and end-to-end-test Next.js pages, where the real data function actually runs.
code
javascript · 10 linesimport DashboardPage from '../../pages/dashboard'
describe('DashboardPage', () => {
it('renders its empty state without server data', () => {
// getServerSideProps never runs here, so `rows` arrives undefined
cy.mount(<DashboardPage />)
cy.get('[data-cy=grid-empty]').should('be.visible')
})
})go deeper
Be ready to say that a mount renders only the component and that Next.js server functions never run under one, so their props are simply absent.
Explain why this cannot be configured away: those functions import server-only modules and depend on a request lifecycle a component dev server does not have.
Recognise the false green — a wall of passing page mounts fed by hand-written fixtures — and be able to say what such a suite has and has not proved.
Set the standard for where the boundary sits: components get mounts, pages get end-to-end coverage, and be ready to defend the extra infrastructure that second half needs.
A Next.js page is two things at once: a React component that renders markup, and a module that exports functions Next.js calls **on the server** to produce that component's props. A Cypress component test only ever gets the first half. ## What a mount does and does not execute `cy.mount()` imports the page module into a browser page served by the Cypress dev server, constructs the component and renders it. That is all. Nothing in the pipeline plays the role Next.js plays in production: there is no server render, no route match, and therefore no call to the page's data functions. - `getServerSideProps` runs on the server on every request. Under a mount, nobody calls it. - `getStaticProps` runs at build time (and on revalidation). Under a mount, nobody calls it. - The `props` those functions would have returned are simply never passed in. So the page component is constructed with whatever you handed `cy.mount()` — usually nothing — and every prop that would have come from the server reads as `undefined`. That is why a page whose job is to render your design system's data grid from server-fetched rows mounts as an empty grid, a spinner that never resolves, or a crash inside a `rows.map(...)` on `undefined`. ## Why this is not a bug you can configure away It is tempting to look for a flag. There isn't one, and there could not sensibly be one: 1. These functions are **Node-side code by design**. They routinely read environment secrets, open database connections and import server-only modules. Running them inside the browser page that hosts your component would either fail on the first Node-only import or require Cypress to reimplement the Next.js server. 2. The component-testing dev server compiles and serves **your component modules**, not a Next.js server. There is no request lifecycle for a data function to hang off. 3. Even if the props arrived by some side channel, the interesting behaviour — redirects, not-found responses, caching, revalidation, error handling on a failed fetch — lives in the data function, and none of it would be exercised. ## The two honest options **Pass the props yourself.** You can mount the page component and supply the shape the server would have returned: - It gets the page rendering, so you can assert on its layout and its use of your components. - It leaves every server-side branch untested, and it silently drifts: when the data function starts returning a new field, the test still passes against the old fixture. **Test the page end-to-end instead.** A Cypress end-to-end test visits the real URL against a running Next.js app, so Next.js executes `getServerSideProps` or serves the `getStaticProps` output exactly as it will in production. This is what the Cypress documentation recommends for Next.js **pages**. | | Component mount of a page | End-to-end test of the page | | --- | --- | --- | | Runs `getServerSideProps` | no | yes | | Runs `getStaticProps` output | no | yes | | Props source | whatever you pass in | the real data path | | Needs a running app | no | yes | | Cost per test | ~1-2 seconds | seconds, plus a server | ## Where the line usually lands The documented recommendation is the one most teams converge on independently: **component-test the components, end-to-end-test the pages**. For a design system that is a comfortable split, because the interesting units are exactly the pieces that carry no server data: - The data grid, given rows as a prop, is a perfect component-test subject — its sorting, empty state, sticky column and keyboard behaviour are all prop-driven. - The toast, the rating widget and every other presentational component are the same. - The page that fetches rows, handles a failed fetch and passes them down is a page, and its interesting half runs on the server. The failure mode to name in an interview is the false green. A team mounts pages, passes hand-written props, sees a wall of passing tests, and believes the pages are covered. They are covered as renderers and untested as data consumers, and the first production incident is usually a data function returning a shape the fixture never had. ## Symptoms to recognise If you inherit a suite that mounts pages, these are the tells: - Assertions written entirely against empty states, because that is what an unfed page renders. - Props objects hand-built inside the spec with no relationship to the data function's return type. - Tests that never fail when the data function changes, because nothing in the spec references it. Any of those means the component test has quietly stopped being evidence about the page and become evidence about the page's markup with a fixture bolted on.
- If you hand-write the props a Cypress mount does not receive, what have you actually covered?The page's rendering, given one hand-chosen shape. Every server-side branch — a failed fetch, a redirect, a not-found, caching or revalidation — stays untested, and the fixture drifts silently: when the data function starts returning a new field, the spec still passes against the old shape.
- Which parts of a Next.js app are still good Cypress component-test subjects?Anything prop-driven. A design system's data grid, rating widget and toast take their data as props, so a mount exercises exactly the behaviour that matters: sorting, empty states, keyboard handling and layout. Reserve end-to-end tests for the pages that fetch the data and pass it down.
saying these in an interview costs you the question
- Believes a config flag can enable server data functions
- Claims Cypress runs getServerSideProps in the browser
- Says mounting pages with fixtures covers the data path
- Confuses build-time and request-time data functions
- Assumes an undefined prop means a broken mount setup