1
- import { renderHook , waitFor } from "@testing-library/react" ;
1
+ import { configure , renderHook , waitFor } from "@testing-library/react" ;
2
2
import { newPromise , newSymbol } from "../__testfixtures__/index.js" ;
3
3
import { useGet } from "./useGet.js" ;
4
- import { it , expect , beforeEach , describe , vi } from "vitest" ;
4
+ import { it , expect , beforeEach , describe , vi , afterEach } from "vitest" ;
5
5
6
6
const result1 = newSymbol < string > ( "Result 1" ) ;
7
7
const result2 = newSymbol < string > ( "Result 2" ) ;
8
- const error = newSymbol ( "Error" ) ;
8
+ const error1 = newSymbol ( "Error 1" ) ;
9
+ const error2 = newSymbol ( "Error 2" ) ;
9
10
10
11
const refA1 = newSymbol ( "Ref A1" ) ;
11
12
const refA2 = newSymbol ( "Ref A2" ) ;
12
13
13
14
const refB1 = newSymbol ( "Ref B1" ) ;
14
15
const refB2 = newSymbol ( "Ref B2" ) ;
15
16
16
- const getData = vi . fn ( ) ;
17
17
const isEqual = ( a : unknown , b : unknown ) =>
18
18
[ a , b ] . every ( ( x ) => [ refA1 , refA2 ] . includes ( x ) ) || [ a , b ] . every ( ( x ) => [ refB1 , refB2 ] . includes ( x ) ) ;
19
19
20
- beforeEach ( ( ) => {
21
- vi . resetAllMocks ( ) ;
20
+ afterEach ( ( ) => {
21
+ configure ( { reactStrictMode : false } ) ;
22
22
} ) ;
23
23
24
- describe ( "initial state" , ( ) => {
25
- it ( "defined reference" , ( ) => {
26
- getData . mockReturnValue ( new Promise ( ( ) => { } ) ) ;
27
- const { result } = renderHook ( ( ) => useGet ( refA1 , getData , isEqual ) ) ;
28
- expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
29
- } ) ;
24
+ describe . each ( [ { reactStrictMode : true } , { reactStrictMode : false } ] ) (
25
+ `strictMode=$reactStrictMode` ,
26
+ ( { reactStrictMode } ) => {
27
+ beforeEach ( ( ) => {
28
+ configure ( { reactStrictMode } ) ;
29
+ } ) ;
30
30
31
- it ( "undefined reference" , ( ) => {
32
- const { result } = renderHook ( ( ) => useGet ( undefined , getData , isEqual ) ) ;
33
- expect ( result . current ) . toStrictEqual ( [ undefined , false , undefined ] ) ;
34
- } ) ;
35
- } ) ;
31
+ describe ( "initial state" , ( ) => {
32
+ it ( "defined reference" , ( ) => {
33
+ const getData = vi . fn ( ) . mockReturnValue ( new Promise ( ( ) => { } ) ) ;
34
+ const { result } = renderHook ( ( ) => useGet ( refA1 , getData , isEqual ) ) ;
35
+ expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
36
+ } ) ;
37
+
38
+ it ( "undefined reference" , ( ) => {
39
+ const getData = vi . fn ( ) ;
40
+ const { result } = renderHook ( ( ) => useGet ( undefined , getData , isEqual ) ) ;
41
+ expect ( result . current ) . toStrictEqual ( [ undefined , false , undefined ] ) ;
42
+ } ) ;
43
+ } ) ;
44
+ } ,
45
+ ) ;
36
46
37
47
describe ( "initial load" , ( ) => {
38
48
it ( "should return success result" , async ( ) => {
39
49
const { promise, resolve } = newPromise < string > ( ) ;
40
- getData . mockReturnValue ( promise ) ;
50
+ const getData = vi . fn ( ) . mockReturnValue ( promise ) ;
41
51
42
52
const { result } = renderHook ( ( ) => useGet ( refA1 , getData , isEqual ) ) ;
53
+
54
+ // initial state
43
55
expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
56
+
57
+ // resolve promise
44
58
resolve ( result1 ) ;
45
59
await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ result1 , false , undefined ] ) ) ;
46
60
} ) ;
47
61
48
62
it ( "should return error result" , async ( ) => {
49
63
const { promise, reject } = newPromise < string > ( ) ;
50
- getData . mockReturnValue ( promise ) ;
64
+ const getData = vi . fn ( ) . mockReturnValue ( promise ) ;
51
65
52
66
const { result } = renderHook ( ( ) => useGet ( refA1 , getData , isEqual ) ) ;
67
+
68
+ // initial state
53
69
expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
54
- reject ( error ) ;
55
- await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , false , error ] ) ) ;
70
+
71
+ // reject promise
72
+ reject ( error1 ) ;
73
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , false , error1 ] ) ) ;
56
74
} ) ;
57
75
} ) ;
58
76
59
77
describe ( "when ref changes" , ( ) => {
60
78
describe ( "to equal ref" , ( ) => {
61
79
it ( "should not update success result" , async ( ) => {
62
- getData . mockResolvedValueOnce ( result1 ) ;
80
+ const getData = vi . fn ( ) . mockResolvedValueOnce ( result1 ) ;
63
81
64
82
const { result, rerender } = renderHook ( ( { ref } ) => useGet ( ref , getData , isEqual ) , {
65
83
initialProps : { ref : refA1 } ,
66
84
} ) ;
67
85
86
+ // initial state
68
87
expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
69
88
await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ result1 , false , undefined ] ) ) ;
70
89
expect ( getData ) . toHaveBeenCalledTimes ( 1 ) ;
71
90
91
+ // change ref
72
92
rerender ( { ref : refA2 } ) ;
73
93
expect ( result . current ) . toStrictEqual ( [ result1 , false , undefined ] ) ;
74
94
expect ( getData ) . toHaveBeenCalledTimes ( 1 ) ;
75
95
} ) ;
76
96
77
97
it ( "should not update error result" , async ( ) => {
78
- getData . mockRejectedValueOnce ( error ) ;
98
+ const getData = vi . fn ( ) . mockRejectedValueOnce ( error1 ) ;
79
99
80
100
const { result, rerender } = renderHook ( ( { ref } ) => useGet ( ref , getData , isEqual ) , {
81
101
initialProps : { ref : refA1 } ,
82
102
} ) ;
83
103
104
+ // initial state
84
105
expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
85
- await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , false , error ] ) ) ;
106
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , false , error1 ] ) ) ;
86
107
expect ( getData ) . toHaveBeenCalledTimes ( 1 ) ;
87
108
109
+ // change ref
88
110
rerender ( { ref : refA2 } ) ;
89
- expect ( result . current ) . toStrictEqual ( [ undefined , false , error ] ) ;
111
+ expect ( result . current ) . toStrictEqual ( [ undefined , false , error1 ] ) ;
90
112
expect ( getData ) . toHaveBeenCalledTimes ( 1 ) ;
91
113
} ) ;
92
114
} ) ;
93
115
94
116
describe ( "to unequal ref" , ( ) => {
95
117
it ( "should update success result" , async ( ) => {
96
- getData . mockResolvedValueOnce ( result1 ) . mockResolvedValueOnce ( result2 ) ;
118
+ const getData = vi . fn ( ) . mockResolvedValueOnce ( result1 ) . mockResolvedValueOnce ( result2 ) ;
97
119
98
120
const { result, rerender } = renderHook ( ( { ref } ) => useGet ( ref , getData , isEqual ) , {
99
121
initialProps : { ref : refA1 } ,
100
122
} ) ;
101
123
124
+ // initial state
102
125
expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
103
126
expect ( getData ) . toHaveBeenCalledTimes ( 1 ) ;
104
127
await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ result1 , false , undefined ] ) ) ;
105
128
129
+ // change ref
106
130
rerender ( { ref : refB1 } ) ;
107
131
expect ( getData ) . toHaveBeenCalledTimes ( 2 ) ;
108
132
await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ result2 , false , undefined ] ) ) ;
109
133
} ) ;
110
134
111
135
it ( "should update error result" , async ( ) => {
112
- getData . mockRejectedValueOnce ( error ) . mockResolvedValueOnce ( result2 ) ;
136
+ const getData = vi . fn ( ) . mockRejectedValueOnce ( error1 ) . mockResolvedValueOnce ( result2 ) ;
113
137
114
138
const { result, rerender } = renderHook ( ( { ref } ) => useGet ( ref , getData , isEqual ) , {
115
139
initialProps : { ref : refA1 } ,
116
140
} ) ;
117
141
142
+ // initial state
118
143
expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
119
144
expect ( getData ) . toHaveBeenCalledTimes ( 1 ) ;
120
- await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , false , error ] ) ) ;
145
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , false , error1 ] ) ) ;
121
146
147
+ // change ref
122
148
rerender ( { ref : refB1 } ) ;
123
149
expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ;
124
150
expect ( getData ) . toHaveBeenCalledTimes ( 2 ) ;
125
151
await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ result2 , false , undefined ] ) ) ;
126
152
} ) ;
153
+
154
+ describe ( "if changed before first `getData` is settled" , ( ) => {
155
+ it ( "should ignore the first result" , async ( ) => {
156
+ const { promise : promise1 , resolve : resolve1 } = newPromise < string > ( ) ;
157
+ const { promise : promise2 , resolve : resolve2 } = newPromise < string > ( ) ;
158
+ const getData = vi . fn ( ) . mockReturnValueOnce ( promise1 ) . mockReturnValueOnce ( promise2 ) ;
159
+
160
+ const { result, rerender } = renderHook ( ( { ref } ) => useGet ( ref , getData , isEqual ) , {
161
+ initialProps : { ref : refA1 } ,
162
+ } ) ;
163
+
164
+ // initial state
165
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ) ;
166
+
167
+ // change ref
168
+ rerender ( { ref : refB1 } ) ;
169
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ) ;
170
+
171
+ // first promise resolves
172
+ resolve1 ( result1 ) ;
173
+
174
+ // ensure that the first result is ignored
175
+ await expect (
176
+ waitFor (
177
+ ( ) => {
178
+ expect ( result . current ) . toStrictEqual ( [ result1 , false , undefined ] ) ;
179
+ } ,
180
+ { timeout : 200 } ,
181
+ ) ,
182
+ ) . rejects . toThrow ( ) ;
183
+
184
+ // second promise resolves
185
+ resolve2 ( result2 ) ;
186
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ result2 , false , undefined ] ) ) ;
187
+ } ) ;
188
+
189
+ it ( "should ignore the first thrown error" , async ( ) => {
190
+ const { promise : promise1 , reject : reject1 } = newPromise < string > ( ) ;
191
+ const { promise : promise2 , reject : reject2 } = newPromise < string > ( ) ;
192
+ const getData = vi . fn ( ) . mockReturnValueOnce ( promise1 ) . mockReturnValueOnce ( promise2 ) ;
193
+
194
+ const { result, rerender } = renderHook ( ( { ref } ) => useGet ( ref , getData , isEqual ) , {
195
+ initialProps : { ref : refA1 } ,
196
+ } ) ;
197
+
198
+ // initial state
199
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ) ;
200
+
201
+ // change ref
202
+ rerender ( { ref : refB1 } ) ;
203
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , true , undefined ] ) ) ;
204
+
205
+ // first promise rejects
206
+ reject1 ( error1 ) ;
207
+
208
+ // ensure that the first result is ignored
209
+ await expect (
210
+ waitFor (
211
+ ( ) => {
212
+ expect ( result . current ) . toStrictEqual ( [ undefined , false , error1 ] ) ;
213
+ } ,
214
+ { timeout : 200 } ,
215
+ ) ,
216
+ ) . rejects . toThrow ( ) ;
217
+
218
+ // second promise rejects
219
+ reject2 ( error2 ) ;
220
+ await waitFor ( ( ) => expect ( result . current ) . toStrictEqual ( [ undefined , false , error2 ] ) ) ;
221
+ } ) ;
222
+ } ) ;
127
223
} ) ;
128
224
} ) ;
129
225
@@ -135,13 +231,14 @@ it("refetches if `getData` changes", async () => {
135
231
initialProps : { getData : getData1 } ,
136
232
} ) ;
137
233
234
+ // initial state
138
235
await waitFor ( ( ) => {
139
236
expect ( result . current ) . toStrictEqual ( [ result1 , false , undefined ] ) ;
140
237
} ) ;
141
238
expect ( getData1 ) . toHaveBeenCalledTimes ( 1 ) ;
142
239
240
+ // changing `getData`
143
241
rerender ( { getData : getData2 } ) ;
144
-
145
242
await waitFor ( ( ) => {
146
243
expect ( result . current ) . toStrictEqual ( [ result2 , false , undefined ] ) ;
147
244
} ) ;
0 commit comments