@wordpress/data 8.6.0 → 9.0.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 +6 -0
- package/build/components/use-select/index.js +90 -55
- package/build/components/use-select/index.js.map +1 -1
- package/build/registry.js +16 -7
- package/build/registry.js.map +1 -1
- package/build-module/components/use-select/index.js +90 -55
- package/build-module/components/use-select/index.js.map +1 -1
- package/build-module/registry.js +16 -7
- package/build-module/registry.js.map +1 -1
- package/build-types/components/use-select/index.d.ts.map +1 -1
- package/build-types/registry.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/components/use-select/index.js +87 -57
- package/src/components/use-select/test/index.js +247 -163
- package/src/registry.js +20 -8
- package/src/test/registry.js +31 -22
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -6,7 +6,7 @@ import { act, render, fireEvent, screen } from '@testing-library/react';
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { useLayoutEffect, useState, useReducer } from '@wordpress/element';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Internal dependencies
|
|
@@ -19,6 +19,19 @@ import {
|
|
|
19
19
|
} from '../../..';
|
|
20
20
|
import useSelect from '..';
|
|
21
21
|
|
|
22
|
+
function counterStore( initialCount = 0, step = 1 ) {
|
|
23
|
+
return {
|
|
24
|
+
reducer: ( state = initialCount, action ) =>
|
|
25
|
+
action.type === 'INC' ? state + step : state,
|
|
26
|
+
actions: {
|
|
27
|
+
inc: () => ( { type: 'INC' } ),
|
|
28
|
+
},
|
|
29
|
+
selectors: {
|
|
30
|
+
get: ( state ) => state,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
describe( 'useSelect', () => {
|
|
23
36
|
let registry;
|
|
24
37
|
beforeEach( () => {
|
|
@@ -109,7 +122,7 @@ describe( 'useSelect', () => {
|
|
|
109
122
|
);
|
|
110
123
|
|
|
111
124
|
expect( selectSpyFoo ).toHaveBeenCalledTimes( 2 );
|
|
112
|
-
expect( selectSpyBar ).toHaveBeenCalledTimes(
|
|
125
|
+
expect( selectSpyBar ).toHaveBeenCalledTimes( 1 );
|
|
113
126
|
expect( TestComponent ).toHaveBeenCalledTimes( 3 );
|
|
114
127
|
|
|
115
128
|
// Ensure expected state was rendered.
|
|
@@ -180,6 +193,81 @@ describe( 'useSelect', () => {
|
|
|
180
193
|
expect( Child ).toHaveBeenCalledTimes( 1 );
|
|
181
194
|
} );
|
|
182
195
|
|
|
196
|
+
it( 'incrementally subscribes to newly selected stores', () => {
|
|
197
|
+
registry.registerStore( 'store-main', counterStore() );
|
|
198
|
+
registry.registerStore( 'store-even', counterStore( 0, 2 ) );
|
|
199
|
+
registry.registerStore( 'store-odd', counterStore( 1, 2 ) );
|
|
200
|
+
|
|
201
|
+
const mapSelect = jest.fn( ( select ) => {
|
|
202
|
+
const first = select( 'store-main' ).get();
|
|
203
|
+
// select from other stores depending on whether main value is even or odd
|
|
204
|
+
const secondStore = first % 2 === 1 ? 'store-odd' : 'store-even';
|
|
205
|
+
const second = select( secondStore ).get();
|
|
206
|
+
return first + ':' + second;
|
|
207
|
+
} );
|
|
208
|
+
|
|
209
|
+
const TestComponent = jest.fn( () => {
|
|
210
|
+
const data = useSelect( mapSelect, [] );
|
|
211
|
+
return <div role="status">{ data }</div>;
|
|
212
|
+
} );
|
|
213
|
+
|
|
214
|
+
render(
|
|
215
|
+
<RegistryProvider value={ registry }>
|
|
216
|
+
<TestComponent />
|
|
217
|
+
</RegistryProvider>
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
expect( mapSelect ).toHaveBeenCalledTimes( 2 );
|
|
221
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 1 );
|
|
222
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0:0' );
|
|
223
|
+
|
|
224
|
+
// check that increment in store-even triggers a render
|
|
225
|
+
act( () => {
|
|
226
|
+
registry.dispatch( 'store-even' ).inc();
|
|
227
|
+
} );
|
|
228
|
+
|
|
229
|
+
expect( mapSelect ).toHaveBeenCalledTimes( 3 );
|
|
230
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
231
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0:2' );
|
|
232
|
+
|
|
233
|
+
// check that increment in store-odd doesn't trigger a render (not listening yet)
|
|
234
|
+
act( () => {
|
|
235
|
+
registry.dispatch( 'store-odd' ).inc();
|
|
236
|
+
} );
|
|
237
|
+
|
|
238
|
+
expect( mapSelect ).toHaveBeenCalledTimes( 3 );
|
|
239
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
240
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0:2' );
|
|
241
|
+
|
|
242
|
+
// check that increment in main store switches to store-odd
|
|
243
|
+
act( () => {
|
|
244
|
+
registry.dispatch( 'store-main' ).inc();
|
|
245
|
+
} );
|
|
246
|
+
|
|
247
|
+
expect( mapSelect ).toHaveBeenCalledTimes( 4 );
|
|
248
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 3 );
|
|
249
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1:3' );
|
|
250
|
+
|
|
251
|
+
// check that increment in store-odd triggers a render
|
|
252
|
+
act( () => {
|
|
253
|
+
registry.dispatch( 'store-odd' ).inc();
|
|
254
|
+
} );
|
|
255
|
+
|
|
256
|
+
expect( mapSelect ).toHaveBeenCalledTimes( 5 );
|
|
257
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 4 );
|
|
258
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1:5' );
|
|
259
|
+
|
|
260
|
+
// check that increment in store-even triggers a mapSelect call (still listening)
|
|
261
|
+
// but not a render (not used for selected value which doesn't change)
|
|
262
|
+
act( () => {
|
|
263
|
+
registry.dispatch( 'store-even' ).inc();
|
|
264
|
+
} );
|
|
265
|
+
|
|
266
|
+
expect( mapSelect ).toHaveBeenCalledTimes( 6 );
|
|
267
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 4 );
|
|
268
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1:5' );
|
|
269
|
+
} );
|
|
270
|
+
|
|
183
271
|
describe( 'rerenders as expected with various mapSelect return types', () => {
|
|
184
272
|
const getComponent = ( mapSelectSpy ) => () => {
|
|
185
273
|
const data = useSelect( mapSelectSpy, [] );
|
|
@@ -254,40 +342,20 @@ describe( 'useSelect', () => {
|
|
|
254
342
|
} );
|
|
255
343
|
|
|
256
344
|
describe( 're-calls the selector as few times as possible', () => {
|
|
257
|
-
const counterStore = {
|
|
258
|
-
actions: {
|
|
259
|
-
increment: () => ( { type: 'INCREMENT' } ),
|
|
260
|
-
},
|
|
261
|
-
reducer: ( state, action ) => {
|
|
262
|
-
if ( ! state ) {
|
|
263
|
-
return { counter: 0 };
|
|
264
|
-
}
|
|
265
|
-
if ( action?.type === 'INCREMENT' ) {
|
|
266
|
-
return { counter: state.counter + 1 };
|
|
267
|
-
}
|
|
268
|
-
return state;
|
|
269
|
-
},
|
|
270
|
-
selectors: {
|
|
271
|
-
getCounter: ( state ) => state.counter,
|
|
272
|
-
},
|
|
273
|
-
};
|
|
274
|
-
|
|
275
345
|
it( 'only calls the selectors it has selected', () => {
|
|
276
|
-
registry.registerStore( 'store-1', counterStore );
|
|
277
|
-
registry.registerStore( 'store-2', counterStore );
|
|
346
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
347
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
278
348
|
|
|
279
349
|
const selectCount1 = jest.fn();
|
|
280
350
|
const selectCount2 = jest.fn();
|
|
281
351
|
|
|
282
352
|
const TestComponent = jest.fn( () => {
|
|
283
353
|
const count1 = useSelect(
|
|
284
|
-
( select ) =>
|
|
285
|
-
selectCount1() || select( 'store-1' ).getCounter(),
|
|
354
|
+
( select ) => selectCount1() || select( 'store-1' ).get(),
|
|
286
355
|
[]
|
|
287
356
|
);
|
|
288
357
|
useSelect(
|
|
289
|
-
( select ) =>
|
|
290
|
-
selectCount2() || select( 'store-2' ).getCounter(),
|
|
358
|
+
( select ) => selectCount2() || select( 'store-2' ).get(),
|
|
291
359
|
[]
|
|
292
360
|
);
|
|
293
361
|
|
|
@@ -306,7 +374,7 @@ describe( 'useSelect', () => {
|
|
|
306
374
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0' );
|
|
307
375
|
|
|
308
376
|
act( () => {
|
|
309
|
-
registry.dispatch( 'store-2' ).
|
|
377
|
+
registry.dispatch( 'store-2' ).inc();
|
|
310
378
|
} );
|
|
311
379
|
|
|
312
380
|
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
@@ -315,7 +383,7 @@ describe( 'useSelect', () => {
|
|
|
315
383
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0' );
|
|
316
384
|
|
|
317
385
|
act( () => {
|
|
318
|
-
registry.dispatch( 'store-1' ).
|
|
386
|
+
registry.dispatch( 'store-1' ).inc();
|
|
319
387
|
} );
|
|
320
388
|
|
|
321
389
|
expect( selectCount1 ).toHaveBeenCalledTimes( 3 );
|
|
@@ -328,9 +396,9 @@ describe( 'useSelect', () => {
|
|
|
328
396
|
} );
|
|
329
397
|
|
|
330
398
|
it( 'can subscribe to multiple stores at once', () => {
|
|
331
|
-
registry.registerStore( 'store-1', counterStore );
|
|
332
|
-
registry.registerStore( 'store-2', counterStore );
|
|
333
|
-
registry.registerStore( 'store-3', counterStore );
|
|
399
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
400
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
401
|
+
registry.registerStore( 'store-3', counterStore() );
|
|
334
402
|
|
|
335
403
|
const selectCount1And2 = jest.fn();
|
|
336
404
|
|
|
@@ -338,8 +406,8 @@ describe( 'useSelect', () => {
|
|
|
338
406
|
const { count1, count2 } = useSelect(
|
|
339
407
|
( select ) =>
|
|
340
408
|
selectCount1And2() || {
|
|
341
|
-
count1: select( 'store-1' ).
|
|
342
|
-
count2: select( 'store-2' ).
|
|
409
|
+
count1: select( 'store-1' ).get(),
|
|
410
|
+
count2: select( 'store-2' ).get(),
|
|
343
411
|
},
|
|
344
412
|
[]
|
|
345
413
|
);
|
|
@@ -361,14 +429,14 @@ describe( 'useSelect', () => {
|
|
|
361
429
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0,0' );
|
|
362
430
|
|
|
363
431
|
act( () => {
|
|
364
|
-
registry.dispatch( 'store-2' ).
|
|
432
|
+
registry.dispatch( 'store-2' ).inc();
|
|
365
433
|
} );
|
|
366
434
|
|
|
367
435
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
368
436
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0,1' );
|
|
369
437
|
|
|
370
438
|
act( () => {
|
|
371
|
-
registry.dispatch( 'store-3' ).
|
|
439
|
+
registry.dispatch( 'store-3' ).inc();
|
|
372
440
|
} );
|
|
373
441
|
|
|
374
442
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
@@ -376,9 +444,9 @@ describe( 'useSelect', () => {
|
|
|
376
444
|
} );
|
|
377
445
|
|
|
378
446
|
it( 're-calls the selector when deps changed', () => {
|
|
379
|
-
registry.registerStore( 'store-1', counterStore );
|
|
380
|
-
registry.registerStore( 'store-2', counterStore );
|
|
381
|
-
registry.registerStore( 'store-3', counterStore );
|
|
447
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
448
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
449
|
+
registry.registerStore( 'store-3', counterStore() );
|
|
382
450
|
|
|
383
451
|
let dep, setDep;
|
|
384
452
|
const selectCount1AndDep = jest.fn();
|
|
@@ -388,7 +456,7 @@ describe( 'useSelect', () => {
|
|
|
388
456
|
const state = useSelect(
|
|
389
457
|
( select ) =>
|
|
390
458
|
selectCount1AndDep() || {
|
|
391
|
-
count1: select( 'store-1' ).
|
|
459
|
+
count1: select( 'store-1' ).get(),
|
|
392
460
|
dep,
|
|
393
461
|
},
|
|
394
462
|
[ dep ]
|
|
@@ -416,63 +484,40 @@ describe( 'useSelect', () => {
|
|
|
416
484
|
setDep( 1 );
|
|
417
485
|
} );
|
|
418
486
|
|
|
419
|
-
expect( selectCount1AndDep ).toHaveBeenCalledTimes(
|
|
487
|
+
expect( selectCount1AndDep ).toHaveBeenCalledTimes( 3 );
|
|
420
488
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
421
489
|
'count:0,dep:1'
|
|
422
490
|
);
|
|
423
491
|
|
|
424
492
|
act( () => {
|
|
425
|
-
registry.dispatch( 'store-1' ).
|
|
493
|
+
registry.dispatch( 'store-1' ).inc();
|
|
426
494
|
} );
|
|
427
495
|
|
|
428
|
-
expect( selectCount1AndDep ).toHaveBeenCalledTimes(
|
|
496
|
+
expect( selectCount1AndDep ).toHaveBeenCalledTimes( 4 );
|
|
429
497
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
430
498
|
'count:1,dep:1'
|
|
431
499
|
);
|
|
432
500
|
} );
|
|
433
501
|
|
|
434
|
-
it( 'captures state changes scheduled between render and
|
|
435
|
-
registry.registerStore( 'store-1', counterStore );
|
|
436
|
-
|
|
437
|
-
class ChildComponent extends Component {
|
|
438
|
-
componentDidUpdate( prevProps ) {
|
|
439
|
-
if (
|
|
440
|
-
this.props.childShouldDispatch &&
|
|
441
|
-
this.props.childShouldDispatch !==
|
|
442
|
-
prevProps.childShouldDispatch
|
|
443
|
-
) {
|
|
444
|
-
registry.dispatch( 'store-1' ).increment();
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
render() {
|
|
449
|
-
return null;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
502
|
+
it( 'captures state changes scheduled between render and subscription', () => {
|
|
503
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
452
504
|
|
|
453
|
-
const
|
|
454
|
-
count1: select( 'store-1' ).
|
|
505
|
+
const selectCount1 = jest.fn( ( select ) => ( {
|
|
506
|
+
count1: select( 'store-1' ).get(),
|
|
455
507
|
} ) );
|
|
456
508
|
|
|
457
|
-
const TestComponent = () => {
|
|
458
|
-
const
|
|
459
|
-
useState( false );
|
|
460
|
-
const state = useSelect( selectCount1AndDep, [] );
|
|
509
|
+
const TestComponent = jest.fn( () => {
|
|
510
|
+
const { count1 } = useSelect( selectCount1, [] );
|
|
461
511
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
triggerChildDispatch
|
|
472
|
-
</button>
|
|
473
|
-
</>
|
|
474
|
-
);
|
|
475
|
-
};
|
|
512
|
+
// Increment the store value from 0 to 1 after render and before subscription
|
|
513
|
+
useLayoutEffect( () => {
|
|
514
|
+
if ( count1 === 0 ) {
|
|
515
|
+
registry.dispatch( 'store-1' ).inc();
|
|
516
|
+
}
|
|
517
|
+
}, [ count1 ] );
|
|
518
|
+
|
|
519
|
+
return <div role="status">count1:{ count1 }</div>;
|
|
520
|
+
} );
|
|
476
521
|
|
|
477
522
|
render(
|
|
478
523
|
<RegistryProvider value={ registry }>
|
|
@@ -480,30 +525,93 @@ describe( 'useSelect', () => {
|
|
|
480
525
|
</RegistryProvider>
|
|
481
526
|
);
|
|
482
527
|
|
|
483
|
-
|
|
528
|
+
// One select on initial render, and one in `checkIfSnapshotChanged` after subscribing.
|
|
529
|
+
// There's a third selector call on the second render, but that one returns a memoized value.
|
|
530
|
+
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
484
531
|
|
|
485
|
-
|
|
532
|
+
// Initial render and second render after counter increment (which is expected to be detected).
|
|
533
|
+
expect( TestComponent ).toHaveBeenCalledTimes( 2 );
|
|
534
|
+
|
|
535
|
+
// Finally rendered with the incremented counter's value.
|
|
486
536
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
487
537
|
'count1:1'
|
|
488
538
|
);
|
|
489
539
|
} );
|
|
490
540
|
|
|
541
|
+
it( 'captures state changes scheduled between render and effect after selector change', () => {
|
|
542
|
+
registry.registerStore( 'names', {
|
|
543
|
+
reducer: ( state = {}, action ) => {
|
|
544
|
+
if ( action.type === 'SET_NAME' ) {
|
|
545
|
+
return {
|
|
546
|
+
...state,
|
|
547
|
+
[ action.id ]: action.name,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
return state;
|
|
551
|
+
},
|
|
552
|
+
actions: {
|
|
553
|
+
setName: ( id, name ) => ( { type: 'SET_NAME', id, name } ),
|
|
554
|
+
},
|
|
555
|
+
selectors: {
|
|
556
|
+
getName: ( state, id ) => state[ id ] ?? 'null',
|
|
557
|
+
},
|
|
558
|
+
} );
|
|
559
|
+
|
|
560
|
+
const renderedItems = [];
|
|
561
|
+
|
|
562
|
+
function TestComponent() {
|
|
563
|
+
const [ blockId, setBlockId ] = useState( 1 );
|
|
564
|
+
|
|
565
|
+
const name = useSelect(
|
|
566
|
+
( select ) => select( 'names' ).getName( blockId ),
|
|
567
|
+
[ blockId ]
|
|
568
|
+
);
|
|
569
|
+
|
|
570
|
+
// Change name of block 2. The store listener will still use the old selector
|
|
571
|
+
// for block 1, because a new one will be stored by an effect a moment later,
|
|
572
|
+
// but we're testing that it still won't miss the update, because one more check
|
|
573
|
+
// will happen in that effect.
|
|
574
|
+
useLayoutEffect( () => {
|
|
575
|
+
if ( blockId === 2 ) {
|
|
576
|
+
registry.dispatch( 'names' ).setName( 2, 'new2' );
|
|
577
|
+
}
|
|
578
|
+
}, [ blockId ] );
|
|
579
|
+
|
|
580
|
+
renderedItems.push( name );
|
|
581
|
+
|
|
582
|
+
return (
|
|
583
|
+
<button onClick={ () => setBlockId( 2 ) }>
|
|
584
|
+
change-block
|
|
585
|
+
</button>
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
render(
|
|
590
|
+
<RegistryProvider value={ registry }>
|
|
591
|
+
<TestComponent />
|
|
592
|
+
</RegistryProvider>
|
|
593
|
+
);
|
|
594
|
+
expect( renderedItems ).toEqual( [ 'null' ] );
|
|
595
|
+
|
|
596
|
+
fireEvent.click( screen.getByRole( 'button' ) );
|
|
597
|
+
// After click, there are two new renders:
|
|
598
|
+
// 1. With of block 2, after state update of `blockId` from 1 to 2
|
|
599
|
+
// 2. After dispatching an action to change 2's name to `new2`
|
|
600
|
+
expect( renderedItems ).toEqual( [ 'null', 'null', 'new2' ] );
|
|
601
|
+
} );
|
|
602
|
+
|
|
491
603
|
it( 'handles registry selectors', () => {
|
|
492
604
|
const getCount1And2 = createRegistrySelector(
|
|
493
605
|
( select ) => ( state ) => ( {
|
|
494
|
-
count1: state
|
|
495
|
-
count2: select( 'store-2' ).
|
|
606
|
+
count1: state,
|
|
607
|
+
count2: select( 'store-2' ).get(),
|
|
496
608
|
} )
|
|
497
609
|
);
|
|
498
610
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
getCount1And2,
|
|
504
|
-
},
|
|
505
|
-
} );
|
|
506
|
-
registry.registerStore( 'store-2', counterStore );
|
|
611
|
+
const store1Spec = counterStore();
|
|
612
|
+
Object.assign( store1Spec.selectors, { getCount1And2 } );
|
|
613
|
+
registry.registerStore( 'store-1', store1Spec );
|
|
614
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
507
615
|
|
|
508
616
|
const selectCount1And2 = jest.fn();
|
|
509
617
|
|
|
@@ -534,7 +642,7 @@ describe( 'useSelect', () => {
|
|
|
534
642
|
);
|
|
535
643
|
|
|
536
644
|
act( () => {
|
|
537
|
-
registry.dispatch( 'store-2' ).
|
|
645
|
+
registry.dispatch( 'store-2' ).inc();
|
|
538
646
|
} );
|
|
539
647
|
|
|
540
648
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
@@ -544,8 +652,8 @@ describe( 'useSelect', () => {
|
|
|
544
652
|
} );
|
|
545
653
|
|
|
546
654
|
it( 'handles conditional statements in selectors', () => {
|
|
547
|
-
registry.registerStore( 'store-1', counterStore );
|
|
548
|
-
registry.registerStore( 'store-2', counterStore );
|
|
655
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
656
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
549
657
|
|
|
550
658
|
const selectCount1 = jest.fn();
|
|
551
659
|
const selectCount2 = jest.fn();
|
|
@@ -559,13 +667,11 @@ describe( 'useSelect', () => {
|
|
|
559
667
|
( select ) => {
|
|
560
668
|
if ( shouldSelectCount1 ) {
|
|
561
669
|
selectCount1();
|
|
562
|
-
select( 'store-1' ).
|
|
563
|
-
return 'count1';
|
|
670
|
+
return 'count1:' + select( 'store-1' ).get();
|
|
564
671
|
}
|
|
565
672
|
|
|
566
673
|
selectCount2();
|
|
567
|
-
select( 'store-2' ).
|
|
568
|
-
return 'count2';
|
|
674
|
+
return 'count2:' + select( 'store-2' ).get();
|
|
569
675
|
},
|
|
570
676
|
[ shouldSelectCount1 ]
|
|
571
677
|
);
|
|
@@ -587,29 +693,40 @@ describe( 'useSelect', () => {
|
|
|
587
693
|
expect( selectCount1 ).toHaveBeenCalledTimes( 0 );
|
|
588
694
|
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
589
695
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
590
|
-
'count2'
|
|
696
|
+
'count2:0'
|
|
591
697
|
);
|
|
592
698
|
|
|
593
699
|
act( () => screen.getByText( 'Toggle' ).click() );
|
|
594
700
|
|
|
701
|
+
expect( selectCount1 ).toHaveBeenCalledTimes( 1 );
|
|
702
|
+
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
703
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
704
|
+
'count1:0'
|
|
705
|
+
);
|
|
706
|
+
|
|
707
|
+
// Verify that the component subscribed to store-1 after selected from
|
|
708
|
+
act( () => {
|
|
709
|
+
registry.dispatch( 'store-1' ).inc();
|
|
710
|
+
} );
|
|
711
|
+
|
|
595
712
|
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
596
713
|
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
597
714
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
598
|
-
'count1'
|
|
715
|
+
'count1:1'
|
|
599
716
|
);
|
|
600
717
|
} );
|
|
601
718
|
|
|
602
719
|
it( "handles subscriptions to the parent's stores", () => {
|
|
603
|
-
registry.registerStore( 'parent-store', counterStore );
|
|
720
|
+
registry.registerStore( 'parent-store', counterStore() );
|
|
604
721
|
|
|
605
722
|
const subRegistry = createRegistry( {}, registry );
|
|
606
|
-
subRegistry.registerStore( 'child-store', counterStore );
|
|
723
|
+
subRegistry.registerStore( 'child-store', counterStore() );
|
|
607
724
|
|
|
608
725
|
const TestComponent = jest.fn( () => {
|
|
609
726
|
const state = useSelect(
|
|
610
727
|
( select ) => ( {
|
|
611
|
-
parentCount: select( 'parent-store' ).
|
|
612
|
-
childCount: select( 'child-store' ).
|
|
728
|
+
parentCount: select( 'parent-store' ).get(),
|
|
729
|
+
childCount: select( 'child-store' ).get(),
|
|
613
730
|
} ),
|
|
614
731
|
[]
|
|
615
732
|
);
|
|
@@ -634,7 +751,7 @@ describe( 'useSelect', () => {
|
|
|
634
751
|
);
|
|
635
752
|
|
|
636
753
|
act( () => {
|
|
637
|
-
registry.dispatch( 'parent-store' ).
|
|
754
|
+
registry.dispatch( 'parent-store' ).inc();
|
|
638
755
|
} );
|
|
639
756
|
|
|
640
757
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
@@ -643,13 +760,13 @@ describe( 'useSelect', () => {
|
|
|
643
760
|
} );
|
|
644
761
|
|
|
645
762
|
it( 'handles non-existing stores', () => {
|
|
646
|
-
registry.registerStore( 'store-1', counterStore );
|
|
763
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
647
764
|
|
|
648
765
|
const TestComponent = jest.fn( () => {
|
|
649
766
|
const state = useSelect(
|
|
650
767
|
( select ) => ( {
|
|
651
|
-
count1: select( 'store-1' ).
|
|
652
|
-
count2: select( 'store-2' )?.
|
|
768
|
+
count1: select( 'store-1' ).get(),
|
|
769
|
+
count2: select( 'store-2' )?.get() ?? 'blank',
|
|
653
770
|
} ),
|
|
654
771
|
[]
|
|
655
772
|
);
|
|
@@ -672,7 +789,7 @@ describe( 'useSelect', () => {
|
|
|
672
789
|
);
|
|
673
790
|
|
|
674
791
|
act( () => {
|
|
675
|
-
registry.dispatch( 'store-1' ).
|
|
792
|
+
registry.dispatch( 'store-1' ).inc();
|
|
676
793
|
} );
|
|
677
794
|
|
|
678
795
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
@@ -687,8 +804,7 @@ describe( 'useSelect', () => {
|
|
|
687
804
|
const TestComponent = jest.fn( () => {
|
|
688
805
|
const state = useSelect(
|
|
689
806
|
( select ) =>
|
|
690
|
-
select( 'not-yet-registered-store' )?.
|
|
691
|
-
'blank',
|
|
807
|
+
select( 'not-yet-registered-store' )?.get() ?? 'blank',
|
|
692
808
|
[]
|
|
693
809
|
);
|
|
694
810
|
|
|
@@ -706,7 +822,7 @@ describe( 'useSelect', () => {
|
|
|
706
822
|
act( () => {
|
|
707
823
|
registry.registerStore(
|
|
708
824
|
'not-yet-registered-store',
|
|
709
|
-
counterStore
|
|
825
|
+
counterStore()
|
|
710
826
|
);
|
|
711
827
|
} );
|
|
712
828
|
|
|
@@ -714,7 +830,7 @@ describe( 'useSelect', () => {
|
|
|
714
830
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( 'blank' );
|
|
715
831
|
|
|
716
832
|
act( () => {
|
|
717
|
-
registry.dispatch( 'not-yet-registered-store' ).
|
|
833
|
+
registry.dispatch( 'not-yet-registered-store' ).inc();
|
|
718
834
|
} );
|
|
719
835
|
|
|
720
836
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1' );
|
|
@@ -729,9 +845,8 @@ describe( 'useSelect', () => {
|
|
|
729
845
|
const TestComponent = jest.fn( () => {
|
|
730
846
|
const state = useSelect(
|
|
731
847
|
( select ) =>
|
|
732
|
-
select(
|
|
733
|
-
|
|
734
|
-
)?.getCounter() ?? 'blank',
|
|
848
|
+
select( 'not-yet-registered-child-store' )?.get() ??
|
|
849
|
+
'blank',
|
|
735
850
|
[]
|
|
736
851
|
);
|
|
737
852
|
|
|
@@ -751,7 +866,7 @@ describe( 'useSelect', () => {
|
|
|
751
866
|
act( () => {
|
|
752
867
|
registry.registerStore(
|
|
753
868
|
'not-yet-registered-child-store',
|
|
754
|
-
counterStore
|
|
869
|
+
counterStore()
|
|
755
870
|
);
|
|
756
871
|
} );
|
|
757
872
|
|
|
@@ -759,9 +874,7 @@ describe( 'useSelect', () => {
|
|
|
759
874
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( 'blank' );
|
|
760
875
|
|
|
761
876
|
act( () => {
|
|
762
|
-
registry
|
|
763
|
-
.dispatch( 'not-yet-registered-child-store' )
|
|
764
|
-
.increment();
|
|
877
|
+
registry.dispatch( 'not-yet-registered-child-store' ).inc();
|
|
765
878
|
} );
|
|
766
879
|
|
|
767
880
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1' );
|
|
@@ -778,11 +891,11 @@ describe( 'useSelect', () => {
|
|
|
778
891
|
let counter = 0;
|
|
779
892
|
|
|
780
893
|
const selectors = {
|
|
781
|
-
|
|
894
|
+
get: () => counter,
|
|
782
895
|
};
|
|
783
896
|
|
|
784
897
|
const actions = {
|
|
785
|
-
|
|
898
|
+
inc: () => {
|
|
786
899
|
counter += 1;
|
|
787
900
|
storeChanged();
|
|
788
901
|
},
|
|
@@ -806,7 +919,7 @@ describe( 'useSelect', () => {
|
|
|
806
919
|
|
|
807
920
|
const TestComponent = jest.fn( () => {
|
|
808
921
|
const state = useSelect(
|
|
809
|
-
( select ) => select( customStore ).
|
|
922
|
+
( select ) => select( customStore ).get(),
|
|
810
923
|
[]
|
|
811
924
|
);
|
|
812
925
|
|
|
@@ -822,7 +935,7 @@ describe( 'useSelect', () => {
|
|
|
822
935
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0' );
|
|
823
936
|
|
|
824
937
|
act( () => {
|
|
825
|
-
registry.dispatch( customStore ).
|
|
938
|
+
registry.dispatch( customStore ).inc();
|
|
826
939
|
} );
|
|
827
940
|
|
|
828
941
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1' );
|
|
@@ -832,25 +945,8 @@ describe( 'useSelect', () => {
|
|
|
832
945
|
} );
|
|
833
946
|
|
|
834
947
|
describe( 'async mode', () => {
|
|
835
|
-
function registerCounterStore( reg, initialCount = 0 ) {
|
|
836
|
-
reg.registerStore( 'counter', {
|
|
837
|
-
reducer: ( state = initialCount, action ) => {
|
|
838
|
-
if ( action.type === 'INCREMENT' ) {
|
|
839
|
-
return state + 1;
|
|
840
|
-
}
|
|
841
|
-
return state;
|
|
842
|
-
},
|
|
843
|
-
actions: {
|
|
844
|
-
inc: () => ( { type: 'INCREMENT' } ),
|
|
845
|
-
},
|
|
846
|
-
selectors: {
|
|
847
|
-
get: ( state ) => state,
|
|
848
|
-
},
|
|
849
|
-
} );
|
|
850
|
-
}
|
|
851
|
-
|
|
852
948
|
beforeEach( () => {
|
|
853
|
-
|
|
949
|
+
registry.registerStore( 'counter', counterStore() );
|
|
854
950
|
} );
|
|
855
951
|
|
|
856
952
|
it( 'renders with async mode', async () => {
|
|
@@ -1030,7 +1126,7 @@ describe( 'useSelect', () => {
|
|
|
1030
1126
|
|
|
1031
1127
|
it( 'cancels scheduled updates when registry changes', async () => {
|
|
1032
1128
|
const registry2 = createRegistry();
|
|
1033
|
-
|
|
1129
|
+
registry2.registerStore( 'counter', counterStore( 100 ) );
|
|
1034
1130
|
|
|
1035
1131
|
const selectSpy = jest.fn( ( select ) =>
|
|
1036
1132
|
select( 'counter' ).get()
|
|
@@ -1073,16 +1169,8 @@ describe( 'useSelect', () => {
|
|
|
1073
1169
|
} );
|
|
1074
1170
|
|
|
1075
1171
|
describe( 'usage without dependencies array', () => {
|
|
1076
|
-
function registerStore( name, initial ) {
|
|
1077
|
-
registry.registerStore( name, {
|
|
1078
|
-
reducer: ( s = initial, a ) => ( a.type === 'inc' ? s + 1 : s ),
|
|
1079
|
-
actions: { inc: () => ( { type: 'inc' } ) },
|
|
1080
|
-
selectors: { get: ( s ) => s },
|
|
1081
|
-
} );
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
1172
|
it( 'does not memoize the callback when there are no deps', () => {
|
|
1085
|
-
registerStore( 'store', 1 );
|
|
1173
|
+
registry.registerStore( 'store', counterStore( 1 ) );
|
|
1086
1174
|
|
|
1087
1175
|
const Status = ( { multiple } ) => {
|
|
1088
1176
|
const count = useSelect(
|
|
@@ -1106,9 +1194,9 @@ describe( 'useSelect', () => {
|
|
|
1106
1194
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '2' );
|
|
1107
1195
|
} );
|
|
1108
1196
|
|
|
1109
|
-
it( '
|
|
1110
|
-
registerStore( 'counter-1', 1 );
|
|
1111
|
-
registerStore( 'counter-2', 10 );
|
|
1197
|
+
it( 'resubscribes when the set of selected stores changes', () => {
|
|
1198
|
+
registry.registerStore( 'counter-1', counterStore( 1 ) );
|
|
1199
|
+
registry.registerStore( 'counter-2', counterStore( 10 ) );
|
|
1112
1200
|
|
|
1113
1201
|
const Status = ( { store } ) => {
|
|
1114
1202
|
const count = useSelect( ( select ) => select( store ).get() );
|
|
@@ -1135,21 +1223,17 @@ describe( 'useSelect', () => {
|
|
|
1135
1223
|
rerender( <App store="counter-2" /> );
|
|
1136
1224
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '10' );
|
|
1137
1225
|
|
|
1138
|
-
// update from counter-2 is
|
|
1226
|
+
// update from counter-2 is processed because component has subscribed to counter-2
|
|
1139
1227
|
act( () => {
|
|
1140
1228
|
registry.dispatch( 'counter-2' ).inc();
|
|
1141
1229
|
} );
|
|
1142
|
-
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '
|
|
1230
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '11' );
|
|
1143
1231
|
} );
|
|
1144
1232
|
} );
|
|
1145
1233
|
|
|
1146
1234
|
describe( 'static store selection mode', () => {
|
|
1147
1235
|
it( 'can read the current value from store', () => {
|
|
1148
|
-
registry.registerStore( 'testStore',
|
|
1149
|
-
reducer: ( s = 0, a ) => ( a.type === 'INC' ? s + 1 : s ),
|
|
1150
|
-
actions: { inc: () => ( { type: 'INC' } ) },
|
|
1151
|
-
selectors: { get: ( s ) => s },
|
|
1152
|
-
} );
|
|
1236
|
+
registry.registerStore( 'testStore', counterStore() );
|
|
1153
1237
|
|
|
1154
1238
|
const record = jest.fn();
|
|
1155
1239
|
|