Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c7a2e97

Browse files
authored
fix(types): fix cleanup return type to match async implementation
* fix(types): fix `cleanup` return type to match `async` implementation * test: refactor tests to reduce duplication for different renderers * test: refactor `hydratedServerRenderer` and added comment for clarity about it
1 parent eff2ca6 commit c7a2e97

File tree

95 files changed

+1525
-3674
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+1525
-3674
lines changed

‎jest.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const { jest: jestConfig } = require('kcd-scripts/config')
2+
module.exports = Object.assign(jestConfig, {
3+
setupFiles: ['<rootDir>/src/__tests__/utils/runForRenderers.ts']
4+
})

‎src/__tests__/asyncHook.test.ts

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
import { useState, useRef, useEffect } from 'react'
2+
3+
describe('async hook tests', () => {
4+
const useSequence = (values: string[], intervalMs = 50) => {
5+
const [first, ...otherValues] = values
6+
const [value, setValue] = useState(() => first)
7+
const index = useRef(0)
8+
9+
useEffect(() => {
10+
const interval = setInterval(() => {
11+
setValue(otherValues[index.current++])
12+
if (index.current >= otherValues.length) {
13+
clearInterval(interval)
14+
}
15+
}, intervalMs)
16+
return () => {
17+
clearInterval(interval)
18+
}
19+
// eslint-disable-next-line react-hooks/exhaustive-deps
20+
}, otherValues)
21+
22+
return value
23+
}
24+
25+
runForRenderers(['default', 'dom', 'native', 'server/hydrated'], ({ renderHook }) => {
26+
test('should wait for next update', async () => {
27+
const { result, waitForNextUpdate } = renderHook(() => useSequence(['first', 'second']))
28+
29+
expect(result.current).toBe('first')
30+
31+
await waitForNextUpdate()
32+
33+
expect(result.current).toBe('second')
34+
})
35+
36+
test('should wait for multiple updates', async () => {
37+
const { result, waitForNextUpdate } = renderHook(() =>
38+
useSequence(['first', 'second', 'third'])
39+
)
40+
41+
expect(result.current).toBe('first')
42+
43+
await waitForNextUpdate()
44+
45+
expect(result.current).toBe('second')
46+
47+
await waitForNextUpdate()
48+
49+
expect(result.current).toBe('third')
50+
})
51+
52+
test('should reject if timeout exceeded when waiting for next update', async () => {
53+
const { result, waitForNextUpdate } = renderHook(() => useSequence(['first', 'second']))
54+
55+
expect(result.current).toBe('first')
56+
57+
await expect(waitForNextUpdate({ timeout: 10 })).rejects.toThrow(
58+
Error('Timed out in waitForNextUpdate after 10ms.')
59+
)
60+
})
61+
62+
test('should not reject when waiting for next update if timeout has been disabled', async () => {
63+
const { result, waitForNextUpdate } = renderHook(() => useSequence(['first', 'second'], 1100))
64+
65+
expect(result.current).toBe('first')
66+
67+
await waitForNextUpdate({ timeout: false })
68+
69+
expect(result.current).toBe('second')
70+
})
71+
72+
test('should wait for expectation to pass', async () => {
73+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
74+
75+
expect(result.current).toBe('first')
76+
77+
let complete = false
78+
await waitFor(() => {
79+
expect(result.current).toBe('third')
80+
complete = true
81+
})
82+
expect(complete).toBe(true)
83+
})
84+
85+
test('should wait for arbitrary expectation to pass', async () => {
86+
const { waitFor } = renderHook(() => null)
87+
88+
let actual = 0
89+
const expected = 1
90+
91+
setTimeout(() => {
92+
actual = expected
93+
}, 200)
94+
95+
let complete = false
96+
await waitFor(() => {
97+
expect(actual).toBe(expected)
98+
complete = true
99+
})
100+
101+
expect(complete).toBe(true)
102+
})
103+
104+
test('should not hang if expectation is already passing', async () => {
105+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second']))
106+
107+
expect(result.current).toBe('first')
108+
109+
let complete = false
110+
await waitFor(() => {
111+
expect(result.current).toBe('first')
112+
complete = true
113+
})
114+
expect(complete).toBe(true)
115+
})
116+
117+
test('should wait for truthy value', async () => {
118+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
119+
120+
expect(result.current).toBe('first')
121+
122+
await waitFor(() => result.current === 'third')
123+
124+
expect(result.current).toBe('third')
125+
})
126+
127+
test('should wait for arbitrary truthy value', async () => {
128+
const { waitFor } = renderHook(() => null)
129+
130+
let actual = 0
131+
const expected = 1
132+
133+
setTimeout(() => {
134+
actual = expected
135+
}, 200)
136+
137+
await waitFor(() => actual === 1)
138+
139+
expect(actual).toBe(expected)
140+
})
141+
142+
test('should reject if timeout exceeded when waiting for expectation to pass', async () => {
143+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
144+
145+
expect(result.current).toBe('first')
146+
147+
await expect(
148+
waitFor(
149+
() => {
150+
expect(result.current).toBe('third')
151+
},
152+
{ timeout: 75 }
153+
)
154+
).rejects.toThrow(Error('Timed out in waitFor after 75ms.'))
155+
})
156+
157+
test('should not reject when waiting for expectation to pass if timeout has been disabled', async () => {
158+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third'], 550))
159+
160+
expect(result.current).toBe('first')
161+
162+
await waitFor(
163+
() => {
164+
expect(result.current).toBe('third')
165+
},
166+
{ timeout: false }
167+
)
168+
169+
expect(result.current).toBe('third')
170+
})
171+
172+
test('should check on interval when waiting for expectation to pass', async () => {
173+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
174+
175+
let checks = 0
176+
177+
await waitFor(
178+
() => {
179+
checks++
180+
return result.current === 'third'
181+
},
182+
{ interval: 100 }
183+
)
184+
185+
expect(checks).toBe(3)
186+
})
187+
188+
test('should wait for value to change', async () => {
189+
const { result, waitForValueToChange } = renderHook(() =>
190+
useSequence(['first', 'second', 'third'])
191+
)
192+
193+
expect(result.current).toBe('first')
194+
195+
await waitForValueToChange(() => result.current === 'third')
196+
197+
expect(result.current).toBe('third')
198+
})
199+
200+
test('should wait for arbitrary value to change', async () => {
201+
const { waitForValueToChange } = renderHook(() => null)
202+
203+
let actual = 0
204+
const expected = 1
205+
206+
setTimeout(() => {
207+
actual = expected
208+
}, 200)
209+
210+
await waitForValueToChange(() => actual)
211+
212+
expect(actual).toBe(expected)
213+
})
214+
215+
test('should reject if timeout exceeded when waiting for value to change', async () => {
216+
const { result, waitForValueToChange } = renderHook(() =>
217+
useSequence(['first', 'second', 'third'])
218+
)
219+
220+
expect(result.current).toBe('first')
221+
222+
await expect(
223+
waitForValueToChange(() => result.current === 'third', {
224+
timeout: 75
225+
})
226+
).rejects.toThrow(Error('Timed out in waitForValueToChange after 75ms.'))
227+
})
228+
229+
test('should not reject when waiting for value to change if timeout is disabled', async () => {
230+
const { result, waitForValueToChange } = renderHook(() =>
231+
useSequence(['first', 'second', 'third'], 550)
232+
)
233+
234+
expect(result.current).toBe('first')
235+
236+
await waitForValueToChange(() => result.current === 'third', {
237+
timeout: false
238+
})
239+
240+
expect(result.current).toBe('third')
241+
})
242+
243+
test('should reject if selector throws error', async () => {
244+
const { result, waitForValueToChange } = renderHook(() => useSequence(['first', 'second']))
245+
246+
expect(result.current).toBe('first')
247+
248+
await expect(
249+
waitForValueToChange(() => {
250+
if (result.current === 'second') {
251+
throw new Error('Something Unexpected')
252+
}
253+
return result.current
254+
})
255+
).rejects.toThrow(Error('Something Unexpected'))
256+
})
257+
})
258+
})
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useEffect } from 'react'
2+
3+
// This verifies that if RHTL_SKIP_AUTO_CLEANUP is set
4+
// then we DON'T auto-wire up the afterEach for folks
5+
describe('skip auto cleanup (disabled) tests', () => {
6+
process.env.RHTL_SKIP_AUTO_CLEANUP = 'true'
7+
8+
runForRenderers(['default', 'dom', 'native', 'server/hydrated'], ({ renderHook }) => {
9+
let cleanupCalled = false
10+
11+
test('first', () => {
12+
const useHookWithCleanup = () => {
13+
useEffect(() => {
14+
return () => {
15+
cleanupCalled = true
16+
}
17+
})
18+
}
19+
renderHook(() => useHookWithCleanup())
20+
})
21+
22+
test('second', () => {
23+
expect(cleanupCalled).toBe(false)
24+
})
25+
})
26+
})
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useEffect } from 'react'
2+
3+
// This verifies that if afterEach is unavailable
4+
// then we DON'T auto-wire up the afterEach for folks
5+
describe('skip auto cleanup (no afterEach) tests', () => {
6+
// @ts-expect-error Turning off AfterEach -- ignore Jest LifeCycle Type
7+
// eslint-disable-next-line no-global-assign
8+
afterEach = false
9+
10+
runForRenderers(['default', 'dom', 'native', 'server/hydrated'], ({ renderHook }) => {
11+
let cleanupCalled = false
12+
13+
test('first', () => {
14+
const useHookWithCleanup = () => {
15+
useEffect(() => {
16+
return () => {
17+
cleanupCalled = true
18+
}
19+
})
20+
}
21+
renderHook(() => useHookWithCleanup())
22+
})
23+
24+
test('second', () => {
25+
expect(cleanupCalled).toBe(false)
26+
})
27+
})
28+
})
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useEffect } from 'react'
2+
3+
// This verifies that if process.env is unavailable
4+
// then we still auto-wire up the afterEach for folks
5+
describe('auto cleanup (no process.env) tests', () => {
6+
process.env = {
7+
...process.env,
8+
get RHTL_SKIP_AUTO_CLEANUP(): string | undefined {
9+
throw new Error('expected')
10+
}
11+
}
12+
13+
runForRenderers(['default', 'dom', 'native', 'server/hydrated'], ({ renderHook }) => {
14+
let cleanupCalled = false
15+
16+
test('first', () => {
17+
const useHookWithCleanup = () => {
18+
useEffect(() => {
19+
return () => {
20+
cleanupCalled = true
21+
}
22+
})
23+
}
24+
renderHook(() => useHookWithCleanup())
25+
})
26+
27+
test('second', () => {
28+
expect(cleanupCalled).toBe(true)
29+
})
30+
})
31+
})

‎src/__tests__/autoCleanup.pure.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useEffect } from 'react'
2+
3+
// This verifies that if pure imports are used
4+
// then we DON'T auto-wire up the afterEach for folks
5+
describe('skip auto cleanup (pure) tests', () => {
6+
runForRenderers(
7+
['default/pure', 'dom/pure', 'native/pure', 'server/hydrated/pure'],
8+
({ renderHook }) => {
9+
let cleanupCalled = false
10+
11+
test('first', () => {
12+
const useHookWithCleanup = () => {
13+
useEffect(() => {
14+
return () => {
15+
cleanupCalled = true
16+
}
17+
})
18+
}
19+
renderHook(() => useHookWithCleanup())
20+
})
21+
22+
test('second', () => {
23+
expect(cleanupCalled).toBe(false)
24+
})
25+
}
26+
)
27+
})

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /