-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test(ssr): Validate state synchronization between server and client in React 18 using Zustand (#903) #2088
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 24da89c:
|
Can anyone review this PR please? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some ideas to make it work on react versions under 18
tests/ssr.test.tsx
Outdated
import React, { useEffect } from 'react' | ||
import { act, screen } from '@testing-library/react' | ||
import { hydrateRoot } from 'react-dom/client' | ||
import { renderToString } from 'react-dom/server' | ||
import { describe, expect, it } from 'vitest' | ||
import { create } from 'zustand' | ||
|
||
const IS_REACT_18 = React.version.startsWith('18') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can skip any react version under 18
import React, { useEffect } from 'react' | |
import { act, screen } from '@testing-library/react' | |
import { hydrateRoot } from 'react-dom/client' | |
import { renderToString } from 'react-dom/server' | |
import { describe, expect, it } from 'vitest' | |
import { create } from 'zustand' | |
const IS_REACT_18 = React.version.startsWith('18') | |
import React, { useEffect } from 'react' | |
if (!React.version.startsWith('18')) { | |
describe.skip('skipping test on react version < 18', () => {}) | |
return | |
} | |
import { act, screen } from '@testing-library/react' | |
import { hydrateRoot } from 'react-dom/client' | |
import { renderToString } from 'react-dom/server' | |
import { describe, expect, it } from 'vitest' | |
import { create } from 'zustand' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, thank you for your review.
I understand your intention.
I resolved it by using the only method from vitest and dynamic import.
What do you think about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NaamuKim that approach doesn't work you should completely avoid execute the next lines. Let's try with my suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dbritto-dev There's an issue with top-level returns not being allowed in ESM, causing errors.
I think your suggestion of using describe.skip is excellent, and I've configured it to conditionally branch describe based on the version.
Could you please confirm this?
tests/ssr.test.tsx
Outdated
if (!IS_REACT_18) { | ||
it('Dummy test for React 17, ignore', () => {}) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can omit this statement
if (!IS_REACT_18) { | |
it('Dummy test for React 17, ignore', () => {}) | |
return | |
} |
@dai-shi would you mind triggering the tests again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor tweaks
tests/ssr.test.tsx
Outdated
// Using dynamic import for 'react-dom/client' as it’s not accessible in React versions below 18. | ||
// eslint-disable-next-line import/no-unresolved | ||
const { hydrateRoot } = await require('react-dom/client') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to the top and use vi.importActual
instead of require
// Using dynamic import for 'react-dom/client' as it’s not accessible in React versions below 18. | |
// eslint-disable-next-line import/no-unresolved | |
const { hydrateRoot } = await require('react-dom/client') |
tests/ssr.test.tsx
Outdated
const describeTest = React.version.startsWith('18') ? describe : describe.skip | ||
|
||
describeTest('ssr behavior with react 18', () => { | ||
interface BearStoreState { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interface BearStoreState { | |
const { hydrateRoot } = await vi.importActual('react-dom/client') | |
interface BearStoreState { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to use it like this, but if I change it to "skipIf" and it runs, it throws an error because it doesn't actually skip the context.
describe.skipIf(!React.version.startsWith('18'))(
'ssr behavior with react 18',
async () => {
const {
hydrateRoot,
}: {
hydrateRoot: (
container: Element | Document,
initialChildren: React.ReactNode
) => void
} = await vi.importActual('react-dom/client')
throw error with a message Error: Failed to load url react-dom/client (resolved id: react-dom/client). Does the file exist?
If I move the other context inside the it context, it resolves the issue.
I've applied the changes with it.
Please take a look and feel free to share any further suggestions or improvements
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I mean to the top of the context
tests/ssr.test.tsx
Outdated
import React, { useEffect } from 'react' | ||
import { act, screen } from '@testing-library/react' | ||
import { renderToString } from 'react-dom/server' | ||
import { describe, expect, it } from 'vitest' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add vi on imports
import { describe, expect, it } from 'vitest' | |
import { describe, expect, it, vi } from 'vitest' |
tests/ssr.test.tsx
Outdated
const describeTest = React.version.startsWith('18') ? describe : describe.skip | ||
|
||
describeTest('ssr behavior with react 18', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use describe.skipIf
const describeTest = React.version.startsWith('18') ? describe : describe.skip | |
describeTest('ssr behavior with react 18', () => { | |
describe.skipIf(!React.version.startsWith('18'))('ssr behavior with react 18', () => { |
tests/ssr.test.tsx
Outdated
const { | ||
hydrateRoot, | ||
}: { | ||
hydrateRoot: ( | ||
container: Element | Document, | ||
initialChildren: React.ReactNode | ||
) => void | ||
} = await vi.importActual('react-dom/client') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const { | |
hydrateRoot, | |
}: { | |
hydrateRoot: ( | |
container: Element | Document, | |
initialChildren: React.ReactNode | |
) => void | |
} = await vi.importActual('react-dom/client') | |
const { hydrateRoot } = await vi.importActual<typeof import('react-dom/client')>('react-dom/client') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the suggestion. I've made the requested changes as you suggested.
…n React 18 using Zustand (pmndrs#903)
…pe for 'hydrateRoot'
f20877e
to
d2bfd2a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution!
return <div>bears: {bears}</div> | ||
} | ||
|
||
describe.skipIf(!React.version.startsWith('18'))( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I didn't know about skipIf
!
We should use it in jotai
too:
https://github.com/pmndrs/jotai/blob/d6afb777705eb3a90385817fd6db30db101f6caa/tests/react/transition.test.tsx#L12C1-L16
Free free to open a PR there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am also glad to have learned about skipIf, and I will apply refactoring accordingly in Jotai as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we are good to merge the changes :D. BTW, good job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for your review.
I'm delighted to learn about the useful functions of vitest. I'll continue to check if there are any opportunities for further contributions.
[](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [zustand](https://togithub.com/pmndrs/zustand) | [`4.4.1` -> `4.4.6`](https://renovatebot.com/diffs/npm/zustand/4.4.1/4.4.6) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>pmndrs/zustand (zustand)</summary> ### [`v4.4.6`](https://togithub.com/pmndrs/zustand/releases/tag/v4.4.6) [Compare Source](https://togithub.com/pmndrs/zustand/compare/v4.4.5...v4.4.6) v4.4.5 has an issue with some TypeScript configs about module resolution. It should be fixed now. Thanks for the patience. #### What's Changed - Update export types by [@​dbritto-dev](https://togithub.com/dbritto-dev) in [https://github.com/pmndrs/zustand/pull/2170](https://togithub.com/pmndrs/zustand/pull/2170) #### New Contributors - [@​cheatkey](https://togithub.com/cheatkey) made their first contribution in [https://github.com/pmndrs/zustand/pull/2147](https://togithub.com/pmndrs/zustand/pull/2147) - [@​frixaco](https://togithub.com/frixaco) made their first contribution in [https://github.com/pmndrs/zustand/pull/2166](https://togithub.com/pmndrs/zustand/pull/2166) **Full Changelog**: pmndrs/zustand@v4.4.5...v4.4.6 ### [`v4.4.5`](https://togithub.com/pmndrs/zustand/releases/tag/v4.4.5) [Compare Source](https://togithub.com/pmndrs/zustand/compare/v4.4.4...v4.4.5) Hopefully, it should fix some issues with Node.js environment including Next.js. #### What's Changed - fix: importing CJS React in ESM by [@​dai-shi](https://togithub.com/dai-shi) in [https://github.com/pmndrs/zustand/pull/2154](https://togithub.com/pmndrs/zustand/pull/2154) - Apply publint recommendations by [@​dbritto-dev](https://togithub.com/dbritto-dev) in [https://github.com/pmndrs/zustand/pull/2157](https://togithub.com/pmndrs/zustand/pull/2157) #### New Contributors - [@​plrs9816](https://togithub.com/plrs9816) made their first contribution in [https://github.com/pmndrs/zustand/pull/2137](https://togithub.com/pmndrs/zustand/pull/2137) - [@​Brammm](https://togithub.com/Brammm) made their first contribution in [https://github.com/pmndrs/zustand/pull/2139](https://togithub.com/pmndrs/zustand/pull/2139) - [@​sobies93](https://togithub.com/sobies93) made their first contribution in [https://github.com/pmndrs/zustand/pull/2142](https://togithub.com/pmndrs/zustand/pull/2142) **Full Changelog**: pmndrs/zustand@v4.4.4...v4.4.5 ### [`v4.4.4`](https://togithub.com/pmndrs/zustand/releases/tag/v4.4.4) [Compare Source](https://togithub.com/pmndrs/zustand/compare/v4.4.3...v4.4.4) There was a tiny issue in v4.4.3, which broke with some bundlers, which this version fixes. #### What's Changed - fix(build): patch entry points zustand/shallow for CJS by [@​dai-shi](https://togithub.com/dai-shi) in [https://github.com/pmndrs/zustand/pull/2128](https://togithub.com/pmndrs/zustand/pull/2128) **Full Changelog**: pmndrs/zustand@v4.4.3...v4.4.4 ### [`v4.4.3`](https://togithub.com/pmndrs/zustand/releases/tag/v4.4.3) [Compare Source](https://togithub.com/pmndrs/zustand/compare/v4.4.2...v4.4.3) The changes in v4.4.2 were troublesome for some users. This version should fix/mitigate such cases. #### What's Changed - fix(shallow): Extract shallow vanilla and react by [@​dbritto-dev](https://togithub.com/dbritto-dev) in [https://github.com/pmndrs/zustand/pull/2097](https://togithub.com/pmndrs/zustand/pull/2097) - fix(types): mitigate devtools typing by [@​dai-shi](https://togithub.com/dai-shi) in [https://github.com/pmndrs/zustand/pull/2099](https://togithub.com/pmndrs/zustand/pull/2099) **Full Changelog**: pmndrs/zustand@v4.4.2...v4.4.3 ### [`v4.4.2`](https://togithub.com/pmndrs/zustand/releases/tag/v4.4.2) [Compare Source](https://togithub.com/pmndrs/zustand/compare/v4.4.1...v4.4.2) This adds `useShallow` hook to cover some use cases that are deprecated with v4.4.0 change. Check out [the guide](https://togithub.com/pmndrs/zustand/blob/ec538e9d4c0b9b5759e6dfd0fd3c9a21f8236949/docs/guides/prevent-rerenders-with-use-shallow.md). ##### Migration Guide [#​1991](https://togithub.com/pmndrs/zustand/issues/1991) requires something like below if you are using the `devtools` middleware *and* TypeScript. ```diff import { devtools } from 'zustand/middleware' + import type {} from '@​redux-devtools/extension' ``` ##### What's Changed - fix(types)(middleware/devtools): avoid copying types by [@​dai-shi](https://togithub.com/dai-shi) in [https://github.com/pmndrs/zustand/pull/1991](https://togithub.com/pmndrs/zustand/pull/1991) - fix(traditional): make defaultEqualityFn optional in TS Types by [@​charkour](https://togithub.com/charkour) in [https://github.com/pmndrs/zustand/pull/2060](https://togithub.com/pmndrs/zustand/pull/2060) - feat: add useShallow by [@​FaberVitale](https://togithub.com/FaberVitale) in [https://github.com/pmndrs/zustand/pull/2090](https://togithub.com/pmndrs/zustand/pull/2090) ##### New Contributors - [@​aykutkardas](https://togithub.com/aykutkardas) made their first contribution in [https://github.com/pmndrs/zustand/pull/1993](https://togithub.com/pmndrs/zustand/pull/1993) - [@​michelts](https://togithub.com/michelts) made their first contribution in [https://github.com/pmndrs/zustand/pull/1997](https://togithub.com/pmndrs/zustand/pull/1997) - [@​elusive](https://togithub.com/elusive) made their first contribution in [https://github.com/pmndrs/zustand/pull/2001](https://togithub.com/pmndrs/zustand/pull/2001) - [@​mayank1513](https://togithub.com/mayank1513) made their first contribution in [https://github.com/pmndrs/zustand/pull/2015](https://togithub.com/pmndrs/zustand/pull/2015) - [@​fdb](https://togithub.com/fdb) made their first contribution in [https://github.com/pmndrs/zustand/pull/2029](https://togithub.com/pmndrs/zustand/pull/2029) - [@​tmkx](https://togithub.com/tmkx) made their first contribution in [https://github.com/pmndrs/zustand/pull/2032](https://togithub.com/pmndrs/zustand/pull/2032) - [@​OshriAsulin](https://togithub.com/OshriAsulin) made their first contribution in [https://github.com/pmndrs/zustand/pull/2028](https://togithub.com/pmndrs/zustand/pull/2028) - [@​ivanquirino](https://togithub.com/ivanquirino) made their first contribution in [https://github.com/pmndrs/zustand/pull/2047](https://togithub.com/pmndrs/zustand/pull/2047) - [@​stavkamil](https://togithub.com/stavkamil) made their first contribution in [https://github.com/pmndrs/zustand/pull/2071](https://togithub.com/pmndrs/zustand/pull/2071) - [@​NaamuKim](https://togithub.com/NaamuKim) made their first contribution in [https://github.com/pmndrs/zustand/pull/2088](https://togithub.com/pmndrs/zustand/pull/2088) - [@​FaberVitale](https://togithub.com/FaberVitale) made their first contribution in [https://github.com/pmndrs/zustand/pull/2090](https://togithub.com/pmndrs/zustand/pull/2090) **Full Changelog**: pmndrs/zustand@v4.4.1...v4.4.2 </details> --- ### Configuration 📅 **Schedule**: Branch creation - "after 4pm every weekday" in timezone Europe/Paris, Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/specfy/specfy). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40Ni4wIiwidXBkYXRlZEluVmVyIjoiMzcuNDYuMCIsInRhcmdldEJyYW5jaCI6ImNob3JlL3Jlbm92YXRlQmFzZUJyYW5jaCJ9--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Related Issues or Discussions
Summary
This change tests state synchronization between server and client using React 18 and Zustand. It verifies that the server-rendered markup reflects the initial state correctly, and this state is accurately updated on the client side. This test is executed only when the version of React is 18.
Please suggest me if you have any other tests that might be helpful!
Check List
yarn run prettier
for formatting code and docs