From 662f38a8c33e0758da859cf608caac6bccc5eddd Mon Sep 17 00:00:00 2001 From: Younghoo Kim Date: Mon, 11 Dec 2023 21:34:35 +0900 Subject: [PATCH 1/2] docs(immer): change demo url (#2239) --- docs/integrations/immer-middleware.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations/immer-middleware.md b/docs/integrations/immer-middleware.md index 6e77730096..b29cc90b38 100644 --- a/docs/integrations/immer-middleware.md +++ b/docs/integrations/immer-middleware.md @@ -125,5 +125,5 @@ Zustand will skip calling the subscriptions. ## CodeSandbox Demo -- [Basic](https://codesandbox.io/s/zustand-updating-draft-states-basic-demo-zkp22g), -- [Advanced](https://codesandbox.io/s/zustand-updating-draft-states-advanced-demo-3znqzk). +- [Basic](https://codesandbox.io/p/sandbox/zustand-updating-draft-states-basic-demo-forked-96mkdw), +- [Advanced](https://codesandbox.io/p/sandbox/zustand-updating-draft-states-advanced-demo-forked-phkzzg). From 9baf0a5d38ee33cdafced98b5c86c8cc77db3b2e Mon Sep 17 00:00:00 2001 From: Charles Kornoelje <33156025+charkour@users.noreply.github.com> Date: Tue, 12 Dec 2023 10:46:50 -0500 Subject: [PATCH 2/2] chore(test): stop testing deprecated features and test subscribe in vanilla (#2244) * chore(test): update test to stop testing deprecated features * chore(test): add subscribe test for zustand/vanilla * chore(test): only verify that subscribe exists on `create` * chore(test): switch type of test --- tests/shallow.test.tsx | 5 +- tests/subscribe.test.tsx | 122 +----------------------------- tests/vanilla/subscribe.test.tsx | 123 +++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 120 deletions(-) create mode 100644 tests/vanilla/subscribe.test.tsx diff --git a/tests/shallow.test.tsx b/tests/shallow.test.tsx index 9226a34a2d..65441f8efa 100644 --- a/tests/shallow.test.tsx +++ b/tests/shallow.test.tsx @@ -3,11 +3,12 @@ import { act, fireEvent, render } from '@testing-library/react' import { beforeEach, describe, expect, it, vi } from 'vitest' import { create } from 'zustand' import { useShallow } from 'zustand/react/shallow' +import { createWithEqualityFn } from 'zustand/traditional' import { shallow } from 'zustand/vanilla/shallow' describe('types', () => { it('works with useBoundStore and array selector (#1107)', () => { - const useBoundStore = create(() => ({ + const useBoundStore = createWithEqualityFn(() => ({ villages: [] as { name: string }[], })) const Component = () => { @@ -18,7 +19,7 @@ describe('types', () => { }) it('works with useBoundStore and string selector (#1107)', () => { - const useBoundStore = create(() => ({ + const useBoundStore = createWithEqualityFn(() => ({ refetchTimestamp: '', })) const Component = () => { diff --git a/tests/subscribe.test.tsx b/tests/subscribe.test.tsx index 3e160ac95e..5427eeb151 100644 --- a/tests/subscribe.test.tsx +++ b/tests/subscribe.test.tsx @@ -1,123 +1,9 @@ -import { describe, expect, it, vi } from 'vitest' +import { describe, expect, it } from 'vitest' import { create } from 'zustand' -import { subscribeWithSelector } from 'zustand/middleware' describe('subscribe()', () => { - it('should not be called if new state identity is the same', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { setState, subscribe } = create(() => initialState) - - subscribe(spy) - setState(initialState) - expect(spy).not.toHaveBeenCalled() - }) - - it('should be called if new state identity is different', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { setState, getState, subscribe } = create(() => initialState) - - subscribe(spy) - setState({ ...getState() }) - expect(spy).toHaveBeenCalledWith(initialState, initialState) - }) - - it('should not be called when state slice is the same', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { setState, subscribe } = create( - subscribeWithSelector(() => initialState), - ) - - subscribe((s) => s.value, spy) - setState({ other: 'b' }) - expect(spy).not.toHaveBeenCalled() - }) - - it('should be called when state slice changes', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { setState, subscribe } = create( - subscribeWithSelector(() => initialState), - ) - - subscribe((s) => s.value, spy) - setState({ value: initialState.value + 1 }) - expect(spy).toHaveBeenCalledTimes(1) - expect(spy).toHaveBeenCalledWith(initialState.value + 1, initialState.value) - }) - - it('should not be called when equality checker returns true', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { setState, subscribe } = create( - subscribeWithSelector(() => initialState), - ) - - subscribe((s) => s, spy, { equalityFn: () => true }) - setState({ value: initialState.value + 2 }) - expect(spy).not.toHaveBeenCalled() - }) - - it('should be called when equality checker returns false', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { setState, subscribe } = create( - subscribeWithSelector(() => initialState), - ) - - subscribe((s) => s.value, spy, { equalityFn: () => false }) - setState({ value: initialState.value + 2 }) - expect(spy).toHaveBeenCalledTimes(1) - expect(spy).toHaveBeenCalledWith(initialState.value + 2, initialState.value) - }) - - it('should unsubscribe correctly', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { setState, subscribe } = create( - subscribeWithSelector(() => initialState), - ) - - const unsub = subscribe((s) => s.value, spy) - - setState({ value: initialState.value + 1 }) - unsub() - setState({ value: initialState.value + 2 }) - - expect(spy).toHaveBeenCalledTimes(1) - expect(spy).toHaveBeenCalledWith(initialState.value + 1, initialState.value) - }) - - it('should keep consistent behavior with equality check', () => { - const spy = vi.fn() - const initialState = { value: 1, other: 'a' } - const { getState, setState, subscribe } = create( - subscribeWithSelector(() => initialState), - ) - - const isRoughEqual = (x: number, y: number) => Math.abs(x - y) < 1 - setState({ value: 0 }) - spy.mockReset() - const spy2 = vi.fn() - let prevValue = getState().value - const unsub = subscribe((s) => { - if (isRoughEqual(prevValue, s.value)) { - // skip assuming values are equal - return - } - spy(s.value, prevValue) - prevValue = s.value - }) - const unsub2 = subscribe((s) => s.value, spy2, { equalityFn: isRoughEqual }) - setState({ value: 0.5 }) - setState({ value: 1 }) - unsub() - unsub2() - expect(spy).toHaveBeenCalledTimes(1) - expect(spy).toHaveBeenCalledWith(1, 0) - expect(spy2).toHaveBeenCalledTimes(1) - expect(spy2).toHaveBeenCalledWith(1, 0) + it('should correctly have access to subscribe', () => { + const { subscribe } = create(() => ({ value: 1 })) + expect(typeof subscribe).toBe('function') }) }) diff --git a/tests/vanilla/subscribe.test.tsx b/tests/vanilla/subscribe.test.tsx new file mode 100644 index 0000000000..0210672b09 --- /dev/null +++ b/tests/vanilla/subscribe.test.tsx @@ -0,0 +1,123 @@ +import { describe, expect, it, vi } from 'vitest' +import { subscribeWithSelector } from 'zustand/middleware' +import { createStore } from 'zustand/vanilla' + +describe('subscribe()', () => { + it('should not be called if new state identity is the same', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { setState, subscribe } = createStore(() => initialState) + + subscribe(spy) + setState(initialState) + expect(spy).not.toHaveBeenCalled() + }) + + it('should be called if new state identity is different', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { setState, getState, subscribe } = createStore(() => initialState) + + subscribe(spy) + setState({ ...getState() }) + expect(spy).toHaveBeenCalledWith(initialState, initialState) + }) + + it('should not be called when state slice is the same', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { setState, subscribe } = createStore( + subscribeWithSelector(() => initialState), + ) + + subscribe((s) => s.value, spy) + setState({ other: 'b' }) + expect(spy).not.toHaveBeenCalled() + }) + + it('should be called when state slice changes', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { setState, subscribe } = createStore( + subscribeWithSelector(() => initialState), + ) + + subscribe((s) => s.value, spy) + setState({ value: initialState.value + 1 }) + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith(initialState.value + 1, initialState.value) + }) + + it('should not be called when equality checker returns true', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { setState, subscribe } = createStore( + subscribeWithSelector(() => initialState), + ) + + subscribe((s) => s, spy, { equalityFn: () => true }) + setState({ value: initialState.value + 2 }) + expect(spy).not.toHaveBeenCalled() + }) + + it('should be called when equality checker returns false', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { setState, subscribe } = createStore( + subscribeWithSelector(() => initialState), + ) + + subscribe((s) => s.value, spy, { equalityFn: () => false }) + setState({ value: initialState.value + 2 }) + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith(initialState.value + 2, initialState.value) + }) + + it('should unsubscribe correctly', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { setState, subscribe } = createStore( + subscribeWithSelector(() => initialState), + ) + + const unsub = subscribe((s) => s.value, spy) + + setState({ value: initialState.value + 1 }) + unsub() + setState({ value: initialState.value + 2 }) + + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith(initialState.value + 1, initialState.value) + }) + + it('should keep consistent behavior with equality check', () => { + const spy = vi.fn() + const initialState = { value: 1, other: 'a' } + const { getState, setState, subscribe } = createStore( + subscribeWithSelector(() => initialState), + ) + + const isRoughEqual = (x: number, y: number) => Math.abs(x - y) < 1 + setState({ value: 0 }) + spy.mockReset() + const spy2 = vi.fn() + let prevValue = getState().value + const unsub = subscribe((s) => { + if (isRoughEqual(prevValue, s.value)) { + // skip assuming values are equal + return + } + spy(s.value, prevValue) + prevValue = s.value + }) + const unsub2 = subscribe((s) => s.value, spy2, { equalityFn: isRoughEqual }) + setState({ value: 0.5 }) + setState({ value: 1 }) + unsub() + unsub2() + expect(spy).toHaveBeenCalledTimes(1) + expect(spy).toHaveBeenCalledWith(1, 0) + expect(spy2).toHaveBeenCalledTimes(1) + expect(spy2).toHaveBeenCalledWith(1, 0) + }) +})