@wordpress/data 6.5.0 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/build/components/use-select/index.js +25 -32
- package/build/components/use-select/index.js.map +1 -1
- package/build/plugins/persistence/index.js +218 -13
- package/build/plugins/persistence/index.js.map +1 -1
- package/build/redux-store/index.js +42 -27
- package/build/redux-store/index.js.map +1 -1
- package/build/registry.js +10 -17
- package/build/registry.js.map +1 -1
- package/build-module/components/use-select/index.js +25 -32
- package/build-module/components/use-select/index.js.map +1 -1
- package/build-module/plugins/persistence/index.js +215 -14
- package/build-module/plugins/persistence/index.js.map +1 -1
- package/build-module/redux-store/index.js +42 -27
- package/build-module/redux-store/index.js.map +1 -1
- package/build-module/registry.js +10 -17
- package/build-module/registry.js.map +1 -1
- package/package.json +8 -8
- package/src/components/use-select/index.js +28 -36
- package/src/components/use-select/test/index.js +439 -265
- package/src/plugins/persistence/index.js +214 -19
- package/src/plugins/persistence/test/index.js +233 -3
- package/src/redux-store/index.js +23 -12
- package/src/redux-store/test/index.js +15 -5
- package/src/registry.js +10 -10
- package/src/test/registry.js +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
4
|
+
import { act, render } from '@testing-library/react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
@@ -11,10 +11,15 @@ import { useState, useReducer } from '@wordpress/element';
|
|
|
11
11
|
/**
|
|
12
12
|
* Internal dependencies
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
import {
|
|
15
|
+
createRegistry,
|
|
16
|
+
createRegistrySelector,
|
|
17
|
+
RegistryProvider,
|
|
18
|
+
AsyncModeProvider,
|
|
19
|
+
} from '../../..';
|
|
20
|
+
import useSelect from '..';
|
|
21
|
+
|
|
22
|
+
jest.useRealTimers();
|
|
18
23
|
|
|
19
24
|
describe( 'useSelect', () => {
|
|
20
25
|
let registry;
|
|
@@ -22,15 +27,6 @@ describe( 'useSelect', () => {
|
|
|
22
27
|
registry = createRegistry();
|
|
23
28
|
} );
|
|
24
29
|
|
|
25
|
-
const getTestComponent = ( mapSelectSpy, dependencyKey ) => ( props ) => {
|
|
26
|
-
const dependencies = props[ dependencyKey ];
|
|
27
|
-
mapSelectSpy.mockImplementation( ( select ) => ( {
|
|
28
|
-
results: select( 'testStore' ).testSelector( props.keyName ),
|
|
29
|
-
} ) );
|
|
30
|
-
const data = useSelect( mapSelectSpy, [ dependencies ] );
|
|
31
|
-
return <div>{ data.results }</div>;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
30
|
it( 'passes the relevant data to the component', () => {
|
|
35
31
|
registry.registerStore( 'testStore', {
|
|
36
32
|
reducer: () => ( { foo: 'bar' } ),
|
|
@@ -38,19 +34,22 @@ describe( 'useSelect', () => {
|
|
|
38
34
|
testSelector: ( state, key ) => state[ key ],
|
|
39
35
|
},
|
|
40
36
|
} );
|
|
37
|
+
|
|
41
38
|
const selectSpy = jest.fn();
|
|
42
|
-
const TestComponent = jest
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<RegistryProvider value={ registry }>
|
|
49
|
-
<TestComponent keyName="foo" />
|
|
50
|
-
</RegistryProvider>
|
|
51
|
-
);
|
|
39
|
+
const TestComponent = jest.fn( ( props ) => {
|
|
40
|
+
selectSpy.mockImplementation( ( select ) => ( {
|
|
41
|
+
results: select( 'testStore' ).testSelector( props.keyName ),
|
|
42
|
+
} ) );
|
|
43
|
+
const data = useSelect( selectSpy, [ props.keyName ] );
|
|
44
|
+
return <div role="status">{ data.results }</div>;
|
|
52
45
|
} );
|
|
53
|
-
|
|
46
|
+
|
|
47
|
+
const rendered = render(
|
|
48
|
+
<RegistryProvider value={ registry }>
|
|
49
|
+
<TestComponent keyName="foo" />
|
|
50
|
+
</RegistryProvider>
|
|
51
|
+
);
|
|
52
|
+
|
|
54
53
|
// 2 times expected
|
|
55
54
|
// - 1 for initial mount
|
|
56
55
|
// - 1 for after mount before subscription set.
|
|
@@ -58,9 +57,7 @@ describe( 'useSelect', () => {
|
|
|
58
57
|
expect( TestComponent ).toHaveBeenCalledTimes( 1 );
|
|
59
58
|
|
|
60
59
|
// Ensure expected state was rendered.
|
|
61
|
-
expect(
|
|
62
|
-
children: 'bar',
|
|
63
|
-
} );
|
|
60
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 'bar' );
|
|
64
61
|
} );
|
|
65
62
|
|
|
66
63
|
it( 'uses memoized selector if dependencies do not change', () => {
|
|
@@ -71,73 +68,62 @@ describe( 'useSelect', () => {
|
|
|
71
68
|
},
|
|
72
69
|
} );
|
|
73
70
|
|
|
74
|
-
const selectSpyFoo = jest.fn(
|
|
75
|
-
const selectSpyBar = jest.fn(
|
|
76
|
-
const TestComponent = jest.fn(
|
|
71
|
+
const selectSpyFoo = jest.fn( () => 'foo' );
|
|
72
|
+
const selectSpyBar = jest.fn( () => 'bar' );
|
|
73
|
+
const TestComponent = jest.fn( ( props ) => {
|
|
77
74
|
const mapSelect = props.change ? selectSpyFoo : selectSpyBar;
|
|
78
75
|
const data = useSelect( mapSelect, [ props.keyName ] );
|
|
79
|
-
return <div>{ data }</div>;
|
|
80
|
-
} );
|
|
81
|
-
let renderer;
|
|
82
|
-
act( () => {
|
|
83
|
-
renderer = TestRenderer.create(
|
|
84
|
-
<RegistryProvider value={ registry }>
|
|
85
|
-
<TestComponent keyName="foo" change={ true } />
|
|
86
|
-
</RegistryProvider>
|
|
87
|
-
);
|
|
76
|
+
return <div role="status">{ data }</div>;
|
|
88
77
|
} );
|
|
89
|
-
|
|
78
|
+
|
|
79
|
+
const rendered = render(
|
|
80
|
+
<RegistryProvider value={ registry }>
|
|
81
|
+
<TestComponent keyName="foo" change={ true } />
|
|
82
|
+
</RegistryProvider>
|
|
83
|
+
);
|
|
90
84
|
|
|
91
85
|
expect( selectSpyFoo ).toHaveBeenCalledTimes( 2 );
|
|
92
86
|
expect( selectSpyBar ).toHaveBeenCalledTimes( 0 );
|
|
93
87
|
expect( TestComponent ).toHaveBeenCalledTimes( 1 );
|
|
94
88
|
|
|
95
89
|
// Ensure expected state was rendered.
|
|
96
|
-
expect(
|
|
97
|
-
children: 'foo',
|
|
98
|
-
} );
|
|
90
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 'foo' );
|
|
99
91
|
|
|
100
92
|
// Rerender with non dependency changed.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
);
|
|
107
|
-
} );
|
|
93
|
+
rendered.rerender(
|
|
94
|
+
<RegistryProvider value={ registry }>
|
|
95
|
+
<TestComponent keyName="foo" change={ false } />
|
|
96
|
+
</RegistryProvider>
|
|
97
|
+
);
|
|
108
98
|
|
|
109
99
|
expect( selectSpyFoo ).toHaveBeenCalledTimes( 2 );
|
|
110
100
|
expect( selectSpyBar ).toHaveBeenCalledTimes( 0 );
|
|
111
101
|
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
112
102
|
|
|
113
103
|
// Ensure expected state was rendered.
|
|
114
|
-
expect(
|
|
115
|
-
children: 'foo',
|
|
116
|
-
} );
|
|
104
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 'foo' );
|
|
117
105
|
|
|
118
106
|
// Rerender with dependency changed.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
);
|
|
125
|
-
} );
|
|
107
|
+
rendered.rerender(
|
|
108
|
+
<RegistryProvider value={ registry }>
|
|
109
|
+
<TestComponent keyName="bar" change={ false } />
|
|
110
|
+
</RegistryProvider>
|
|
111
|
+
);
|
|
126
112
|
|
|
127
113
|
expect( selectSpyFoo ).toHaveBeenCalledTimes( 2 );
|
|
128
114
|
expect( selectSpyBar ).toHaveBeenCalledTimes( 2 );
|
|
129
115
|
expect( TestComponent ).toHaveBeenCalledTimes( 3 );
|
|
130
116
|
|
|
131
117
|
// Ensure expected state was rendered.
|
|
132
|
-
expect(
|
|
133
|
-
children: 'bar',
|
|
134
|
-
} );
|
|
118
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 'bar' );
|
|
135
119
|
} );
|
|
120
|
+
|
|
136
121
|
describe( 'rerenders as expected with various mapSelect return types', () => {
|
|
137
122
|
const getComponent = ( mapSelectSpy ) => () => {
|
|
138
123
|
const data = useSelect( mapSelectSpy, [] );
|
|
139
|
-
return <div data={ data } />;
|
|
124
|
+
return <div role="status" data-d={ JSON.stringify( data ) } />;
|
|
140
125
|
};
|
|
126
|
+
|
|
141
127
|
let TestComponent;
|
|
142
128
|
const mapSelectSpy = jest.fn( ( select ) =>
|
|
143
129
|
select( 'testStore' ).testSelector()
|
|
@@ -156,6 +142,7 @@ describe( 'useSelect', () => {
|
|
|
156
142
|
} );
|
|
157
143
|
TestComponent = getComponent( mapSelectSpy );
|
|
158
144
|
} );
|
|
145
|
+
|
|
159
146
|
afterEach( () => {
|
|
160
147
|
selectorSpy.mockClear();
|
|
161
148
|
mapSelectSpy.mockClear();
|
|
@@ -180,18 +167,14 @@ describe( 'useSelect', () => {
|
|
|
180
167
|
( type, testValues ) => {
|
|
181
168
|
const [ valueA, valueB ] = testValues;
|
|
182
169
|
selectorSpy.mockReturnValue( valueA );
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
</RegistryProvider>
|
|
189
|
-
);
|
|
190
|
-
} );
|
|
191
|
-
const testInstance = renderer.root;
|
|
170
|
+
const rendered = render(
|
|
171
|
+
<RegistryProvider value={ registry }>
|
|
172
|
+
<TestComponent />
|
|
173
|
+
</RegistryProvider>
|
|
174
|
+
);
|
|
192
175
|
// Ensure expected state was rendered.
|
|
193
|
-
expect(
|
|
194
|
-
valueA
|
|
176
|
+
expect( rendered.getByRole( 'status' ).dataset.d ).toBe(
|
|
177
|
+
JSON.stringify( valueA )
|
|
195
178
|
);
|
|
196
179
|
|
|
197
180
|
// Update the returned value from the selector and trigger the
|
|
@@ -200,15 +183,15 @@ describe( 'useSelect', () => {
|
|
|
200
183
|
selectorSpy.mockReturnValue( valueB );
|
|
201
184
|
registry.dispatch( 'testStore' ).forceUpdate();
|
|
202
185
|
} );
|
|
203
|
-
expect(
|
|
204
|
-
valueB
|
|
186
|
+
expect( rendered.getByRole( 'status' ).dataset.d ).toBe(
|
|
187
|
+
JSON.stringify( valueB )
|
|
205
188
|
);
|
|
206
189
|
expect( mapSelectSpy ).toHaveBeenCalledTimes( 3 );
|
|
207
190
|
}
|
|
208
191
|
);
|
|
209
192
|
} );
|
|
210
193
|
|
|
211
|
-
describe( 're-calls the selector as
|
|
194
|
+
describe( 're-calls the selector as few times as possible', () => {
|
|
212
195
|
const counterStore = {
|
|
213
196
|
actions: {
|
|
214
197
|
increment: () => ( { type: 'INCREMENT' } ),
|
|
@@ -231,8 +214,6 @@ describe( 'useSelect', () => {
|
|
|
231
214
|
registry.registerStore( 'store-1', counterStore );
|
|
232
215
|
registry.registerStore( 'store-2', counterStore );
|
|
233
216
|
|
|
234
|
-
let renderer;
|
|
235
|
-
|
|
236
217
|
const selectCount1 = jest.fn();
|
|
237
218
|
const selectCount2 = jest.fn();
|
|
238
219
|
|
|
@@ -248,23 +229,19 @@ describe( 'useSelect', () => {
|
|
|
248
229
|
[]
|
|
249
230
|
);
|
|
250
231
|
|
|
251
|
-
return <div
|
|
232
|
+
return <div role="status">{ count1 }</div>;
|
|
252
233
|
} );
|
|
253
234
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
<
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
);
|
|
260
|
-
} );
|
|
261
|
-
|
|
262
|
-
const testInstance = renderer.root;
|
|
235
|
+
const rendered = render(
|
|
236
|
+
<RegistryProvider value={ registry }>
|
|
237
|
+
<TestComponent />
|
|
238
|
+
</RegistryProvider>
|
|
239
|
+
);
|
|
263
240
|
|
|
264
241
|
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
265
242
|
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
266
243
|
expect( TestComponent ).toHaveBeenCalledTimes( 1 );
|
|
267
|
-
expect(
|
|
244
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
268
245
|
|
|
269
246
|
act( () => {
|
|
270
247
|
registry.dispatch( 'store-2' ).increment();
|
|
@@ -273,7 +250,7 @@ describe( 'useSelect', () => {
|
|
|
273
250
|
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
274
251
|
expect( selectCount2 ).toHaveBeenCalledTimes( 3 );
|
|
275
252
|
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
276
|
-
expect(
|
|
253
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
277
254
|
|
|
278
255
|
act( () => {
|
|
279
256
|
registry.dispatch( 'store-1' ).increment();
|
|
@@ -282,10 +259,10 @@ describe( 'useSelect', () => {
|
|
|
282
259
|
expect( selectCount1 ).toHaveBeenCalledTimes( 3 );
|
|
283
260
|
expect( selectCount2 ).toHaveBeenCalledTimes( 3 );
|
|
284
261
|
expect( TestComponent ).toHaveBeenCalledTimes( 3 );
|
|
285
|
-
expect(
|
|
262
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 1 );
|
|
286
263
|
|
|
287
264
|
// Test if the unsubscribers get called correctly.
|
|
288
|
-
|
|
265
|
+
rendered.unmount();
|
|
289
266
|
} );
|
|
290
267
|
|
|
291
268
|
it( 'can subscribe to multiple stores at once', () => {
|
|
@@ -293,8 +270,6 @@ describe( 'useSelect', () => {
|
|
|
293
270
|
registry.registerStore( 'store-2', counterStore );
|
|
294
271
|
registry.registerStore( 'store-3', counterStore );
|
|
295
272
|
|
|
296
|
-
let renderer;
|
|
297
|
-
|
|
298
273
|
const selectCount1And2 = jest.fn();
|
|
299
274
|
|
|
300
275
|
const TestComponent = jest.fn( () => {
|
|
@@ -307,44 +282,35 @@ describe( 'useSelect', () => {
|
|
|
307
282
|
[]
|
|
308
283
|
);
|
|
309
284
|
|
|
310
|
-
return
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
renderer = TestRenderer.create(
|
|
315
|
-
<RegistryProvider value={ registry }>
|
|
316
|
-
<TestComponent />
|
|
317
|
-
</RegistryProvider>
|
|
285
|
+
return (
|
|
286
|
+
<div role="status">
|
|
287
|
+
{ count1 },{ count2 }
|
|
288
|
+
</div>
|
|
318
289
|
);
|
|
319
290
|
} );
|
|
320
291
|
|
|
321
|
-
const
|
|
292
|
+
const rendered = render(
|
|
293
|
+
<RegistryProvider value={ registry }>
|
|
294
|
+
<TestComponent />
|
|
295
|
+
</RegistryProvider>
|
|
296
|
+
);
|
|
322
297
|
|
|
323
298
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 2 );
|
|
324
|
-
expect(
|
|
325
|
-
count1: 0,
|
|
326
|
-
count2: 0,
|
|
327
|
-
} );
|
|
299
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( '0,0' );
|
|
328
300
|
|
|
329
301
|
act( () => {
|
|
330
302
|
registry.dispatch( 'store-2' ).increment();
|
|
331
303
|
} );
|
|
332
304
|
|
|
333
305
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
334
|
-
expect(
|
|
335
|
-
count1: 0,
|
|
336
|
-
count2: 1,
|
|
337
|
-
} );
|
|
306
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( '0,1' );
|
|
338
307
|
|
|
339
308
|
act( () => {
|
|
340
309
|
registry.dispatch( 'store-3' ).increment();
|
|
341
310
|
} );
|
|
342
311
|
|
|
343
312
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
344
|
-
expect(
|
|
345
|
-
count1: 0,
|
|
346
|
-
count2: 1,
|
|
347
|
-
} );
|
|
313
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( '0,1' );
|
|
348
314
|
} );
|
|
349
315
|
|
|
350
316
|
it( 're-calls the selector when deps changed', () => {
|
|
@@ -352,7 +318,7 @@ describe( 'useSelect', () => {
|
|
|
352
318
|
registry.registerStore( 'store-2', counterStore );
|
|
353
319
|
registry.registerStore( 'store-3', counterStore );
|
|
354
320
|
|
|
355
|
-
let
|
|
321
|
+
let dep, setDep;
|
|
356
322
|
const selectCount1AndDep = jest.fn();
|
|
357
323
|
|
|
358
324
|
const TestComponent = jest.fn( () => {
|
|
@@ -366,44 +332,41 @@ describe( 'useSelect', () => {
|
|
|
366
332
|
[ dep ]
|
|
367
333
|
);
|
|
368
334
|
|
|
369
|
-
return
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
renderer = TestRenderer.create(
|
|
374
|
-
<RegistryProvider value={ registry }>
|
|
375
|
-
<TestComponent />
|
|
376
|
-
</RegistryProvider>
|
|
335
|
+
return (
|
|
336
|
+
<div role="status">
|
|
337
|
+
count:{ state.count1 },dep:{ state.dep }
|
|
338
|
+
</div>
|
|
377
339
|
);
|
|
378
340
|
} );
|
|
379
341
|
|
|
380
|
-
const
|
|
342
|
+
const rendered = render(
|
|
343
|
+
<RegistryProvider value={ registry }>
|
|
344
|
+
<TestComponent />
|
|
345
|
+
</RegistryProvider>
|
|
346
|
+
);
|
|
381
347
|
|
|
382
348
|
expect( selectCount1AndDep ).toHaveBeenCalledTimes( 2 );
|
|
383
|
-
expect(
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
} );
|
|
349
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
350
|
+
'count:0,dep:0'
|
|
351
|
+
);
|
|
387
352
|
|
|
388
353
|
act( () => {
|
|
389
354
|
setDep( 1 );
|
|
390
355
|
} );
|
|
391
356
|
|
|
392
357
|
expect( selectCount1AndDep ).toHaveBeenCalledTimes( 4 );
|
|
393
|
-
expect(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
} );
|
|
358
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
359
|
+
'count:0,dep:1'
|
|
360
|
+
);
|
|
397
361
|
|
|
398
362
|
act( () => {
|
|
399
363
|
registry.dispatch( 'store-1' ).increment();
|
|
400
364
|
} );
|
|
401
365
|
|
|
402
366
|
expect( selectCount1AndDep ).toHaveBeenCalledTimes( 5 );
|
|
403
|
-
expect(
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
} );
|
|
367
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
368
|
+
'count:1,dep:1'
|
|
369
|
+
);
|
|
407
370
|
} );
|
|
408
371
|
|
|
409
372
|
it( 'handles registry selectors', () => {
|
|
@@ -423,7 +386,6 @@ describe( 'useSelect', () => {
|
|
|
423
386
|
} );
|
|
424
387
|
registry.registerStore( 'store-2', counterStore );
|
|
425
388
|
|
|
426
|
-
let renderer;
|
|
427
389
|
const selectCount1And2 = jest.fn();
|
|
428
390
|
|
|
429
391
|
const TestComponent = jest.fn( () => {
|
|
@@ -434,46 +396,43 @@ describe( 'useSelect', () => {
|
|
|
434
396
|
[]
|
|
435
397
|
);
|
|
436
398
|
|
|
437
|
-
return
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
renderer = TestRenderer.create(
|
|
442
|
-
<RegistryProvider value={ registry }>
|
|
443
|
-
<TestComponent />
|
|
444
|
-
</RegistryProvider>
|
|
399
|
+
return (
|
|
400
|
+
<div role="status">
|
|
401
|
+
count1:{ state.count1 },count2:{ state.count2 }
|
|
402
|
+
</div>
|
|
445
403
|
);
|
|
446
404
|
} );
|
|
447
405
|
|
|
448
|
-
const
|
|
406
|
+
const rendered = render(
|
|
407
|
+
<RegistryProvider value={ registry }>
|
|
408
|
+
<TestComponent />
|
|
409
|
+
</RegistryProvider>
|
|
410
|
+
);
|
|
449
411
|
|
|
450
412
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 2 );
|
|
451
|
-
expect(
|
|
452
|
-
count1:
|
|
453
|
-
|
|
454
|
-
} );
|
|
413
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
414
|
+
'count1:0,count2:0'
|
|
415
|
+
);
|
|
455
416
|
|
|
456
417
|
act( () => {
|
|
457
418
|
registry.dispatch( 'store-2' ).increment();
|
|
458
419
|
} );
|
|
459
420
|
|
|
460
421
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
461
|
-
expect(
|
|
462
|
-
count1:
|
|
463
|
-
|
|
464
|
-
} );
|
|
422
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
423
|
+
'count1:0,count2:1'
|
|
424
|
+
);
|
|
465
425
|
} );
|
|
466
426
|
|
|
467
427
|
it( 'handles conditional statements in selectors', () => {
|
|
468
428
|
registry.registerStore( 'store-1', counterStore );
|
|
469
429
|
registry.registerStore( 'store-2', counterStore );
|
|
470
430
|
|
|
471
|
-
let renderer, shouldSelectCount1, toggle;
|
|
472
431
|
const selectCount1 = jest.fn();
|
|
473
432
|
const selectCount2 = jest.fn();
|
|
474
433
|
|
|
475
434
|
const TestComponent = jest.fn( () => {
|
|
476
|
-
[ shouldSelectCount1, toggle ] = useReducer(
|
|
435
|
+
const [ shouldSelectCount1, toggle ] = useReducer(
|
|
477
436
|
( should ) => ! should,
|
|
478
437
|
false
|
|
479
438
|
);
|
|
@@ -492,32 +451,31 @@ describe( 'useSelect', () => {
|
|
|
492
451
|
[ shouldSelectCount1 ]
|
|
493
452
|
);
|
|
494
453
|
|
|
495
|
-
return
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
<RegistryProvider value={ registry }>
|
|
501
|
-
<TestComponent />
|
|
502
|
-
</RegistryProvider>
|
|
454
|
+
return (
|
|
455
|
+
<>
|
|
456
|
+
<div role="status">{ state }</div>
|
|
457
|
+
<button onClick={ toggle }>Toggle</button>
|
|
458
|
+
</>
|
|
503
459
|
);
|
|
504
460
|
} );
|
|
505
461
|
|
|
506
|
-
const
|
|
462
|
+
const rendered = render(
|
|
463
|
+
<RegistryProvider value={ registry }>
|
|
464
|
+
<TestComponent />
|
|
465
|
+
</RegistryProvider>
|
|
466
|
+
);
|
|
507
467
|
|
|
508
468
|
expect( selectCount1 ).toHaveBeenCalledTimes( 0 );
|
|
509
469
|
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
510
|
-
expect(
|
|
470
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
511
471
|
'count2'
|
|
512
472
|
);
|
|
513
473
|
|
|
514
|
-
|
|
515
|
-
toggle();
|
|
516
|
-
} );
|
|
474
|
+
rendered.getByText( 'Toggle' ).click();
|
|
517
475
|
|
|
518
476
|
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
519
477
|
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
520
|
-
expect(
|
|
478
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
521
479
|
'count1'
|
|
522
480
|
);
|
|
523
481
|
} );
|
|
@@ -528,8 +486,6 @@ describe( 'useSelect', () => {
|
|
|
528
486
|
const subRegistry = createRegistry( {}, registry );
|
|
529
487
|
subRegistry.registerStore( 'child-store', counterStore );
|
|
530
488
|
|
|
531
|
-
let renderer;
|
|
532
|
-
|
|
533
489
|
const TestComponent = jest.fn( () => {
|
|
534
490
|
const state = useSelect(
|
|
535
491
|
( select ) => ( {
|
|
@@ -539,106 +495,95 @@ describe( 'useSelect', () => {
|
|
|
539
495
|
[]
|
|
540
496
|
);
|
|
541
497
|
|
|
542
|
-
return
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
renderer = TestRenderer.create(
|
|
547
|
-
<RegistryProvider value={ registry }>
|
|
548
|
-
<RegistryProvider value={ subRegistry }>
|
|
549
|
-
<TestComponent />
|
|
550
|
-
</RegistryProvider>
|
|
551
|
-
</RegistryProvider>
|
|
498
|
+
return (
|
|
499
|
+
<div role="status">
|
|
500
|
+
parent:{ state.parentCount },child:{ state.childCount }
|
|
501
|
+
</div>
|
|
552
502
|
);
|
|
553
503
|
} );
|
|
554
504
|
|
|
555
|
-
const
|
|
505
|
+
const rendered = render(
|
|
506
|
+
<RegistryProvider value={ registry }>
|
|
507
|
+
<RegistryProvider value={ subRegistry }>
|
|
508
|
+
<TestComponent />
|
|
509
|
+
</RegistryProvider>
|
|
510
|
+
</RegistryProvider>
|
|
511
|
+
);
|
|
556
512
|
|
|
557
|
-
expect(
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
} );
|
|
513
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
514
|
+
'parent:0,child:0'
|
|
515
|
+
);
|
|
561
516
|
|
|
562
517
|
act( () => {
|
|
563
518
|
registry.dispatch( 'parent-store' ).increment();
|
|
564
519
|
} );
|
|
565
520
|
|
|
566
|
-
expect(
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
} );
|
|
521
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
522
|
+
'parent:1,child:0'
|
|
523
|
+
);
|
|
570
524
|
} );
|
|
571
525
|
|
|
572
526
|
it( 'handles non-existing stores', () => {
|
|
573
527
|
registry.registerStore( 'store-1', counterStore );
|
|
574
528
|
|
|
575
|
-
let renderer;
|
|
576
|
-
|
|
577
529
|
const TestComponent = jest.fn( () => {
|
|
578
530
|
const state = useSelect(
|
|
579
531
|
( select ) => ( {
|
|
580
532
|
count1: select( 'store-1' ).getCounter(),
|
|
581
|
-
|
|
533
|
+
count2: select( 'store-2' )?.getCounter() ?? 'blank',
|
|
582
534
|
} ),
|
|
583
535
|
[]
|
|
584
536
|
);
|
|
585
537
|
|
|
586
|
-
return
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
renderer = TestRenderer.create(
|
|
591
|
-
<RegistryProvider value={ registry }>
|
|
592
|
-
<TestComponent />
|
|
593
|
-
</RegistryProvider>
|
|
538
|
+
return (
|
|
539
|
+
<div role="status">
|
|
540
|
+
count1:{ state.count1 },count2:{ state.count2 }
|
|
541
|
+
</div>
|
|
594
542
|
);
|
|
595
543
|
} );
|
|
596
544
|
|
|
597
|
-
const
|
|
545
|
+
const rendered = render(
|
|
546
|
+
<RegistryProvider value={ registry }>
|
|
547
|
+
<TestComponent />
|
|
548
|
+
</RegistryProvider>
|
|
549
|
+
);
|
|
598
550
|
|
|
599
|
-
expect(
|
|
600
|
-
count1:
|
|
601
|
-
|
|
602
|
-
} );
|
|
551
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
552
|
+
'count1:0,count2:blank'
|
|
553
|
+
);
|
|
603
554
|
|
|
604
555
|
act( () => {
|
|
605
556
|
registry.dispatch( 'store-1' ).increment();
|
|
606
557
|
} );
|
|
607
558
|
|
|
608
|
-
expect(
|
|
609
|
-
count1:
|
|
610
|
-
|
|
611
|
-
} );
|
|
559
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
560
|
+
'count1:1,count2:blank'
|
|
561
|
+
);
|
|
612
562
|
|
|
613
563
|
// Test if the unsubscribers get called correctly.
|
|
614
|
-
|
|
564
|
+
rendered.unmount();
|
|
615
565
|
} );
|
|
616
566
|
|
|
617
567
|
it( 'handles registration of a non-existing store during rendering', () => {
|
|
618
|
-
let renderer;
|
|
619
|
-
|
|
620
568
|
const TestComponent = jest.fn( () => {
|
|
621
569
|
const state = useSelect(
|
|
622
570
|
( select ) =>
|
|
623
|
-
select( 'not-yet-registered-store' )?.getCounter()
|
|
571
|
+
select( 'not-yet-registered-store' )?.getCounter() ??
|
|
572
|
+
'blank',
|
|
624
573
|
[]
|
|
625
574
|
);
|
|
626
575
|
|
|
627
|
-
return <div
|
|
576
|
+
return <div role="status">{ state }</div>;
|
|
628
577
|
} );
|
|
629
578
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
<
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
);
|
|
636
|
-
} );
|
|
637
|
-
|
|
638
|
-
const testInstance = renderer.root;
|
|
579
|
+
const rendered = render(
|
|
580
|
+
<RegistryProvider value={ registry }>
|
|
581
|
+
<TestComponent />
|
|
582
|
+
</RegistryProvider>
|
|
583
|
+
);
|
|
639
584
|
|
|
640
|
-
expect(
|
|
641
|
-
|
|
585
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
586
|
+
'blank'
|
|
642
587
|
);
|
|
643
588
|
|
|
644
589
|
act( () => {
|
|
@@ -649,23 +594,21 @@ describe( 'useSelect', () => {
|
|
|
649
594
|
} );
|
|
650
595
|
|
|
651
596
|
// This is not ideal, but is the way it's working before and we want to prevent breaking changes.
|
|
652
|
-
expect(
|
|
653
|
-
|
|
597
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
598
|
+
'blank'
|
|
654
599
|
);
|
|
655
600
|
|
|
656
601
|
act( () => {
|
|
657
602
|
registry.dispatch( 'not-yet-registered-store' ).increment();
|
|
658
603
|
} );
|
|
659
604
|
|
|
660
|
-
expect(
|
|
605
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 1 );
|
|
661
606
|
|
|
662
607
|
// Test if the unsubscribers get called correctly.
|
|
663
|
-
|
|
608
|
+
rendered.unmount();
|
|
664
609
|
} );
|
|
665
610
|
|
|
666
611
|
it( 'handles registration of a non-existing store of sub-registry during rendering', () => {
|
|
667
|
-
let renderer;
|
|
668
|
-
|
|
669
612
|
const subRegistry = createRegistry( {}, registry );
|
|
670
613
|
|
|
671
614
|
const TestComponent = jest.fn( () => {
|
|
@@ -673,27 +616,23 @@ describe( 'useSelect', () => {
|
|
|
673
616
|
( select ) =>
|
|
674
617
|
select(
|
|
675
618
|
'not-yet-registered-child-store'
|
|
676
|
-
)?.getCounter(),
|
|
619
|
+
)?.getCounter() ?? 'blank',
|
|
677
620
|
[]
|
|
678
621
|
);
|
|
679
622
|
|
|
680
|
-
return <div
|
|
623
|
+
return <div role="status">{ state }</div>;
|
|
681
624
|
} );
|
|
682
625
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
<RegistryProvider value={
|
|
686
|
-
<
|
|
687
|
-
<TestComponent />
|
|
688
|
-
</RegistryProvider>
|
|
626
|
+
const rendered = render(
|
|
627
|
+
<RegistryProvider value={ registry }>
|
|
628
|
+
<RegistryProvider value={ subRegistry }>
|
|
629
|
+
<TestComponent />
|
|
689
630
|
</RegistryProvider>
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
const testInstance = renderer.root;
|
|
631
|
+
</RegistryProvider>
|
|
632
|
+
);
|
|
694
633
|
|
|
695
|
-
expect(
|
|
696
|
-
|
|
634
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
635
|
+
'blank'
|
|
697
636
|
);
|
|
698
637
|
|
|
699
638
|
act( () => {
|
|
@@ -704,8 +643,8 @@ describe( 'useSelect', () => {
|
|
|
704
643
|
} );
|
|
705
644
|
|
|
706
645
|
// This is not ideal, but is the way it's working before and we want to prevent breaking changes.
|
|
707
|
-
expect(
|
|
708
|
-
|
|
646
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent(
|
|
647
|
+
'blank'
|
|
709
648
|
);
|
|
710
649
|
|
|
711
650
|
act( () => {
|
|
@@ -714,15 +653,13 @@ describe( 'useSelect', () => {
|
|
|
714
653
|
.increment();
|
|
715
654
|
} );
|
|
716
655
|
|
|
717
|
-
expect(
|
|
656
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( '1' );
|
|
718
657
|
|
|
719
658
|
// Test if the unsubscribers get called correctly.
|
|
720
|
-
|
|
659
|
+
rendered.unmount();
|
|
721
660
|
} );
|
|
722
661
|
|
|
723
662
|
it( 'handles custom generic stores without a unsubscribe function', () => {
|
|
724
|
-
let renderer;
|
|
725
|
-
|
|
726
663
|
const customStore = {
|
|
727
664
|
name: 'generic-store',
|
|
728
665
|
instantiate() {
|
|
@@ -762,28 +699,265 @@ describe( 'useSelect', () => {
|
|
|
762
699
|
[]
|
|
763
700
|
);
|
|
764
701
|
|
|
765
|
-
return <div
|
|
702
|
+
return <div role="status">{ state }</div>;
|
|
766
703
|
} );
|
|
767
704
|
|
|
705
|
+
const rendered = render(
|
|
706
|
+
<RegistryProvider value={ registry }>
|
|
707
|
+
<TestComponent />
|
|
708
|
+
</RegistryProvider>
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
712
|
+
|
|
768
713
|
act( () => {
|
|
769
|
-
|
|
714
|
+
registry.dispatch( customStore ).increment();
|
|
715
|
+
} );
|
|
716
|
+
|
|
717
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 1 );
|
|
718
|
+
|
|
719
|
+
expect( () => rendered.unmount() ).not.toThrow();
|
|
720
|
+
} );
|
|
721
|
+
} );
|
|
722
|
+
|
|
723
|
+
describe( 'async mode', () => {
|
|
724
|
+
function registerCounterStore( reg, initialCount = 0 ) {
|
|
725
|
+
reg.registerStore( 'counter', {
|
|
726
|
+
reducer: ( state = initialCount, action ) => {
|
|
727
|
+
if ( action.type === 'INCREMENT' ) {
|
|
728
|
+
return state + 1;
|
|
729
|
+
}
|
|
730
|
+
return state;
|
|
731
|
+
},
|
|
732
|
+
actions: {
|
|
733
|
+
inc: () => ( { type: 'INCREMENT' } ),
|
|
734
|
+
},
|
|
735
|
+
selectors: {
|
|
736
|
+
get: ( state ) => state,
|
|
737
|
+
},
|
|
738
|
+
} );
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
beforeEach( () => {
|
|
742
|
+
registerCounterStore( registry );
|
|
743
|
+
} );
|
|
744
|
+
|
|
745
|
+
it( 'renders with async mode', async () => {
|
|
746
|
+
const selectSpy = jest.fn( ( select ) =>
|
|
747
|
+
select( 'counter' ).get()
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
const TestComponent = jest.fn( () => {
|
|
751
|
+
const count = useSelect( selectSpy, [] );
|
|
752
|
+
return <div role="status">{ count }</div>;
|
|
753
|
+
} );
|
|
754
|
+
|
|
755
|
+
const rendered = render(
|
|
756
|
+
<AsyncModeProvider value={ true }>
|
|
770
757
|
<RegistryProvider value={ registry }>
|
|
771
758
|
<TestComponent />
|
|
772
759
|
</RegistryProvider>
|
|
773
|
-
|
|
760
|
+
</AsyncModeProvider>
|
|
761
|
+
);
|
|
762
|
+
|
|
763
|
+
// initial render + missed update catcher in subscribing effect
|
|
764
|
+
expect( selectSpy ).toHaveBeenCalledTimes( 2 );
|
|
765
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 1 );
|
|
766
|
+
|
|
767
|
+
// Ensure expected state was rendered.
|
|
768
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
769
|
+
|
|
770
|
+
act( () => {
|
|
771
|
+
registry.dispatch( 'counter' ).inc();
|
|
774
772
|
} );
|
|
775
773
|
|
|
776
|
-
|
|
774
|
+
// still not called right after increment
|
|
775
|
+
expect( selectSpy ).toHaveBeenCalledTimes( 2 );
|
|
776
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
777
777
|
|
|
778
|
-
expect(
|
|
778
|
+
expect( await rendered.findByText( 1 ) ).toBeInTheDocument();
|
|
779
779
|
|
|
780
|
+
expect( selectSpy ).toHaveBeenCalledTimes( 3 );
|
|
781
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
782
|
+
} );
|
|
783
|
+
|
|
784
|
+
// Tests render queue fixes done in https://github.com/WordPress/gutenberg/pull/19286
|
|
785
|
+
it( 'catches updates while switching from async to sync', () => {
|
|
786
|
+
const selectSpy = jest.fn( ( select ) =>
|
|
787
|
+
select( 'counter' ).get()
|
|
788
|
+
);
|
|
789
|
+
|
|
790
|
+
const TestComponent = jest.fn( () => {
|
|
791
|
+
const count = useSelect( selectSpy, [] );
|
|
792
|
+
return <div role="status">{ count }</div>;
|
|
793
|
+
} );
|
|
794
|
+
|
|
795
|
+
const App = ( { async } ) => (
|
|
796
|
+
<AsyncModeProvider value={ async }>
|
|
797
|
+
<RegistryProvider value={ registry }>
|
|
798
|
+
<TestComponent />
|
|
799
|
+
</RegistryProvider>
|
|
800
|
+
</AsyncModeProvider>
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
const rendered = render( <App async={ true } /> );
|
|
804
|
+
|
|
805
|
+
// Ensure expected state was rendered.
|
|
806
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
807
|
+
|
|
808
|
+
// Schedules an async update of the component.
|
|
780
809
|
act( () => {
|
|
781
|
-
registry.dispatch(
|
|
810
|
+
registry.dispatch( 'counter' ).inc();
|
|
782
811
|
} );
|
|
783
812
|
|
|
784
|
-
|
|
813
|
+
// Ensure the async update wasn't processed yet.
|
|
814
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
785
815
|
|
|
786
|
-
|
|
816
|
+
// Switch from async mode to sync.
|
|
817
|
+
rendered.rerender( <App async={ false } /> );
|
|
818
|
+
|
|
819
|
+
// Ensure the async update was flushed during the rerender.
|
|
820
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 1 );
|
|
821
|
+
|
|
822
|
+
// initial render + subscription check + flushed store update
|
|
823
|
+
expect( selectSpy ).toHaveBeenCalledTimes( 3 );
|
|
824
|
+
// initial render + rerender with isAsync=false + store state update
|
|
825
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 3 );
|
|
826
|
+
} );
|
|
827
|
+
|
|
828
|
+
it( 'cancels scheduled updates when mapSelect function changes', async () => {
|
|
829
|
+
const selectA = jest.fn(
|
|
830
|
+
( select ) => 'a:' + select( 'counter' ).get()
|
|
831
|
+
);
|
|
832
|
+
const selectB = jest.fn(
|
|
833
|
+
( select ) => 'b:' + select( 'counter' ).get()
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
const TestComponent = jest.fn( ( { variant } ) => {
|
|
837
|
+
const count = useSelect( variant === 'a' ? selectA : selectB, [
|
|
838
|
+
variant,
|
|
839
|
+
] );
|
|
840
|
+
return <div role="status">{ count }</div>;
|
|
841
|
+
} );
|
|
842
|
+
|
|
843
|
+
const App = ( { variant } ) => (
|
|
844
|
+
<AsyncModeProvider value={ true }>
|
|
845
|
+
<RegistryProvider value={ registry }>
|
|
846
|
+
<TestComponent variant={ variant } />
|
|
847
|
+
</RegistryProvider>
|
|
848
|
+
</AsyncModeProvider>
|
|
849
|
+
);
|
|
850
|
+
|
|
851
|
+
const rendered = render( <App variant="a" /> );
|
|
852
|
+
|
|
853
|
+
// Ensure expected state was rendered.
|
|
854
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 'a:0' );
|
|
855
|
+
|
|
856
|
+
// Schedules an async update of the component.
|
|
857
|
+
act( () => {
|
|
858
|
+
registry.dispatch( 'counter' ).inc();
|
|
859
|
+
} );
|
|
860
|
+
|
|
861
|
+
// Ensure the async update wasn't processed yet.
|
|
862
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 'a:0' );
|
|
863
|
+
|
|
864
|
+
// Rerender with a prop change that causes dependency change.
|
|
865
|
+
rendered.rerender( <App variant="b" /> );
|
|
866
|
+
|
|
867
|
+
// Ensure the async update was flushed (cancelled) during the rerender.
|
|
868
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 'b:1' );
|
|
869
|
+
|
|
870
|
+
// Give the async update time to run in case it wasn't cancelled
|
|
871
|
+
await new Promise( setImmediate );
|
|
872
|
+
|
|
873
|
+
expect( selectA ).toHaveBeenCalledTimes( 2 );
|
|
874
|
+
expect( selectB ).toHaveBeenCalledTimes( 2 );
|
|
875
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
876
|
+
} );
|
|
877
|
+
|
|
878
|
+
it( 'cancels scheduled updates when unmounting', async () => {
|
|
879
|
+
const selectSpy = jest.fn( ( select ) =>
|
|
880
|
+
select( 'counter' ).get()
|
|
881
|
+
);
|
|
882
|
+
|
|
883
|
+
const TestComponent = jest.fn( () => {
|
|
884
|
+
const count = useSelect( selectSpy, [] );
|
|
885
|
+
return <div role="status">{ count }</div>;
|
|
886
|
+
} );
|
|
887
|
+
|
|
888
|
+
const App = () => (
|
|
889
|
+
<AsyncModeProvider value={ true }>
|
|
890
|
+
<RegistryProvider value={ registry }>
|
|
891
|
+
<TestComponent />
|
|
892
|
+
</RegistryProvider>
|
|
893
|
+
</AsyncModeProvider>
|
|
894
|
+
);
|
|
895
|
+
|
|
896
|
+
const rendered = render( <App /> );
|
|
897
|
+
|
|
898
|
+
// Ensure expected state was rendered.
|
|
899
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
900
|
+
|
|
901
|
+
// Schedules an async update of the component.
|
|
902
|
+
act( () => {
|
|
903
|
+
registry.dispatch( 'counter' ).inc();
|
|
904
|
+
} );
|
|
905
|
+
|
|
906
|
+
// Ensure the async update wasn't processed yet.
|
|
907
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
908
|
+
|
|
909
|
+
// Unmount
|
|
910
|
+
rendered.unmount();
|
|
911
|
+
|
|
912
|
+
// Give the async update time to run in case it wasn't cancelled
|
|
913
|
+
await new Promise( setImmediate );
|
|
914
|
+
|
|
915
|
+
// only the initial render, no state updates
|
|
916
|
+
expect( selectSpy ).toHaveBeenCalledTimes( 2 );
|
|
917
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 1 );
|
|
918
|
+
} );
|
|
919
|
+
|
|
920
|
+
it( 'cancels scheduled updates when registry changes', async () => {
|
|
921
|
+
const registry2 = createRegistry();
|
|
922
|
+
registerCounterStore( registry2, 100 );
|
|
923
|
+
|
|
924
|
+
const selectSpy = jest.fn( ( select ) =>
|
|
925
|
+
select( 'counter' ).get()
|
|
926
|
+
);
|
|
927
|
+
|
|
928
|
+
const TestComponent = jest.fn( () => {
|
|
929
|
+
const count = useSelect( selectSpy, [] );
|
|
930
|
+
return <div role="status">{ count }</div>;
|
|
931
|
+
} );
|
|
932
|
+
|
|
933
|
+
const App = ( { reg } ) => (
|
|
934
|
+
<AsyncModeProvider value={ true }>
|
|
935
|
+
<RegistryProvider value={ reg }>
|
|
936
|
+
<TestComponent />
|
|
937
|
+
</RegistryProvider>
|
|
938
|
+
</AsyncModeProvider>
|
|
939
|
+
);
|
|
940
|
+
|
|
941
|
+
const rendered = render( <App reg={ registry } /> );
|
|
942
|
+
|
|
943
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
944
|
+
|
|
945
|
+
act( () => {
|
|
946
|
+
registry.dispatch( 'counter' ).inc();
|
|
947
|
+
} );
|
|
948
|
+
|
|
949
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 0 );
|
|
950
|
+
|
|
951
|
+
rendered.rerender( <App reg={ registry2 } /> );
|
|
952
|
+
|
|
953
|
+
expect( rendered.getByRole( 'status' ) ).toHaveTextContent( 100 );
|
|
954
|
+
|
|
955
|
+
// Give the async update time to run in case it wasn't cancelled
|
|
956
|
+
await new Promise( setImmediate );
|
|
957
|
+
|
|
958
|
+
// initial render + registry change rerender, no state updates
|
|
959
|
+
expect( selectSpy ).toHaveBeenCalledTimes( 4 );
|
|
960
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
787
961
|
} );
|
|
788
962
|
} );
|
|
789
963
|
} );
|