From 86bb440307cfe585b223b266d0f982574b852459 Mon Sep 17 00:00:00 2001 From: Oskar Eichler <62393985+OskarEichler@users.noreply.github.com> Date: Thu, 27 Aug 2026 17:26:45 +0300 Subject: [PATCH 1/6] fix: respect falsy server snapshots and production context overrides --- src/components/Provider.tsx | 2 +- src/components/connect.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index 5f532c459..763004e2c 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -65,7 +65,7 @@ function Provider = UnknownAction, S = unknown>( const baseContextValue = { store, subscription, - getServerState: serverState ? () => serverState : undefined, + getServerState: serverState !== undefined ? () => serverState : undefined, } if (process.env.NODE_ENV === 'production') { diff --git a/src/components/connect.tsx b/src/components/connect.tsx index 1c874cd20..7c2903f4b 100644 --- a/src/components/connect.tsx +++ b/src/components/connect.tsx @@ -736,8 +736,8 @@ function _connect< 'You must pass a valid React context consumer as `props.context`', ) } - ResultContext = propsContext } + ResultContext = propsContext } return ResultContext }, [propsContext, Context]) From d179c827edc264f079362346428ae2bbebe8d54c Mon Sep 17 00:00:00 2001 From: Oskar Eichler <62393985+OskarEichler@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:59:57 +0300 Subject: [PATCH 2/6] test: cover falsy server snapshots --- test/integration/ssr.spec.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/integration/ssr.spec.tsx b/test/integration/ssr.spec.tsx index 1869b5b6d..1a437cc27 100644 --- a/test/integration/ssr.spec.tsx +++ b/test/integration/ssr.spec.tsx @@ -124,6 +124,25 @@ describe('New v8 serverState behavior', () => { vi.restoreAllMocks() }) + it.each([0, false, '', null])( + 'uses a falsy serverState value of %p', + (serverState) => { + const store = createStore((state: unknown = 'client') => state) + + function Value() { + return {String(useSelector((state: unknown) => state))} + } + + const markup = renderToString( + + + , + ) + + expect(markup).toBe(`${String(serverState)}`) + }, + ) + it('Handles hydration correctly', async () => { const ssrStore = createStore(dataSlice.reducer) From 8fcdc865e1cd3835988f50967406451e69a09425 Mon Sep 17 00:00:00 2001 From: Oskar Eichler <62393985+OskarEichler@users.noreply.github.com> Date: Fri, 28 Aug 2026 17:00:18 +0300 Subject: [PATCH 3/6] test: cover production context props --- test/components/connect.spec.tsx | 61 +++++++++++++++++--------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/test/components/connect.spec.tsx b/test/components/connect.spec.tsx index 22eac6914..9d20d3f36 100644 --- a/test/components/connect.spec.tsx +++ b/test/components/connect.spec.tsx @@ -2236,41 +2236,46 @@ describe('React', () => { expect(actualState).toEqual(expectedState) }) - it('should use a custom context provider and consumer if passed as a prop to the component', () => { - class Container extends Component { - render() { - return + it.each(['development', 'production'])( + 'should use a custom context prop in %s', + (nodeEnv) => { + vi.stubEnv('NODE_ENV', nodeEnv) + class Container extends Component { + render() { + return + } } - } - const context = React.createContext | null>(null) + const context = React.createContext | null>(null) - let actualState + let actualState - const expectedState = { foos: {} } - const ignoredState = { bars: {} } + const expectedState = { foos: {} } + const ignoredState = { bars: {} } - const decorator = connect((state) => { - actualState = state - return { a: 42 } - }) - const Decorated = decorator(Container) + const decorator = connect((state) => { + actualState = state + return { a: 42 } + }) + const Decorated = decorator(Container) - const store1 = createStore(() => expectedState) - const store2 = createStore(() => ignoredState) - rtl.render( - - - - - , - ) + const store1 = createStore(() => expectedState) + const store2 = createStore(() => ignoredState) + rtl.render( + + + + + , + ) - expect(actualState).toEqual(expectedState) - }) + expect(actualState).toEqual(expectedState) + vi.unstubAllEnvs() + }, + ) it('should ignore non-react-context values that are passed as a prop to the component', () => { class Container extends Component { From 16fa807953096e992ed3956cb51359b583c07015 Mon Sep 17 00:00:00 2001 From: Oskar Eichler <62393985+OskarEichler@users.noreply.github.com> Date: Sat, 29 Aug 2026 20:33:45 +0200 Subject: [PATCH 4/6] test: use Vitest parameterized test API --- test/components/connect.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/connect.spec.tsx b/test/components/connect.spec.tsx index 9d20d3f36..201c2633f 100644 --- a/test/components/connect.spec.tsx +++ b/test/components/connect.spec.tsx @@ -2236,7 +2236,7 @@ describe('React', () => { expect(actualState).toEqual(expectedState) }) - it.each(['development', 'production'])( + it.for(['development', 'production'] as const)( 'should use a custom context prop in %s', (nodeEnv) => { vi.stubEnv('NODE_ENV', nodeEnv) From 4ed6719dd49264e1b03e4fc9db6d08d9aef23fb9 Mon Sep 17 00:00:00 2001 From: Oskar Eichler <62393985+OskarEichler@users.noreply.github.com> Date: Sat, 29 Aug 2026 20:33:47 +0200 Subject: [PATCH 5/6] test: use Vitest parameterized test API --- test/integration/ssr.spec.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/ssr.spec.tsx b/test/integration/ssr.spec.tsx index 1a437cc27..a2e22ea46 100644 --- a/test/integration/ssr.spec.tsx +++ b/test/integration/ssr.spec.tsx @@ -124,8 +124,8 @@ describe('New v8 serverState behavior', () => { vi.restoreAllMocks() }) - it.each([0, false, '', null])( - 'uses a falsy serverState value of %p', + it.for([0, false, '', null] as const)( + 'uses a falsy serverState value of %s', (serverState) => { const store = createStore((state: unknown = 'client') => state) From 1cb190607952a0dc29220af780c8f67ddd4260a6 Mon Sep 17 00:00:00 2001 From: Mark Erikson Date: Tue, 29 Sep 2026 22:02:45 -0400 Subject: [PATCH 6/6] Treat null serverState as absent and always unstub NODE_ENV --- src/components/Provider.tsx | 2 +- test/components/connect.spec.tsx | 7 +++++-- test/integration/ssr.spec.tsx | 21 ++++++++++++++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/components/Provider.tsx b/src/components/Provider.tsx index 763004e2c..aeb385fa7 100644 --- a/src/components/Provider.tsx +++ b/src/components/Provider.tsx @@ -65,7 +65,7 @@ function Provider = UnknownAction, S = unknown>( const baseContextValue = { store, subscription, - getServerState: serverState !== undefined ? () => serverState : undefined, + getServerState: serverState != null ? () => serverState : undefined, } if (process.env.NODE_ENV === 'production') { diff --git a/test/components/connect.spec.tsx b/test/components/connect.spec.tsx index 201c2633f..6947da179 100644 --- a/test/components/connect.spec.tsx +++ b/test/components/connect.spec.tsx @@ -2238,8 +2238,12 @@ describe('React', () => { it.for(['development', 'production'] as const)( 'should use a custom context prop in %s', - (nodeEnv) => { + (nodeEnv, { onTestFinished }) => { vi.stubEnv('NODE_ENV', nodeEnv) + onTestFinished(() => { + vi.unstubAllEnvs() + }) + class Container extends Component { render() { return @@ -2273,7 +2277,6 @@ describe('React', () => { ) expect(actualState).toEqual(expectedState) - vi.unstubAllEnvs() }, ) diff --git a/test/integration/ssr.spec.tsx b/test/integration/ssr.spec.tsx index a2e22ea46..dfee4b06d 100644 --- a/test/integration/ssr.spec.tsx +++ b/test/integration/ssr.spec.tsx @@ -124,7 +124,7 @@ describe('New v8 serverState behavior', () => { vi.restoreAllMocks() }) - it.for([0, false, '', null] as const)( + it.for([0, false, ''] as const)( 'uses a falsy serverState value of %s', (serverState) => { const store = createStore((state: unknown = 'client') => state) @@ -143,6 +143,25 @@ describe('New v8 serverState behavior', () => { }, ) + it.for([null, undefined] as const)( + 'falls back to the store state when serverState is %s', + (serverState) => { + const store = createStore((state: unknown = 'client') => state) + + function Value() { + return {String(useSelector((state: unknown) => state))} + } + + const markup = renderToString( + + + , + ) + + expect(markup).toBe('client') + }, + ) + it('Handles hydration correctly', async () => { const ssrStore = createStore(dataSlice.reducer)