You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #2175 bumped jotai to 3 and added an exported flushPendingAtomUpdates() to src/utils/testing/renderHookWithJotai.tsx. Its body is await act(async () => {}) and nothing else. It has one consumer, useSchemaSync.test.ts, with 10 call sites.
The helper works. Where it lives is the open question, and it needs answering before a second test file copies the pattern.
Two things make this worth settling now rather than later. docs/agents/testing.md already tells agents to use renderHookWithState and to avoid renderHookWithJotai, which is the file the helper lives in, so the sanctioned path and the helper's home disagree. And the helper is re-exported through the @/utils/testing barrel, so it reads as general-purpose when exactly one test file needs it.
The decision
Option A: move the settle inside renderHookWithState. Callers get it for free and all 10 call sites plus the barrel export disappear. The cost is that renderHookWithState becomes async, which changes a signature every hook test in the repo uses.
Option B: inline await act(async () => {}) at the few sites that genuinely need it and drop the shared export. No signature change, no shared abstraction for one consumer. The cost is that each future author rediscovers the need.
Whichever wins, the rule needs stating, including when the settle is not needed. waitFor already absorbs it, so a test asserting inside waitFor needs nothing. Without that written down, agents will add the flush to every test by reflex.
Also fold in
useResetState.test.ts has the same un-wrapped post-mount store.set pattern that #2175 wrapped in act() in useSchemaSync.test.ts, left untreated in two places (the search and query-editor reset test, and the previous-session-availability test). They pass today because the atoms they write are not ones the hook under test renders from. Same pattern, one file treated and one not, so pick one treatment and apply it to both.
Background
jotai v2 always re-rendered once right after mount, even without a value change, which absorbed store writes landing before useAtomValue subscribed. v3 drops that extra render and only re-renders on an actual change, so such a write now arrives as its own render after renderHook or store.set returns. jotai's own docs/core/use-atom.mdx documents this as the release's one behavioral caveat.
Expected outcome
A decision between A and B, applied
useResetState.test.ts consistent with useSchemaSync.test.ts
docs/agents/testing.md states the rule and its limit, so the next Jotai-backed hook test does not reinvent a flush
Description
PR #2175 bumped jotai to 3 and added an exported
flushPendingAtomUpdates()tosrc/utils/testing/renderHookWithJotai.tsx. Its body isawait act(async () => {})and nothing else. It has one consumer,useSchemaSync.test.ts, with 10 call sites.The helper works. Where it lives is the open question, and it needs answering before a second test file copies the pattern.
Two things make this worth settling now rather than later.
docs/agents/testing.mdalready tells agents to userenderHookWithStateand to avoidrenderHookWithJotai, which is the file the helper lives in, so the sanctioned path and the helper's home disagree. And the helper is re-exported through the@/utils/testingbarrel, so it reads as general-purpose when exactly one test file needs it.The decision
Option A: move the settle inside
renderHookWithState. Callers get it for free and all 10 call sites plus the barrel export disappear. The cost is thatrenderHookWithStatebecomes async, which changes a signature every hook test in the repo uses.Option B: inline
await act(async () => {})at the few sites that genuinely need it and drop the shared export. No signature change, no shared abstraction for one consumer. The cost is that each future author rediscovers the need.Whichever wins, the rule needs stating, including when the settle is not needed.
waitForalready absorbs it, so a test asserting insidewaitForneeds nothing. Without that written down, agents will add the flush to every test by reflex.Also fold in
useResetState.test.tshas the same un-wrapped post-mountstore.setpattern that #2175 wrapped inact()inuseSchemaSync.test.ts, left untreated in two places (the search and query-editor reset test, and the previous-session-availability test). They pass today because the atoms they write are not ones the hook under test renders from. Same pattern, one file treated and one not, so pick one treatment and apply it to both.Background
jotai v2 always re-rendered once right after mount, even without a value change, which absorbed store writes landing before
useAtomValuesubscribed. v3 drops that extra render and only re-renders on an actual change, so such a write now arrives as its own render afterrenderHookorstore.setreturns. jotai's owndocs/core/use-atom.mdxdocuments this as the release's one behavioral caveat.Expected outcome
useResetState.test.tsconsistent withuseSchemaSync.test.tsdocs/agents/testing.mdstates the rule and its limit, so the next Jotai-backed hook test does not reinvent a flushRelated Issues
Important
Internal only — this issue is maintained by the core team and is not accepting external contributions.