4
4
5
5
import React from "react" ;
6
6
import ReactDom from "react-dom" ;
7
- import { render , fireEvent , wait } from "@testing-library/react" ;
7
+ import { render , fireEvent , waitFor } from "@testing-library/react" ;
8
8
9
9
import withHydrationOnDemand from "../../src" ;
10
10
@@ -14,6 +14,18 @@ const clientSideText = "some content client side";
14
14
15
15
const SSRhtml = `<section data-hydration-on-demand="true"><div class="label">${ serverSideText } </div></section>` ;
16
16
17
+ const originalRequestIdleCallback = window . requestIdleCallback ;
18
+ const originalCancelIdleCallback = window . cancelIdleCallback ;
19
+ const originalIntersectionObserver = window . IntersectionObserver ;
20
+ const originalClearTimeout = window . clearTimeout ;
21
+
22
+ beforeEach ( ( ) => {
23
+ window . requestIdleCallback = originalRequestIdleCallback ;
24
+ window . cancelIdleCallback = originalCancelIdleCallback ;
25
+ window . IntersectionObserver = originalIntersectionObserver ;
26
+ window . clearTimeout = originalClearTimeout ;
27
+ } ) ;
28
+
17
29
describe ( "With SSR" , ( ) => {
18
30
test ( "Render correctly client side, no option " , ( ) => {
19
31
const elem = document . createElement ( "div" ) ;
@@ -27,7 +39,7 @@ describe("With SSR", () => {
27
39
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
28
40
{
29
41
container : elem ,
30
- hydrate : true
42
+ hydrate : true ,
31
43
}
32
44
) ;
33
45
@@ -39,18 +51,18 @@ describe("With SSR", () => {
39
51
elem . innerHTML = SSRhtml ;
40
52
41
53
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
42
- on : [ [ "delay" , 1000 ] ]
54
+ on : [ [ "delay" , 200 ] ] ,
43
55
} ) ( Component ) ;
44
56
45
57
const { getByText } = render (
46
58
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
47
59
{
48
60
container : elem ,
49
- hydrate : true
61
+ hydrate : true ,
50
62
}
51
63
) ;
52
64
53
- await wait ( ( ) => getByText ( clientSideText ) ) ;
65
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
54
66
55
67
expect ( elem ) . toMatchSnapshot ( ) ;
56
68
} ) ;
@@ -60,20 +72,20 @@ describe("With SSR", () => {
60
72
elem . innerHTML = SSRhtml ;
61
73
62
74
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
63
- on : [ "click" ]
75
+ on : [ "click" ] ,
64
76
} ) ( Component ) ;
65
77
66
78
const { getByText } = render (
67
79
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
68
80
{
69
81
container : elem ,
70
- hydrate : true
82
+ hydrate : true ,
71
83
}
72
84
) ;
73
85
74
86
fireEvent . click ( getByText ( serverSideText ) ) ;
75
87
76
- await wait ( ( ) => getByText ( clientSideText ) ) ;
88
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
77
89
78
90
expect ( elem ) . toMatchSnapshot ( ) ;
79
91
} ) ;
@@ -83,46 +95,49 @@ describe("With SSR", () => {
83
95
elem . innerHTML = SSRhtml ;
84
96
85
97
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
86
- on : [ [ "click" , ( ) => elem ] ]
98
+ on : [ [ "click" , ( ) => elem ] ] ,
87
99
} ) ( Component ) ;
88
100
89
101
const { getByText } = render (
90
102
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
91
103
{
92
104
container : elem ,
93
- hydrate : true
105
+ hydrate : true ,
94
106
}
95
107
) ;
96
108
109
+ elem . removeEventListener = jest . fn ( ) ;
97
110
fireEvent . click ( elem ) ;
98
111
99
- await wait ( ( ) => getByText ( clientSideText ) ) ;
112
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
100
113
101
114
expect ( elem ) . toMatchSnapshot ( ) ;
115
+ expect ( elem . removeEventListener ) . toHaveBeenCalled ( ) ;
102
116
} ) ;
103
117
104
118
test ( "Render correctly client side, on idle" , async ( ) => {
105
119
const elem = document . createElement ( "div" ) ;
106
120
elem . innerHTML = SSRhtml ;
107
121
108
- window . requestIdleCallback = jest . fn ( f => f ( ) ) ;
109
-
122
+ window . requestIdleCallback = jest . fn ( ( f ) => f ( ) ) ;
123
+ window . cancelIdleCallback = jest . fn ( ) ;
110
124
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
111
- on : [ "idle" ]
125
+ on : [ "idle" ] ,
112
126
} ) ( Component ) ;
113
127
114
128
const { getByText } = render (
115
129
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
116
130
{
117
131
container : elem ,
118
- hydrate : true
132
+ hydrate : true ,
119
133
}
120
134
) ;
121
135
122
- await wait ( ( ) => getByText ( clientSideText ) ) ;
136
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
123
137
124
138
expect ( window . requestIdleCallback ) . toHaveBeenCalled ( ) ;
125
139
expect ( elem ) . toMatchSnapshot ( ) ;
140
+ expect ( window . cancelIdleCallback ) . toHaveBeenCalled ( ) ;
126
141
} ) ;
127
142
128
143
test ( "Render correctly client side, on idle, requestIdleCallback unsupported" , async ( ) => {
@@ -132,18 +147,18 @@ describe("With SSR", () => {
132
147
delete window . requestIdleCallback ;
133
148
134
149
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
135
- on : [ "idle" ]
150
+ on : [ "idle" ] ,
136
151
} ) ( Component ) ;
137
152
138
153
const { getByText } = render (
139
154
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
140
155
{
141
156
container : elem ,
142
- hydrate : true
157
+ hydrate : true ,
143
158
}
144
159
) ;
145
160
146
- await wait ( ( ) => getByText ( clientSideText ) ) ;
161
+ await waitFor ( ( ) => getByText ( clientSideText ) , { timeout : 3000 } ) ;
147
162
148
163
expect ( elem ) . toMatchSnapshot ( ) ;
149
164
} ) ;
@@ -155,18 +170,18 @@ describe("With SSR", () => {
155
170
delete window . IntersectionObserver ;
156
171
157
172
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
158
- on : [ "visible" ]
173
+ on : [ "visible" ] ,
159
174
} ) ( Component ) ;
160
175
161
176
const { getByText } = render (
162
177
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
163
178
{
164
179
container : elem ,
165
- hydrate : true
180
+ hydrate : true ,
166
181
}
167
182
) ;
168
183
169
- await wait ( ( ) => getByText ( clientSideText ) ) ;
184
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
170
185
171
186
expect ( elem ) . toMatchSnapshot ( ) ;
172
187
} ) ;
@@ -180,9 +195,13 @@ describe("With SSR", () => {
180
195
const getOptions = jest . fn ( ) ;
181
196
window . IntersectionObserver = class IntersectionObserver {
182
197
constructor ( cb ) {
183
- cb ( [ { isIntersecting : false , intersectionRatio : 0 } ] , this ) ;
198
+ this . cb = cb ;
184
199
}
185
200
observe ( ) {
201
+ this . cb (
202
+ [ { isIntersecting : false , intersectionRatio : 0 } ] ,
203
+ this
204
+ ) ;
186
205
return observe ( ) ;
187
206
}
188
207
disconnect ( ) {
@@ -191,14 +210,14 @@ describe("With SSR", () => {
191
210
} ;
192
211
193
212
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
194
- on : [ [ "visible" , getOptions ] ]
213
+ on : [ [ "visible" , getOptions ] ] ,
195
214
} ) ( Component ) ;
196
215
197
216
render (
198
217
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
199
218
{
200
219
container : elem ,
201
- hydrate : true
220
+ hydrate : true ,
202
221
}
203
222
) ;
204
223
@@ -216,9 +235,13 @@ describe("With SSR", () => {
216
235
const getOptions = jest . fn ( ) ;
217
236
window . IntersectionObserver = class IntersectionObserver {
218
237
constructor ( cb ) {
219
- cb ( [ { isIntersecting : true , intersectionRatio : 0.5 } ] , this ) ;
238
+ this . cb = cb ;
220
239
}
221
240
observe ( ) {
241
+ this . cb (
242
+ [ { isIntersecting : true , intersectionRatio : 0.5 } ] ,
243
+ this
244
+ ) ;
222
245
return observe ( ) ;
223
246
}
224
247
disconnect ( ) {
@@ -227,24 +250,22 @@ describe("With SSR", () => {
227
250
} ;
228
251
229
252
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
230
- on : [ [ "visible" , getOptions ] ]
253
+ on : [ [ "visible" , getOptions ] ] ,
231
254
} ) ( Component ) ;
232
255
233
256
const { getByText } = render (
234
257
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
235
258
{
236
259
container : elem ,
237
- hydrate : true
260
+ hydrate : true ,
238
261
}
239
262
) ;
240
263
241
264
expect ( observe ) . toHaveBeenCalled ( ) ;
242
265
expect ( getOptions ) . toHaveBeenCalled ( ) ;
243
-
244
- await wait ( ( ) => getByText ( clientSideText ) ) ;
245
-
246
- expect ( disconnect ) . toHaveBeenCalled ( ) ;
266
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
247
267
expect ( elem ) . toMatchSnapshot ( ) ;
268
+ expect ( disconnect ) . toHaveBeenCalled ( ) ;
248
269
} ) ;
249
270
250
271
test ( "Client side, execute onBefore before hydration" , async ( ) => {
@@ -255,20 +276,20 @@ describe("With SSR", () => {
255
276
256
277
const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
257
278
on : [ "click" ] ,
258
- onBefore
279
+ onBefore,
259
280
} ) ( Component ) ;
260
281
261
282
const { getByText } = render (
262
283
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
263
284
{
264
285
container : elem ,
265
- hydrate : true
286
+ hydrate : true ,
266
287
}
267
288
) ;
268
289
269
290
fireEvent . click ( getByText ( serverSideText ) ) ;
270
291
271
- await wait ( ( ) => getByText ( clientSideText ) ) ;
292
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
272
293
273
294
expect ( onBefore ) . toHaveBeenCalled ( ) ;
274
295
} ) ;
@@ -288,14 +309,50 @@ describe("With SSR", () => {
288
309
/> ,
289
310
{
290
311
container : elem ,
291
- hydrate : true
312
+ hydrate : true ,
292
313
}
293
314
) ;
294
315
295
- await wait ( ( ) => getByText ( clientSideText ) ) ;
316
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
296
317
297
318
expect ( elem ) . toMatchSnapshot ( ) ;
298
319
} ) ;
320
+
321
+ test ( "Clean functions called on component unmount" , async ( ) => {
322
+ const elem = document . createElement ( "div" ) ;
323
+ elem . innerHTML = SSRhtml ;
324
+
325
+ elem . removeEventListener = jest . fn ( ) ;
326
+ window . requestIdleCallback = jest . fn ( Function . prototype ) ;
327
+ window . cancelIdleCallback = jest . fn ( ) ;
328
+ window . clearTimeout = jest . fn ( ) ;
329
+ const disconnect = jest . fn ( ) ;
330
+ window . IntersectionObserver = class IntersectionObserver {
331
+ constructor ( ) { }
332
+ observe ( ) { }
333
+ disconnect ( ) {
334
+ return disconnect ( ) ;
335
+ }
336
+ } ;
337
+
338
+ const ComponentWithHydrationOnDemandClient = withHydrationOnDemand ( {
339
+ on : [ "idle" , "delay" , "visible" , [ "click" , ( ) => elem ] ] ,
340
+ } ) ( Component ) ;
341
+
342
+ const { unmount } = render (
343
+ < ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
344
+ {
345
+ container : elem ,
346
+ hydrate : true ,
347
+ }
348
+ ) ;
349
+
350
+ unmount ( ) ;
351
+ expect ( window . cancelIdleCallback ) . toHaveBeenCalled ( ) ;
352
+ expect ( window . clearTimeout ) . toHaveBeenCalled ( ) ;
353
+ expect ( elem . removeEventListener ) . toHaveBeenCalled ( ) ;
354
+ expect ( disconnect ) . toHaveBeenCalled ( ) ;
355
+ } ) ;
299
356
} ) ;
300
357
301
358
describe ( "Without SSR" , ( ) => {
@@ -310,11 +367,11 @@ describe("Without SSR", () => {
310
367
< ComponentWithHydrationOnDemandClient label = { clientSideText } /> ,
311
368
{
312
369
container : elem ,
313
- hydrate : true
370
+ hydrate : true ,
314
371
}
315
372
) ;
316
373
317
- await wait ( ( ) => getByText ( clientSideText ) ) ;
374
+ await waitFor ( ( ) => getByText ( clientSideText ) ) ;
318
375
319
376
expect ( elem ) . toMatchSnapshot ( ) ;
320
377
} ) ;
0 commit comments