Skip to content

Commit 437f684

Browse files
committed
test(fake-timers): add more tests to test suite for fake timers
1 parent 4bad439 commit 437f684

File tree

1 file changed

+261
-8
lines changed

1 file changed

+261
-8
lines changed

src/__tests__/asyncHook.fakeTimers.test.ts

+261-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
1+
import { useState, useRef, useEffect } from 'react'
2+
13
describe('async hook (fake timers) 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+
225
beforeEach(() => {
326
jest.useFakeTimers()
427
})
@@ -54,9 +77,9 @@ describe('async hook (fake timers) tests', () => {
5477

5578
test('should waitFor arbitrary expectation to pass when fake timers are not advanced explicitly', async () => {
5679
const fn = jest.fn().mockReturnValueOnce(false).mockReturnValueOnce(true)
57-
80+
5881
const { waitFor } = renderHook(() => null)
59-
82+
6083
await waitFor(() => {
6184
expect(fn()).toBe(true)
6285
})
@@ -70,7 +93,7 @@ describe('async hook (fake timers) tests', () => {
7093

7194
setTimeout(() => {
7295
actual = expected
73-
}, 101)
96+
}, 30)
7497

7598
let complete = false
7699

@@ -80,14 +103,244 @@ describe('async hook (fake timers) tests', () => {
80103
expect(actual).toBe(expected)
81104
complete = true
82105
},
83-
{ timeout: 100, interval: 50 }
106+
{ timeout: 29, interval: 10 }
84107
)
85-
).rejects.toThrow(Error('Timed out in waitFor after 100ms.'))
108+
).rejects.toThrow(Error('Timed out in waitFor after 29ms.'))
86109

87110
expect(complete).toBe(false)
88111
})
112+
113+
test('should wait for next update', async () => {
114+
const { result, waitForNextUpdate } = renderHook(() => useSequence(['first', 'second']))
115+
116+
expect(result.current).toBe('first')
117+
118+
await waitForNextUpdate()
119+
120+
expect(result.current).toBe('second')
121+
})
122+
123+
test('should wait for multiple updates', async () => {
124+
const { result, waitForNextUpdate } = renderHook(() =>
125+
useSequence(['first', 'second', 'third'])
126+
)
127+
128+
expect(result.current).toBe('first')
129+
130+
await waitForNextUpdate()
131+
132+
expect(result.current).toBe('second')
133+
134+
await waitForNextUpdate()
135+
136+
expect(result.current).toBe('third')
137+
})
138+
139+
test('should reject if timeout exceeded when waiting for next update', async () => {
140+
const { result, waitForNextUpdate } = renderHook(() => useSequence(['first', 'second']))
141+
142+
expect(result.current).toBe('first')
143+
144+
await expect(waitForNextUpdate({ timeout: 10 })).rejects.toThrow(
145+
Error('Timed out in waitForNextUpdate after 10ms.')
146+
)
147+
})
148+
149+
// eslint-disable-next-line jest/no-disabled-tests
150+
test.skip('should not reject when waiting for next update if timeout has been disabled', async () => {
151+
const { result, waitForNextUpdate } = renderHook(() => useSequence(['first', 'second'], 1100))
152+
153+
expect(result.current).toBe('first')
154+
155+
await waitForNextUpdate({ timeout: false })
156+
157+
expect(result.current).toBe('second')
158+
})
159+
160+
test('should wait for expectation to pass', async () => {
161+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
162+
163+
expect(result.current).toBe('first')
164+
165+
let complete = false
166+
await waitFor(() => {
167+
expect(result.current).toBe('third')
168+
complete = true
169+
})
170+
expect(complete).toBe(true)
171+
})
172+
173+
test('should wait for arbitrary expectation to pass', async () => {
174+
const { waitFor } = renderHook(() => null)
175+
176+
let actual = 0
177+
const expected = 1
178+
179+
setTimeout(() => {
180+
actual = expected
181+
}, 200)
182+
183+
let complete = false
184+
await waitFor(() => {
185+
expect(actual).toBe(expected)
186+
complete = true
187+
})
188+
189+
expect(complete).toBe(true)
190+
})
191+
192+
test('should not hang if expectation is already passing', async () => {
193+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second']))
194+
195+
expect(result.current).toBe('first')
196+
197+
let complete = false
198+
await waitFor(() => {
199+
expect(result.current).toBe('first')
200+
complete = true
201+
})
202+
expect(complete).toBe(true)
203+
})
204+
205+
test('should wait for truthy value', async () => {
206+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
207+
208+
expect(result.current).toBe('first')
209+
210+
await waitFor(() => result.current === 'third')
211+
212+
expect(result.current).toBe('third')
213+
})
214+
215+
test('should wait for arbitrary truthy value', async () => {
216+
const { waitFor } = renderHook(() => null)
217+
218+
let actual = 0
219+
const expected = 1
220+
221+
setTimeout(() => {
222+
actual = expected
223+
}, 200)
224+
225+
await waitFor(() => actual === 1)
226+
227+
expect(actual).toBe(expected)
228+
})
229+
230+
test('should reject if timeout exceeded when waiting for expectation to pass', async () => {
231+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
232+
233+
expect(result.current).toBe('first')
234+
235+
await expect(
236+
waitFor(
237+
() => {
238+
expect(result.current).toBe('third')
239+
},
240+
{ timeout: 75 }
241+
)
242+
).rejects.toThrow(Error('Timed out in waitFor after 75ms.'))
243+
})
244+
245+
test('should not reject when waiting for expectation to pass if timeout has been disabled', async () => {
246+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third'], 550))
247+
248+
expect(result.current).toBe('first')
249+
250+
await waitFor(
251+
() => {
252+
expect(result.current).toBe('third')
253+
},
254+
{ timeout: false }
255+
)
256+
257+
expect(result.current).toBe('third')
258+
})
259+
260+
test('should check on interval when waiting for expectation to pass', async () => {
261+
const { result, waitFor } = renderHook(() => useSequence(['first', 'second', 'third']))
262+
263+
let checks = 0
264+
265+
await waitFor(
266+
() => {
267+
checks++
268+
return result.current === 'third'
269+
},
270+
{ interval: 100 }
271+
)
272+
273+
expect(checks).toBe(3)
274+
})
275+
276+
test('should wait for value to change', async () => {
277+
const { result, waitForValueToChange } = renderHook(() =>
278+
useSequence(['first', 'second', 'third'])
279+
)
280+
281+
expect(result.current).toBe('first')
282+
283+
await waitForValueToChange(() => result.current === 'third')
284+
285+
expect(result.current).toBe('third')
286+
})
287+
288+
test('should wait for arbitrary value to change', async () => {
289+
const { waitForValueToChange } = renderHook(() => null)
290+
291+
let actual = 0
292+
const expected = 1
293+
294+
setTimeout(() => {
295+
actual = expected
296+
}, 200)
297+
298+
await waitForValueToChange(() => actual)
299+
300+
expect(actual).toBe(expected)
301+
})
302+
303+
test('should reject if timeout exceeded when waiting for value to change', async () => {
304+
const { result, waitForValueToChange } = renderHook(() =>
305+
useSequence(['first', 'second', 'third'])
306+
)
307+
308+
expect(result.current).toBe('first')
309+
310+
await expect(
311+
waitForValueToChange(() => result.current === 'third', {
312+
timeout: 75
313+
})
314+
).rejects.toThrow(Error('Timed out in waitForValueToChange after 75ms.'))
315+
})
316+
317+
test('should not reject when waiting for value to change if timeout is disabled', async () => {
318+
const { result, waitForValueToChange } = renderHook(() =>
319+
useSequence(['first', 'second', 'third'], 550)
320+
)
321+
322+
expect(result.current).toBe('first')
323+
324+
await waitForValueToChange(() => result.current === 'third', {
325+
timeout: false
326+
})
327+
328+
expect(result.current).toBe('third')
329+
})
330+
331+
test('should reject if selector throws error', async () => {
332+
const { result, waitForValueToChange } = renderHook(() => useSequence(['first', 'second']))
333+
334+
expect(result.current).toBe('first')
335+
336+
await expect(
337+
waitForValueToChange(() => {
338+
if (result.current === 'second') {
339+
throw new Error('Something Unexpected')
340+
}
341+
return result.current
342+
})
343+
).rejects.toThrow(Error('Something Unexpected'))
344+
})
89345
})
90346
})
91-
92-
// eslint-disable-next-line jest/no-export
93-
export {}

0 commit comments

Comments
 (0)