Skip to content

Commit 975fb17

Browse files
authored
test(useProxy): add tests for read, mutate, nested objects, multiple mutations, and 'sync' option (#1208)
* test(useProxy): add tests for read, mutate, nested objects, multiple mutations, and 'sync' option * test(useProxy): use 'eslint-disable-next-line' instead of file-level 'eslint-disable'
1 parent 0f88bf1 commit 975fb17

1 file changed

Lines changed: 136 additions & 0 deletions

File tree

tests/useProxy.test.tsx

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { StrictMode } from 'react'
2+
import { act, fireEvent, render, screen } from '@testing-library/react'
3+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
4+
import { proxy } from 'valtio'
5+
import { useProxy } from 'valtio/react/utils'
6+
7+
describe('useProxy', () => {
8+
beforeEach(() => {
9+
vi.useFakeTimers()
10+
})
11+
12+
afterEach(() => {
13+
vi.useRealTimers()
14+
})
15+
16+
it('should read and mutate with the same reference', async () => {
17+
const state = proxy({ count: 0 })
18+
19+
const Counter = () => {
20+
const store = useProxy(state)
21+
return (
22+
<>
23+
<div>count: {store.count}</div>
24+
{/* eslint-disable-next-line react-hooks/immutability */}
25+
<button onClick={() => ++store.count}>increment</button>
26+
</>
27+
)
28+
}
29+
30+
render(
31+
<StrictMode>
32+
<Counter />
33+
</StrictMode>,
34+
)
35+
36+
expect(screen.getByText('count: 0')).toBeInTheDocument()
37+
38+
fireEvent.click(screen.getByText('increment'))
39+
await act(() => vi.advanceTimersByTimeAsync(0))
40+
expect(screen.getByText('count: 1')).toBeInTheDocument()
41+
})
42+
43+
it('should update nested object properties', async () => {
44+
const state = proxy({
45+
user: { name: 'Alice', age: 20 },
46+
})
47+
48+
const Profile = () => {
49+
const store = useProxy(state)
50+
return (
51+
<>
52+
<div>
53+
{store.user.name} ({store.user.age})
54+
</div>
55+
{/* eslint-disable-next-line react-hooks/immutability */}
56+
<button onClick={() => (store.user.name = 'Bob')}>rename</button>
57+
</>
58+
)
59+
}
60+
61+
render(
62+
<StrictMode>
63+
<Profile />
64+
</StrictMode>,
65+
)
66+
67+
expect(screen.getByText('Alice (20)')).toBeInTheDocument()
68+
69+
fireEvent.click(screen.getByText('rename'))
70+
await act(() => vi.advanceTimersByTimeAsync(0))
71+
expect(screen.getByText('Bob (20)')).toBeInTheDocument()
72+
})
73+
74+
it('should handle multiple mutations in one handler', async () => {
75+
const state = proxy({ firstName: 'John', lastName: 'Doe' })
76+
77+
const Form = () => {
78+
const store = useProxy(state)
79+
return (
80+
<>
81+
<div>
82+
{store.firstName} {store.lastName}
83+
</div>
84+
<button
85+
onClick={() => {
86+
// eslint-disable-next-line react-hooks/immutability
87+
store.firstName = 'Jane'
88+
store.lastName = 'Smith'
89+
}}
90+
>
91+
update
92+
</button>
93+
</>
94+
)
95+
}
96+
97+
render(
98+
<StrictMode>
99+
<Form />
100+
</StrictMode>,
101+
)
102+
103+
expect(screen.getByText('John Doe')).toBeInTheDocument()
104+
105+
fireEvent.click(screen.getByText('update'))
106+
await act(() => vi.advanceTimersByTimeAsync(0))
107+
expect(screen.getByText('Jane Smith')).toBeInTheDocument()
108+
})
109+
110+
it('should work with sync option', async () => {
111+
const state = proxy({ count: 0 })
112+
113+
const Counter = () => {
114+
const store = useProxy(state, { sync: true })
115+
return (
116+
<>
117+
<div>count: {store.count}</div>
118+
{/* eslint-disable-next-line react-hooks/immutability */}
119+
<button onClick={() => ++store.count}>increment</button>
120+
</>
121+
)
122+
}
123+
124+
render(
125+
<StrictMode>
126+
<Counter />
127+
</StrictMode>,
128+
)
129+
130+
expect(screen.getByText('count: 0')).toBeInTheDocument()
131+
132+
fireEvent.click(screen.getByText('increment'))
133+
await act(() => vi.advanceTimersByTimeAsync(0))
134+
expect(screen.getByText('count: 1')).toBeInTheDocument()
135+
})
136+
})

0 commit comments

Comments
 (0)