The Issue
If you are testing a Next.js (or React) app with Cypress and have come across the following React hydration error:
Console Error
A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
- A server/client branch `if (typeof window !== 'undefined')`.
- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
- Date formatting in a user's locale which doesn't match the server.
- External changing data without sending a snapshot of it along with the HTML.
- Invalid HTML tag nesting.
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
See more info here: https://nextjs.org/docs/messages/react-hydration-error
...
<html
lang="en"
data-scroll-behavior="smooth"
data-theme="dark"
- style={{scroll-behavior:"auto"}}
It may well be caused by Cypress manipulating the page during the actionability checks.
When using commands like .click()
, .type()
, or .clear()
these trigger a series of actionability checks to simulate real user behavior, for example, scrolling the element into view and verifying visibility.
The issue is that before scrolling if the website under test uses smooth scrolling to avoid unwanted issues Cypress temporarily overrides it with scroll-behavior: "auto"
, then resets it afterward. This can cause hydration errors if the DOM is altered before React finishes hydrating, as it leads to a mismatch between the server-rendered HTML and the client state.
Suggested Workaround
This scrolling behaviour can be disabled using the scrollBehavior configuration option. Just remember you may need to add an extra step to scroll to the element.
For example, if you're testing a 'Back to Top' button instead of doing this:
cy.get("footer button").click();
Use this alternative method:
cy.get("footer")
.scrollIntoView()
.get("footer button")
.click({ scrollBehavior: false });
Or this:
cy.scrollTo("bottom")
.get("footer button")
.click({ scrollBehavior: false });
Tip! You can also set this globally using Cypress.config('scrollBehavior', false) or by adding the scrollBehavior: false setting to your cypress.config.js.