Skip to content

Commit a461f78

Browse files
committed
Merge branch 'main' into testMock
# Conflicts: # src/dom/__tests__/asyncHook.test.ts # src/native/__tests__/asyncHook.test.ts # src/server/__tests__/asyncHook.test.ts
2 parents cd60fa4 + a54eeb3 commit a461f78

File tree

98 files changed

+1596
-3850
lines changed

Some content is hidden

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

98 files changed

+1596
-3850
lines changed

.github/workflows/validate.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
runs-on: ubuntu-latest
2121
steps:
2222
- name: 🛑 Cancel Previous Runs
23-
uses: styfle/[email protected].0
23+
uses: styfle/[email protected].1
2424

2525
- name: ⬇️ Checkout repo
2626
uses: actions/checkout@v2
@@ -41,7 +41,7 @@ jobs:
4141
run: npm run validate
4242

4343
- name: ⬆️ Upload coverage report
44-
uses: codecov/codecov-action@v1
44+
uses: codecov/codecov-action@v2.0.2
4545

4646
release:
4747
needs: main
@@ -52,7 +52,7 @@ jobs:
5252
github.event_name == 'push' }}
5353
steps:
5454
- name: 🛑 Cancel Previous Runs
55-
uses: styfle/[email protected].0
55+
uses: styfle/[email protected].1
5656

5757
- name: ⬇️ Checkout repo
5858
uses: actions/checkout@v2

jest.config.js

+4
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+
})

package.json

+10-9
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,22 @@
5353
"react-error-boundary": "^3.1.0"
5454
},
5555
"devDependencies": {
56-
"@typescript-eslint/eslint-plugin": "^4.9.1",
57-
"@typescript-eslint/parser": "^4.9.1",
56+
"@typescript-eslint/eslint-plugin": "4.28.5",
57+
"@typescript-eslint/parser": "4.28.5",
5858
"all-contributors-cli": "6.20.0",
59-
"codecov": "3.8.2",
59+
"codecov": "3.8.3",
6060
"docz": "2.3.1",
6161
"docz-theme-default": "1.2.0",
6262
"docz-utils": "2.3.0",
63-
"eslint": "7.29.0",
64-
"kcd-scripts": "11.1.0",
65-
"prettier": "^2.2.1",
63+
"eslint": "7.31.0",
64+
"get-pkg-repo": "4.1.1",
65+
"kcd-scripts": "11.2.0",
66+
"prettier": "2.3.2",
6667
"react": "17.0.2",
67-
"react-dom": "^17.0.1",
68+
"react-dom": "17.0.2",
6869
"react-test-renderer": "17.0.2",
69-
"ts-node": "^10.0.0",
70-
"typescript": "4.3.4"
70+
"ts-node": "10.1.0",
71+
"typescript": "4.3.5"
7172
},
7273
"peerDependencies": {
7374
"react": ">=16.9.0",
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
describe('async hook (fake timers) tests', () => {
2+
beforeEach(() => {
3+
jest.useFakeTimers()
4+
})
5+
6+
afterEach(() => {
7+
jest.useRealTimers()
8+
})
9+
10+
runForRenderers(['default', 'dom', 'native', 'server/hydrated'], ({ renderHook }) => {
11+
test('should wait for arbitrary expectation to pass when using advanceTimersByTime()', async () => {
12+
const { waitFor } = renderHook(() => null)
13+
14+
let actual = 0
15+
const expected = 1
16+
17+
setTimeout(() => {
18+
actual = expected
19+
}, 200)
20+
21+
let complete = false
22+
23+
jest.advanceTimersByTime(200)
24+
25+
await waitFor(() => {
26+
expect(actual).toBe(expected)
27+
complete = true
28+
})
29+
30+
expect(complete).toBe(true)
31+
})
32+
33+
test('should wait for arbitrary expectation to pass when using runOnlyPendingTimers()', async () => {
34+
const { waitFor } = renderHook(() => null)
35+
36+
let actual = 0
37+
const expected = 1
38+
39+
setTimeout(() => {
40+
actual = expected
41+
}, 200)
42+
43+
let complete = false
44+
45+
jest.runOnlyPendingTimers()
46+
47+
await waitFor(() => {
48+
expect(actual).toBe(expected)
49+
complete = true
50+
})
51+
52+
expect(complete).toBe(true)
53+
})
54+
})
55+
})
56+
57+
// eslint-disable-next-line jest/no-export
58+
export {}

src/__tests__/asyncHook.test.ts

+258
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+
})

0 commit comments

Comments
 (0)