@storve/react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/benchmarks/week3.ts +102 -0
- package/coverage/coverage-summary.json +5 -0
- package/dist/index.cjs +97 -0
- package/dist/index.cjs.js +9 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +7 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.mjs +94 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/useDevtools.d.ts +23 -0
- package/dist/useDevtools.d.ts.map +1 -0
- package/dist/useStore.d.ts +5 -0
- package/dist/useStore.d.ts.map +1 -0
- package/package.json +40 -0
- package/rollup.config.mjs +25 -0
- package/src/index.ts +4 -0
- package/src/types.ts +16 -0
- package/src/useDevtools.ts +74 -0
- package/src/useStore.ts +83 -0
- package/test_output.txt +234 -0
- package/tests/computed.react.test.tsx +71 -0
- package/tests/concurrent.test.tsx +101 -0
- package/tests/index.test.tsx +29 -0
- package/tests/integration.test.tsx +135 -0
- package/tests/lifecycle.test.tsx +148 -0
- package/tests/selector.test.tsx +288 -0
- package/tests/setup.ts +7 -0
- package/tests/useDevtools.test.tsx +80 -0
- package/tests/useStore.test.tsx +233 -0
- package/tsconfig.json +16 -0
- package/vitest.config.mts +30 -0
package/test_output.txt
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
|
|
2
|
+
> reactflux-react@0.0.1 test /Users/dipanshusrivastava/Desktop/React Flux/packages/reactflux-react
|
|
3
|
+
> vitest run --coverage && npx tsx benchmarks/week3.ts --filter reactflux-react --run
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
RUN v2.1.0 /Users/dipanshusrivastava/Desktop/React Flux/packages/reactflux-react
|
|
7
|
+
Coverage enabled with v8
|
|
8
|
+
|
|
9
|
+
stderr | tests/selector.test.tsx > useStore with selector > selector returning object re-renders correctly
|
|
10
|
+
Warning: The result of getSnapshot should be cached to avoid an infinite loop
|
|
11
|
+
at Test (/Users/dipanshusrivastava/Desktop/React Flux/packages/reactflux-react/tests/selector.test.tsx:85:41)
|
|
12
|
+
Error: Uncaught [Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.]
|
|
13
|
+
at reportException (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
|
|
14
|
+
at innerInvokeEventListeners (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:353:9)
|
|
15
|
+
at invokeEventListeners (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
|
|
16
|
+
at HTMLUnknownElementImpl._dispatch (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
|
|
17
|
+
at HTMLUnknownElementImpl.dispatchEvent (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
|
|
18
|
+
at HTMLUnknownElement.dispatchEvent (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
|
|
19
|
+
at Object.invokeGuardedCallbackDev (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:4213:16)
|
|
20
|
+
at invokeGuardedCallback (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:4277:31)
|
|
21
|
+
at reportUncaughtErrorInDEV (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:22877:5)
|
|
22
|
+
at captureCommitPhaseError (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27165:5) Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
|
|
23
|
+
at checkForNestedUpdates (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27331:11)
|
|
24
|
+
at scheduleUpdateOnFiber (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:25514:3)
|
|
25
|
+
at forceStoreRerender (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16158:5)
|
|
26
|
+
at updateStoreInstance (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16124:5)
|
|
27
|
+
at commitHookEffectListMount (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:23189:26)
|
|
28
|
+
at commitPassiveMountOnFiber (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24970:11)
|
|
29
|
+
at commitPassiveMountEffects_complete (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24930:9)
|
|
30
|
+
at commitPassiveMountEffects_begin (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24917:7)
|
|
31
|
+
at commitPassiveMountEffects (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24905:3)
|
|
32
|
+
at flushPassiveEffectsImpl (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27078:3)
|
|
33
|
+
The above error occurred in the <Test> component:
|
|
34
|
+
|
|
35
|
+
at Test (/Users/dipanshusrivastava/Desktop/React Flux/packages/reactflux-react/tests/selector.test.tsx:85:41)
|
|
36
|
+
|
|
37
|
+
Consider adding an error boundary to your tree to customize error handling behavior.
|
|
38
|
+
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
|
|
39
|
+
|
|
40
|
+
stderr | tests/selector.test.tsx > useStore with selector > selector returning array re-renders correctly
|
|
41
|
+
Error: Uncaught [Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.]
|
|
42
|
+
at reportException (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
|
|
43
|
+
at innerInvokeEventListeners (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:353:9)
|
|
44
|
+
at invokeEventListeners (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
|
|
45
|
+
at HTMLUnknownElementImpl._dispatch (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
|
|
46
|
+
at HTMLUnknownElementImpl.dispatchEvent (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
|
|
47
|
+
at HTMLUnknownElement.dispatchEvent (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
|
|
48
|
+
at Object.invokeGuardedCallbackDev (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:4213:16)
|
|
49
|
+
at invokeGuardedCallback (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:4277:31)
|
|
50
|
+
at reportUncaughtErrorInDEV (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:22877:5)
|
|
51
|
+
at captureCommitPhaseError (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27165:5) Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
|
|
52
|
+
at checkForNestedUpdates (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27331:11)
|
|
53
|
+
at scheduleUpdateOnFiber (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:25514:3)
|
|
54
|
+
at forceStoreRerender (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16158:5)
|
|
55
|
+
at updateStoreInstance (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16124:5)
|
|
56
|
+
at commitHookEffectListMount (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:23189:26)
|
|
57
|
+
at commitPassiveMountOnFiber (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24970:11)
|
|
58
|
+
at commitPassiveMountEffects_complete (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24930:9)
|
|
59
|
+
at commitPassiveMountEffects_begin (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24917:7)
|
|
60
|
+
at commitPassiveMountEffects (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24905:3)
|
|
61
|
+
at flushPassiveEffectsImpl (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27078:3)
|
|
62
|
+
The above error occurred in the <Test> component:
|
|
63
|
+
|
|
64
|
+
at Test (/Users/dipanshusrivastava/Desktop/React Flux/packages/reactflux-react/tests/selector.test.tsx:103:43)
|
|
65
|
+
|
|
66
|
+
Consider adding an error boundary to your tree to customize error handling behavior.
|
|
67
|
+
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
|
|
68
|
+
|
|
69
|
+
❯ tests/selector.test.tsx (15 tests | 2 failed) 50ms
|
|
70
|
+
× useStore with selector > selector returning object re-renders correctly
|
|
71
|
+
→ Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
|
|
72
|
+
× useStore with selector > selector returning array re-renders correctly
|
|
73
|
+
→ Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
|
|
74
|
+
❯ tests/useStore.test.tsx (15 tests | 5 failed) 16ms
|
|
75
|
+
× useStore > returns updated state after setState called
|
|
76
|
+
→ expect(element).toHaveTextContent()
|
|
77
|
+
|
|
78
|
+
Expected element to have text content:
|
|
79
|
+
1
|
|
80
|
+
Received:
|
|
81
|
+
0
|
|
82
|
+
× useStore > component re-renders when state changes
|
|
83
|
+
→ expected "spy" to be called 2 times, but got 1 times
|
|
84
|
+
× useStore > component does NOT re-render when unrelated state changes
|
|
85
|
+
→ expected "spy" to be called 2 times, but got 1 times
|
|
86
|
+
× useStore > multiple components using same store all update correctly
|
|
87
|
+
→ expect(element).toHaveTextContent()
|
|
88
|
+
|
|
89
|
+
Expected element to have text content:
|
|
90
|
+
5
|
|
91
|
+
Received:
|
|
92
|
+
0
|
|
93
|
+
× useStore > multiple components using different stores are independent
|
|
94
|
+
→ expect(element).toHaveTextContent()
|
|
95
|
+
|
|
96
|
+
Expected element to have text content:
|
|
97
|
+
10
|
|
98
|
+
Received:
|
|
99
|
+
1
|
|
100
|
+
✓ tests/lifecycle.test.tsx (9 tests) 30ms
|
|
101
|
+
stderr | tests/integration.test.tsx > integration scenarios > todo list — filter selector shows correct items
|
|
102
|
+
Error: Uncaught [Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.]
|
|
103
|
+
at reportException (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
|
|
104
|
+
at innerInvokeEventListeners (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:353:9)
|
|
105
|
+
at invokeEventListeners (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:286:3)
|
|
106
|
+
at HTMLUnknownElementImpl._dispatch (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:233:9)
|
|
107
|
+
at HTMLUnknownElementImpl.dispatchEvent (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:104:17)
|
|
108
|
+
at HTMLUnknownElement.dispatchEvent (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/jsdom@24.1.3/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:241:34)
|
|
109
|
+
at Object.invokeGuardedCallbackDev (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:4213:16)
|
|
110
|
+
at invokeGuardedCallback (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:4277:31)
|
|
111
|
+
at reportUncaughtErrorInDEV (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:22877:5)
|
|
112
|
+
at captureCommitPhaseError (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27165:5) Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
|
|
113
|
+
at checkForNestedUpdates (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27331:11)
|
|
114
|
+
at scheduleUpdateOnFiber (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:25514:3)
|
|
115
|
+
at forceStoreRerender (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16158:5)
|
|
116
|
+
at updateStoreInstance (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16124:5)
|
|
117
|
+
at commitHookEffectListMount (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:23189:26)
|
|
118
|
+
at commitPassiveMountOnFiber (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24970:11)
|
|
119
|
+
at commitPassiveMountEffects_complete (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24930:9)
|
|
120
|
+
at commitPassiveMountEffects_begin (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24917:7)
|
|
121
|
+
at commitPassiveMountEffects (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24905:3)
|
|
122
|
+
at flushPassiveEffectsImpl (/Users/dipanshusrivastava/Desktop/React Flux/node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27078:3)
|
|
123
|
+
The above error occurred in the <VisibleTodos> component:
|
|
124
|
+
|
|
125
|
+
at VisibleTodos (/Users/dipanshusrivastava/Desktop/React Flux/packages/reactflux-react/tests/integration.test.tsx:49:46)
|
|
126
|
+
|
|
127
|
+
Consider adding an error boundary to your tree to customize error handling behavior.
|
|
128
|
+
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
|
|
129
|
+
|
|
130
|
+
❯ tests/integration.test.tsx (5 tests | 1 failed) 52ms
|
|
131
|
+
× integration scenarios > todo list — filter selector shows correct items
|
|
132
|
+
→ Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
|
|
133
|
+
✓ tests/concurrent.test.tsx (5 tests) 5ms
|
|
134
|
+
|
|
135
|
+
⎯⎯⎯⎯⎯⎯⎯ Failed Tests 8 ⎯⎯⎯⎯⎯⎯⎯
|
|
136
|
+
|
|
137
|
+
FAIL tests/integration.test.tsx > integration scenarios > todo list — filter selector shows correct items
|
|
138
|
+
FAIL tests/selector.test.tsx > useStore with selector > selector returning object re-renders correctly
|
|
139
|
+
FAIL tests/selector.test.tsx > useStore with selector > selector returning array re-renders correctly
|
|
140
|
+
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
|
|
141
|
+
❯ checkForNestedUpdates ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27331:11
|
|
142
|
+
❯ scheduleUpdateOnFiber ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:25514:3
|
|
143
|
+
❯ forceStoreRerender ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16158:5
|
|
144
|
+
❯ updateStoreInstance ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:16124:5
|
|
145
|
+
❯ commitHookEffectListMount ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:23189:26
|
|
146
|
+
❯ commitPassiveMountOnFiber ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24970:11
|
|
147
|
+
❯ commitPassiveMountEffects_complete ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24930:9
|
|
148
|
+
❯ commitPassiveMountEffects_begin ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24917:7
|
|
149
|
+
❯ commitPassiveMountEffects ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:24905:3
|
|
150
|
+
❯ flushPassiveEffectsImpl ../../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.development.js:27078:3
|
|
151
|
+
|
|
152
|
+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/8]⎯
|
|
153
|
+
|
|
154
|
+
FAIL tests/useStore.test.tsx > useStore > returns updated state after setState called
|
|
155
|
+
Error: expect(element).toHaveTextContent()
|
|
156
|
+
|
|
157
|
+
Expected element to have text content:
|
|
158
|
+
1
|
|
159
|
+
Received:
|
|
160
|
+
0
|
|
161
|
+
❯ tests/useStore.test.tsx:39:45
|
|
162
|
+
37| store.setState({ count: 1 })
|
|
163
|
+
38| })
|
|
164
|
+
39| expect(screen.getByTestId('count')).toHaveTextContent('1')
|
|
165
|
+
| ^
|
|
166
|
+
40| })
|
|
167
|
+
41|
|
|
168
|
+
|
|
169
|
+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/8]⎯
|
|
170
|
+
|
|
171
|
+
FAIL tests/useStore.test.tsx > useStore > component re-renders when state changes
|
|
172
|
+
AssertionError: expected "spy" to be called 2 times, but got 1 times
|
|
173
|
+
❯ tests/useStore.test.tsx:55:27
|
|
174
|
+
53| store.setState({ count: 1 })
|
|
175
|
+
54| })
|
|
176
|
+
55| expect(renderSpy).toHaveBeenCalledTimes(2)
|
|
177
|
+
| ^
|
|
178
|
+
56| })
|
|
179
|
+
57|
|
|
180
|
+
|
|
181
|
+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/8]⎯
|
|
182
|
+
|
|
183
|
+
FAIL tests/useStore.test.tsx > useStore > component does NOT re-render when unrelated state changes
|
|
184
|
+
AssertionError: expected "spy" to be called 2 times, but got 1 times
|
|
185
|
+
❯ tests/useStore.test.tsx:76:27
|
|
186
|
+
74| store.setState({ b: 3 })
|
|
187
|
+
75| })
|
|
188
|
+
76| expect(renderSpy).toHaveBeenCalledTimes(2)
|
|
189
|
+
| ^
|
|
190
|
+
77| })
|
|
191
|
+
78|
|
|
192
|
+
|
|
193
|
+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/8]⎯
|
|
194
|
+
|
|
195
|
+
FAIL tests/useStore.test.tsx > useStore > multiple components using same store all update correctly
|
|
196
|
+
Error: expect(element).toHaveTextContent()
|
|
197
|
+
|
|
198
|
+
Expected element to have text content:
|
|
199
|
+
5
|
|
200
|
+
Received:
|
|
201
|
+
0
|
|
202
|
+
❯ tests/useStore.test.tsx:95:29
|
|
203
|
+
93| })
|
|
204
|
+
94| const elements = screen.getAllByTestId('count')
|
|
205
|
+
95| expect(elements[0]).toHaveTextContent('5')
|
|
206
|
+
| ^
|
|
207
|
+
96| expect(elements[1]).toHaveTextContent('5')
|
|
208
|
+
97| })
|
|
209
|
+
|
|
210
|
+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/8]⎯
|
|
211
|
+
|
|
212
|
+
FAIL tests/useStore.test.tsx > useStore > multiple components using different stores are independent
|
|
213
|
+
Error: expect(element).toHaveTextContent()
|
|
214
|
+
|
|
215
|
+
Expected element to have text content:
|
|
216
|
+
10
|
|
217
|
+
Received:
|
|
218
|
+
1
|
|
219
|
+
❯ tests/useStore.test.tsx:119:41
|
|
220
|
+
117| store1.setState({ a: 10 })
|
|
221
|
+
118| })
|
|
222
|
+
119| expect(screen.getByTestId('a')).toHaveTextContent('10')
|
|
223
|
+
| ^
|
|
224
|
+
120| expect(screen.getByTestId('b')).toHaveTextContent('2')
|
|
225
|
+
121| })
|
|
226
|
+
|
|
227
|
+
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/8]⎯
|
|
228
|
+
|
|
229
|
+
Test Files 3 failed | 2 passed (5)
|
|
230
|
+
Tests 8 failed | 41 passed (49)
|
|
231
|
+
Start at 18:08:59
|
|
232
|
+
Duration 1.01s (transform 67ms, setup 133ms, collect 70ms, tests 153ms, environment 342ms, prepare 50ms)
|
|
233
|
+
|
|
234
|
+
ELIFECYCLE Test failed. See above for more details.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { render, screen, act } from '@testing-library/react'
|
|
2
|
+
import { createStore } from '@storve/core'
|
|
3
|
+
import { computed } from '@storve/core/computed'
|
|
4
|
+
import { useStore } from '../src/useStore'
|
|
5
|
+
import { expect, it, describe, vi } from 'vitest'
|
|
6
|
+
import React from 'react'
|
|
7
|
+
|
|
8
|
+
describe('useStore with computed values', () => {
|
|
9
|
+
it('component using computed selector re-renders when computed result changes', () => {
|
|
10
|
+
const store = createStore({
|
|
11
|
+
count: 0,
|
|
12
|
+
doubled: computed((s: { count: number }) => s.count * 2),
|
|
13
|
+
})
|
|
14
|
+
const renderSpy = vi.fn()
|
|
15
|
+
function Test() {
|
|
16
|
+
renderSpy()
|
|
17
|
+
const doubled = useStore(store, (s) => s.doubled)
|
|
18
|
+
return <div data-testid="val">{doubled}</div>
|
|
19
|
+
}
|
|
20
|
+
render(<Test />)
|
|
21
|
+
expect(screen.getByTestId('val')).toHaveTextContent('0')
|
|
22
|
+
expect(renderSpy).toHaveBeenCalledTimes(1)
|
|
23
|
+
|
|
24
|
+
act(() => {
|
|
25
|
+
store.setState({ count: 1 })
|
|
26
|
+
})
|
|
27
|
+
expect(screen.getByTestId('val')).toHaveTextContent('2')
|
|
28
|
+
expect(renderSpy).toHaveBeenCalledTimes(2)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('component does NOT re-render when only unrelated state changes', () => {
|
|
32
|
+
const store = createStore({
|
|
33
|
+
count: 0,
|
|
34
|
+
other: 0,
|
|
35
|
+
doubled: computed((s: { count: number }) => s.count * 2),
|
|
36
|
+
})
|
|
37
|
+
const renderSpy = vi.fn()
|
|
38
|
+
function Test() {
|
|
39
|
+
renderSpy()
|
|
40
|
+
const doubled = useStore(store, (s) => s.doubled)
|
|
41
|
+
return <div data-testid="val">{doubled}</div>
|
|
42
|
+
}
|
|
43
|
+
render(<Test />)
|
|
44
|
+
expect(renderSpy).toHaveBeenCalledTimes(1)
|
|
45
|
+
|
|
46
|
+
act(() => {
|
|
47
|
+
store.setState({ other: 1 })
|
|
48
|
+
})
|
|
49
|
+
expect(renderSpy).toHaveBeenCalledTimes(1)
|
|
50
|
+
expect(screen.getByTestId('val')).toHaveTextContent('0')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('component re-renders when computed result changes after dependency update', () => {
|
|
54
|
+
const store = createStore({
|
|
55
|
+
a: 1,
|
|
56
|
+
b: 2,
|
|
57
|
+
sum: computed((s: { a: number; b: number }) => s.a + s.b),
|
|
58
|
+
})
|
|
59
|
+
function Test() {
|
|
60
|
+
const sum = useStore(store, (s) => s.sum)
|
|
61
|
+
return <div data-testid="sum">{sum}</div>
|
|
62
|
+
}
|
|
63
|
+
render(<Test />)
|
|
64
|
+
expect(screen.getByTestId('sum')).toHaveTextContent('3')
|
|
65
|
+
|
|
66
|
+
act(() => {
|
|
67
|
+
store.setState({ a: 10 })
|
|
68
|
+
})
|
|
69
|
+
expect(screen.getByTestId('sum')).toHaveTextContent('12')
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { render, screen, act } from '@testing-library/react'
|
|
2
|
+
import { createStore } from '@storve/core'
|
|
3
|
+
import { useStore } from '../src/useStore'
|
|
4
|
+
import { expect, it, describe, vi } from 'vitest'
|
|
5
|
+
import React, { StrictMode, Suspense, startTransition } from 'react'
|
|
6
|
+
|
|
7
|
+
describe('concurrent mode', () => {
|
|
8
|
+
it('works with React.StrictMode — double invoke safe', () => {
|
|
9
|
+
const store = createStore({ count: 0 })
|
|
10
|
+
const subscribeSpy = vi.spyOn(store, 'subscribe')
|
|
11
|
+
|
|
12
|
+
function Test() {
|
|
13
|
+
useStore(store)
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
render(
|
|
18
|
+
<StrictMode>
|
|
19
|
+
<Test />
|
|
20
|
+
</StrictMode>
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
// StrictMode might double-invoke effects/hooks initialization in dev
|
|
24
|
+
// useSyncExternalStore handles this internally.
|
|
25
|
+
expect(subscribeSpy).toHaveBeenCalled()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('no tearing — all components see consistent state snapshot', () => {
|
|
29
|
+
const store = createStore({ count: 0 })
|
|
30
|
+
|
|
31
|
+
function Display() {
|
|
32
|
+
const count = useStore(store, s => s.count)
|
|
33
|
+
return <div data-testid="count">{count}</div>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
render(
|
|
37
|
+
<>
|
|
38
|
+
<Display />
|
|
39
|
+
<Display />
|
|
40
|
+
<Display />
|
|
41
|
+
</>
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
act(() => {
|
|
45
|
+
store.setState({ count: 1 })
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const elements = screen.getAllByTestId('count')
|
|
49
|
+
const values = elements.map(el => el.textContent)
|
|
50
|
+
expect(new Set(values).size).toBe(1)
|
|
51
|
+
expect(values[0]).toBe('1')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('works inside Suspense boundary', async () => {
|
|
55
|
+
const store = createStore({ data: 'ready' })
|
|
56
|
+
|
|
57
|
+
function Content() {
|
|
58
|
+
const data = useStore(store, s => s.data)
|
|
59
|
+
return <div>{data}</div>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
render(
|
|
63
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
64
|
+
<Content />
|
|
65
|
+
</Suspense>
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
expect(screen.getByText('ready')).toBeInTheDocument()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('state update inside startTransition updates correctly', () => {
|
|
72
|
+
const store = createStore({ count: 0 })
|
|
73
|
+
|
|
74
|
+
function Counter() {
|
|
75
|
+
const count = useStore(store, s => s.count)
|
|
76
|
+
return <div data-testid="count">{count}</div>
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
render(<Counter />)
|
|
80
|
+
|
|
81
|
+
act(() => {
|
|
82
|
+
startTransition(() => {
|
|
83
|
+
store.setState({ count: 1 })
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
expect(screen.getByTestId('count')).toHaveTextContent('1')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('getSnapshot returns stable reference when state unchanged', () => {
|
|
91
|
+
const store = createStore({ a: 1 })
|
|
92
|
+
const state1 = store.getState()
|
|
93
|
+
const state2 = store.getState()
|
|
94
|
+
|
|
95
|
+
// Storve core ensures getState returns same Proxy reference if no changes
|
|
96
|
+
expect(state1).toBe(state2)
|
|
97
|
+
|
|
98
|
+
// useStore uses store.getState() internally via useSyncExternalStore's getSnapshot
|
|
99
|
+
// We can't easily inspect useSyncExternalStore internal state, but we verified getState() stability.
|
|
100
|
+
})
|
|
101
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react'
|
|
2
|
+
import { createStore } from '@storve/core'
|
|
3
|
+
import { useStore } from '../src/index'
|
|
4
|
+
import type { Selector } from '../src/index'
|
|
5
|
+
import { expect, it, describe } from 'vitest'
|
|
6
|
+
import React from 'react'
|
|
7
|
+
|
|
8
|
+
describe('index (public API)', () => {
|
|
9
|
+
it('useStore exported from index works correctly', () => {
|
|
10
|
+
const store = createStore({ count: 0 })
|
|
11
|
+
function Counter() {
|
|
12
|
+
const state = useStore(store)
|
|
13
|
+
return <div data-testid="count">{state.count}</div>
|
|
14
|
+
}
|
|
15
|
+
render(<Counter />)
|
|
16
|
+
expect(screen.getByTestId('count')).toHaveTextContent('0')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('Selector type can be used with useStore', () => {
|
|
20
|
+
const store = createStore({ a: 1, b: 2 })
|
|
21
|
+
const selector: Selector<{ a: number; b: number }, number> = (s) => s.a + s.b
|
|
22
|
+
function Test() {
|
|
23
|
+
const sum = useStore(store, selector)
|
|
24
|
+
return <div data-testid="sum">{sum}</div>
|
|
25
|
+
}
|
|
26
|
+
render(<Test />)
|
|
27
|
+
expect(screen.getByTestId('sum')).toHaveTextContent('3')
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { render, screen, act } from '@testing-library/react'
|
|
2
|
+
import { createStore } from '@storve/core'
|
|
3
|
+
import { useStore } from '../src/useStore'
|
|
4
|
+
import { expect, it, describe, vi } from 'vitest'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
|
|
7
|
+
describe('integration scenarios', () => {
|
|
8
|
+
it('counter component — increment updates UI', () => {
|
|
9
|
+
const store = createStore({ count: 0 })
|
|
10
|
+
const increment = () => store.setState((s) => ({ count: s.count + 1 }))
|
|
11
|
+
|
|
12
|
+
function Counter() {
|
|
13
|
+
const count = useStore(store, s => s.count)
|
|
14
|
+
return (
|
|
15
|
+
<div>
|
|
16
|
+
<span data-testid="count">{count}</span>
|
|
17
|
+
<button onClick={increment}>+</button>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
render(<Counter />)
|
|
23
|
+
expect(screen.getByTestId('count')).toHaveTextContent('0')
|
|
24
|
+
|
|
25
|
+
act(() => {
|
|
26
|
+
screen.getByText('+').click()
|
|
27
|
+
})
|
|
28
|
+
expect(screen.getByTestId('count')).toHaveTextContent('1')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('todo list — add item renders new item', () => {
|
|
32
|
+
const store = createStore({ todos: [] as string[] })
|
|
33
|
+
const addTodo = (text: string) => store.setState(s => ({ todos: [...s.todos, text] }))
|
|
34
|
+
|
|
35
|
+
function TodoList() {
|
|
36
|
+
const todos = useStore(store, s => s.todos)
|
|
37
|
+
return (
|
|
38
|
+
<ul>
|
|
39
|
+
{todos.map((t, i) => <li key={i}>{t}</li>)}
|
|
40
|
+
</ul>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
render(<TodoList />)
|
|
45
|
+
expect(screen.queryByRole('listitem')).not.toBeInTheDocument()
|
|
46
|
+
|
|
47
|
+
act(() => {
|
|
48
|
+
addTodo('Learn Storve')
|
|
49
|
+
})
|
|
50
|
+
expect(screen.getByRole('listitem')).toHaveTextContent('Learn Storve')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('todo list — filter selector shows correct items', () => {
|
|
54
|
+
const store = createStore({
|
|
55
|
+
todos: [
|
|
56
|
+
{ id: 1, text: 'A', done: true },
|
|
57
|
+
{ id: 2, text: 'B', done: false }
|
|
58
|
+
],
|
|
59
|
+
filter: 'all' as 'all' | 'done' | 'pending'
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
function VisibleTodos() {
|
|
63
|
+
const filtered = useStore(store, s => {
|
|
64
|
+
if (s.filter === 'done') return s.todos.filter(t => t.done)
|
|
65
|
+
if (s.filter === 'pending') return s.todos.filter(t => !t.done)
|
|
66
|
+
return s.todos
|
|
67
|
+
})
|
|
68
|
+
return (
|
|
69
|
+
<ul>
|
|
70
|
+
{filtered.map(t => <li key={t.id}>{t.text}</li>)}
|
|
71
|
+
</ul>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
render(<VisibleTodos />)
|
|
76
|
+
expect(screen.getAllByRole('listitem')).toHaveLength(2)
|
|
77
|
+
|
|
78
|
+
act(() => {
|
|
79
|
+
store.setState({ filter: 'done' })
|
|
80
|
+
})
|
|
81
|
+
expect(screen.getAllByRole('listitem')).toHaveLength(1)
|
|
82
|
+
expect(screen.getByRole('listitem')).toHaveTextContent('A')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('rapid state updates (100 in loop) — UI stays consistent', () => {
|
|
86
|
+
const store = createStore({ count: 0 })
|
|
87
|
+
function Counter() {
|
|
88
|
+
const count = useStore(store, s => s.count)
|
|
89
|
+
return <div data-testid="count">{count}</div>
|
|
90
|
+
}
|
|
91
|
+
render(<Counter />)
|
|
92
|
+
|
|
93
|
+
act(() => {
|
|
94
|
+
for (let i = 0; i < 100; i++) {
|
|
95
|
+
store.setState(s => ({ count: s.count + 1 }))
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
expect(screen.getByTestId('count')).toHaveTextContent('100')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('sibling components — one updates, only affected re-renders', () => {
|
|
102
|
+
const store = createStore({ a: 0, b: 0 })
|
|
103
|
+
const renderSpyA = vi.fn()
|
|
104
|
+
const renderSpyB = vi.fn()
|
|
105
|
+
|
|
106
|
+
function ComponentA() {
|
|
107
|
+
renderSpyA()
|
|
108
|
+
const a = useStore(store, s => s.a)
|
|
109
|
+
return <div>{a}</div>
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function ComponentB() {
|
|
113
|
+
renderSpyB()
|
|
114
|
+
const b = useStore(store, s => s.b)
|
|
115
|
+
return <div>{b}</div>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
render(
|
|
119
|
+
<>
|
|
120
|
+
<ComponentA />
|
|
121
|
+
<ComponentB />
|
|
122
|
+
</>
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
renderSpyA.mockClear()
|
|
126
|
+
renderSpyB.mockClear()
|
|
127
|
+
|
|
128
|
+
act(() => {
|
|
129
|
+
store.setState({ a: 1 })
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
expect(renderSpyA).toHaveBeenCalledTimes(1)
|
|
133
|
+
expect(renderSpyB).toHaveBeenCalledTimes(0)
|
|
134
|
+
})
|
|
135
|
+
})
|