@wordpress/data 8.5.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 +8 -0
- package/build/components/use-select/index.js +90 -55
- package/build/components/use-select/index.js.map +1 -1
- package/build/components/with-dispatch/index.js +2 -0
- package/build/components/with-dispatch/index.js.map +1 -1
- package/build/components/with-select/index.js +2 -0
- package/build/components/with-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/components/with-dispatch/index.js +2 -0
- package/build-module/components/with-dispatch/index.js.map +1 -1
- package/build-module/components/with-select/index.js +2 -0
- package/build-module/components/with-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/components/with-dispatch/index.d.ts +3 -1
- package/build-types/components/with-dispatch/index.d.ts.map +1 -1
- package/build-types/components/with-select/index.d.ts +3 -1
- package/build-types/components/with-select/index.d.ts.map +1 -1
- package/build-types/default-registry.d.ts +1 -1
- package/build-types/plugins/persistence/storage/object.d.ts +0 -3
- package/build-types/plugins/persistence/storage/object.d.ts.map +1 -1
- package/build-types/redux-store/metadata/reducer.d.ts +5 -5
- package/build-types/redux-store/metadata/reducer.d.ts.map +1 -1
- package/build-types/registry.d.ts.map +1 -1
- package/build-types/store/index.d.ts +0 -9
- package/build-types/store/index.d.ts.map +1 -1
- package/build-types/types.d.ts +16 -16
- package/build-types/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/components/use-dispatch/test/use-dispatch.js +0 -2
- package/src/components/use-select/index.js +87 -57
- package/src/components/use-select/test/index.js +246 -164
- package/src/components/use-select/test/suspense.js +0 -2
- package/src/components/with-dispatch/index.js +2 -0
- package/src/components/with-dispatch/test/index.js +0 -2
- package/src/components/with-select/index.js +2 -0
- package/src/components/with-select/test/index.js +0 -2
- package/src/redux-store/metadata/test/selectors.js +0 -1
- package/src/redux-store/test/index.js +0 -2
- package/src/registry.js +20 -8
- package/src/test/controls.js +0 -2
- package/src/test/privateAPIs.js +0 -13
- package/src/test/registry.js +32 -30
- 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,7 +19,18 @@ import {
|
|
|
19
19
|
} from '../../..';
|
|
20
20
|
import useSelect from '..';
|
|
21
21
|
|
|
22
|
-
|
|
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
|
+
}
|
|
23
34
|
|
|
24
35
|
describe( 'useSelect', () => {
|
|
25
36
|
let registry;
|
|
@@ -111,7 +122,7 @@ describe( 'useSelect', () => {
|
|
|
111
122
|
);
|
|
112
123
|
|
|
113
124
|
expect( selectSpyFoo ).toHaveBeenCalledTimes( 2 );
|
|
114
|
-
expect( selectSpyBar ).toHaveBeenCalledTimes(
|
|
125
|
+
expect( selectSpyBar ).toHaveBeenCalledTimes( 1 );
|
|
115
126
|
expect( TestComponent ).toHaveBeenCalledTimes( 3 );
|
|
116
127
|
|
|
117
128
|
// Ensure expected state was rendered.
|
|
@@ -182,6 +193,81 @@ describe( 'useSelect', () => {
|
|
|
182
193
|
expect( Child ).toHaveBeenCalledTimes( 1 );
|
|
183
194
|
} );
|
|
184
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
|
+
|
|
185
271
|
describe( 'rerenders as expected with various mapSelect return types', () => {
|
|
186
272
|
const getComponent = ( mapSelectSpy ) => () => {
|
|
187
273
|
const data = useSelect( mapSelectSpy, [] );
|
|
@@ -256,40 +342,20 @@ describe( 'useSelect', () => {
|
|
|
256
342
|
} );
|
|
257
343
|
|
|
258
344
|
describe( 're-calls the selector as few times as possible', () => {
|
|
259
|
-
const counterStore = {
|
|
260
|
-
actions: {
|
|
261
|
-
increment: () => ( { type: 'INCREMENT' } ),
|
|
262
|
-
},
|
|
263
|
-
reducer: ( state, action ) => {
|
|
264
|
-
if ( ! state ) {
|
|
265
|
-
return { counter: 0 };
|
|
266
|
-
}
|
|
267
|
-
if ( action?.type === 'INCREMENT' ) {
|
|
268
|
-
return { counter: state.counter + 1 };
|
|
269
|
-
}
|
|
270
|
-
return state;
|
|
271
|
-
},
|
|
272
|
-
selectors: {
|
|
273
|
-
getCounter: ( state ) => state.counter,
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
|
|
277
345
|
it( 'only calls the selectors it has selected', () => {
|
|
278
|
-
registry.registerStore( 'store-1', counterStore );
|
|
279
|
-
registry.registerStore( 'store-2', counterStore );
|
|
346
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
347
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
280
348
|
|
|
281
349
|
const selectCount1 = jest.fn();
|
|
282
350
|
const selectCount2 = jest.fn();
|
|
283
351
|
|
|
284
352
|
const TestComponent = jest.fn( () => {
|
|
285
353
|
const count1 = useSelect(
|
|
286
|
-
( select ) =>
|
|
287
|
-
selectCount1() || select( 'store-1' ).getCounter(),
|
|
354
|
+
( select ) => selectCount1() || select( 'store-1' ).get(),
|
|
288
355
|
[]
|
|
289
356
|
);
|
|
290
357
|
useSelect(
|
|
291
|
-
( select ) =>
|
|
292
|
-
selectCount2() || select( 'store-2' ).getCounter(),
|
|
358
|
+
( select ) => selectCount2() || select( 'store-2' ).get(),
|
|
293
359
|
[]
|
|
294
360
|
);
|
|
295
361
|
|
|
@@ -308,7 +374,7 @@ describe( 'useSelect', () => {
|
|
|
308
374
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0' );
|
|
309
375
|
|
|
310
376
|
act( () => {
|
|
311
|
-
registry.dispatch( 'store-2' ).
|
|
377
|
+
registry.dispatch( 'store-2' ).inc();
|
|
312
378
|
} );
|
|
313
379
|
|
|
314
380
|
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
@@ -317,7 +383,7 @@ describe( 'useSelect', () => {
|
|
|
317
383
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0' );
|
|
318
384
|
|
|
319
385
|
act( () => {
|
|
320
|
-
registry.dispatch( 'store-1' ).
|
|
386
|
+
registry.dispatch( 'store-1' ).inc();
|
|
321
387
|
} );
|
|
322
388
|
|
|
323
389
|
expect( selectCount1 ).toHaveBeenCalledTimes( 3 );
|
|
@@ -330,9 +396,9 @@ describe( 'useSelect', () => {
|
|
|
330
396
|
} );
|
|
331
397
|
|
|
332
398
|
it( 'can subscribe to multiple stores at once', () => {
|
|
333
|
-
registry.registerStore( 'store-1', counterStore );
|
|
334
|
-
registry.registerStore( 'store-2', counterStore );
|
|
335
|
-
registry.registerStore( 'store-3', counterStore );
|
|
399
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
400
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
401
|
+
registry.registerStore( 'store-3', counterStore() );
|
|
336
402
|
|
|
337
403
|
const selectCount1And2 = jest.fn();
|
|
338
404
|
|
|
@@ -340,8 +406,8 @@ describe( 'useSelect', () => {
|
|
|
340
406
|
const { count1, count2 } = useSelect(
|
|
341
407
|
( select ) =>
|
|
342
408
|
selectCount1And2() || {
|
|
343
|
-
count1: select( 'store-1' ).
|
|
344
|
-
count2: select( 'store-2' ).
|
|
409
|
+
count1: select( 'store-1' ).get(),
|
|
410
|
+
count2: select( 'store-2' ).get(),
|
|
345
411
|
},
|
|
346
412
|
[]
|
|
347
413
|
);
|
|
@@ -363,14 +429,14 @@ describe( 'useSelect', () => {
|
|
|
363
429
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0,0' );
|
|
364
430
|
|
|
365
431
|
act( () => {
|
|
366
|
-
registry.dispatch( 'store-2' ).
|
|
432
|
+
registry.dispatch( 'store-2' ).inc();
|
|
367
433
|
} );
|
|
368
434
|
|
|
369
435
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
370
436
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0,1' );
|
|
371
437
|
|
|
372
438
|
act( () => {
|
|
373
|
-
registry.dispatch( 'store-3' ).
|
|
439
|
+
registry.dispatch( 'store-3' ).inc();
|
|
374
440
|
} );
|
|
375
441
|
|
|
376
442
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
@@ -378,9 +444,9 @@ describe( 'useSelect', () => {
|
|
|
378
444
|
} );
|
|
379
445
|
|
|
380
446
|
it( 're-calls the selector when deps changed', () => {
|
|
381
|
-
registry.registerStore( 'store-1', counterStore );
|
|
382
|
-
registry.registerStore( 'store-2', counterStore );
|
|
383
|
-
registry.registerStore( 'store-3', counterStore );
|
|
447
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
448
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
449
|
+
registry.registerStore( 'store-3', counterStore() );
|
|
384
450
|
|
|
385
451
|
let dep, setDep;
|
|
386
452
|
const selectCount1AndDep = jest.fn();
|
|
@@ -390,7 +456,7 @@ describe( 'useSelect', () => {
|
|
|
390
456
|
const state = useSelect(
|
|
391
457
|
( select ) =>
|
|
392
458
|
selectCount1AndDep() || {
|
|
393
|
-
count1: select( 'store-1' ).
|
|
459
|
+
count1: select( 'store-1' ).get(),
|
|
394
460
|
dep,
|
|
395
461
|
},
|
|
396
462
|
[ dep ]
|
|
@@ -418,63 +484,40 @@ describe( 'useSelect', () => {
|
|
|
418
484
|
setDep( 1 );
|
|
419
485
|
} );
|
|
420
486
|
|
|
421
|
-
expect( selectCount1AndDep ).toHaveBeenCalledTimes(
|
|
487
|
+
expect( selectCount1AndDep ).toHaveBeenCalledTimes( 3 );
|
|
422
488
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
423
489
|
'count:0,dep:1'
|
|
424
490
|
);
|
|
425
491
|
|
|
426
492
|
act( () => {
|
|
427
|
-
registry.dispatch( 'store-1' ).
|
|
493
|
+
registry.dispatch( 'store-1' ).inc();
|
|
428
494
|
} );
|
|
429
495
|
|
|
430
|
-
expect( selectCount1AndDep ).toHaveBeenCalledTimes(
|
|
496
|
+
expect( selectCount1AndDep ).toHaveBeenCalledTimes( 4 );
|
|
431
497
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
432
498
|
'count:1,dep:1'
|
|
433
499
|
);
|
|
434
500
|
} );
|
|
435
501
|
|
|
436
|
-
it( 'captures state changes scheduled between render and
|
|
437
|
-
registry.registerStore( 'store-1', counterStore );
|
|
438
|
-
|
|
439
|
-
class ChildComponent extends Component {
|
|
440
|
-
componentDidUpdate( prevProps ) {
|
|
441
|
-
if (
|
|
442
|
-
this.props.childShouldDispatch &&
|
|
443
|
-
this.props.childShouldDispatch !==
|
|
444
|
-
prevProps.childShouldDispatch
|
|
445
|
-
) {
|
|
446
|
-
registry.dispatch( 'store-1' ).increment();
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
render() {
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
502
|
+
it( 'captures state changes scheduled between render and subscription', () => {
|
|
503
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
454
504
|
|
|
455
|
-
const
|
|
456
|
-
count1: select( 'store-1' ).
|
|
505
|
+
const selectCount1 = jest.fn( ( select ) => ( {
|
|
506
|
+
count1: select( 'store-1' ).get(),
|
|
457
507
|
} ) );
|
|
458
508
|
|
|
459
|
-
const TestComponent = () => {
|
|
460
|
-
const
|
|
461
|
-
useState( false );
|
|
462
|
-
const state = useSelect( selectCount1AndDep, [] );
|
|
509
|
+
const TestComponent = jest.fn( () => {
|
|
510
|
+
const { count1 } = useSelect( selectCount1, [] );
|
|
463
511
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
triggerChildDispatch
|
|
474
|
-
</button>
|
|
475
|
-
</>
|
|
476
|
-
);
|
|
477
|
-
};
|
|
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
|
+
} );
|
|
478
521
|
|
|
479
522
|
render(
|
|
480
523
|
<RegistryProvider value={ registry }>
|
|
@@ -482,30 +525,93 @@ describe( 'useSelect', () => {
|
|
|
482
525
|
</RegistryProvider>
|
|
483
526
|
);
|
|
484
527
|
|
|
485
|
-
|
|
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 );
|
|
486
531
|
|
|
487
|
-
|
|
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.
|
|
488
536
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
489
537
|
'count1:1'
|
|
490
538
|
);
|
|
491
539
|
} );
|
|
492
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
|
+
|
|
493
603
|
it( 'handles registry selectors', () => {
|
|
494
604
|
const getCount1And2 = createRegistrySelector(
|
|
495
605
|
( select ) => ( state ) => ( {
|
|
496
|
-
count1: state
|
|
497
|
-
count2: select( 'store-2' ).
|
|
606
|
+
count1: state,
|
|
607
|
+
count2: select( 'store-2' ).get(),
|
|
498
608
|
} )
|
|
499
609
|
);
|
|
500
610
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
getCount1And2,
|
|
506
|
-
},
|
|
507
|
-
} );
|
|
508
|
-
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() );
|
|
509
615
|
|
|
510
616
|
const selectCount1And2 = jest.fn();
|
|
511
617
|
|
|
@@ -536,7 +642,7 @@ describe( 'useSelect', () => {
|
|
|
536
642
|
);
|
|
537
643
|
|
|
538
644
|
act( () => {
|
|
539
|
-
registry.dispatch( 'store-2' ).
|
|
645
|
+
registry.dispatch( 'store-2' ).inc();
|
|
540
646
|
} );
|
|
541
647
|
|
|
542
648
|
expect( selectCount1And2 ).toHaveBeenCalledTimes( 3 );
|
|
@@ -546,8 +652,8 @@ describe( 'useSelect', () => {
|
|
|
546
652
|
} );
|
|
547
653
|
|
|
548
654
|
it( 'handles conditional statements in selectors', () => {
|
|
549
|
-
registry.registerStore( 'store-1', counterStore );
|
|
550
|
-
registry.registerStore( 'store-2', counterStore );
|
|
655
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
656
|
+
registry.registerStore( 'store-2', counterStore() );
|
|
551
657
|
|
|
552
658
|
const selectCount1 = jest.fn();
|
|
553
659
|
const selectCount2 = jest.fn();
|
|
@@ -561,13 +667,11 @@ describe( 'useSelect', () => {
|
|
|
561
667
|
( select ) => {
|
|
562
668
|
if ( shouldSelectCount1 ) {
|
|
563
669
|
selectCount1();
|
|
564
|
-
select( 'store-1' ).
|
|
565
|
-
return 'count1';
|
|
670
|
+
return 'count1:' + select( 'store-1' ).get();
|
|
566
671
|
}
|
|
567
672
|
|
|
568
673
|
selectCount2();
|
|
569
|
-
select( 'store-2' ).
|
|
570
|
-
return 'count2';
|
|
674
|
+
return 'count2:' + select( 'store-2' ).get();
|
|
571
675
|
},
|
|
572
676
|
[ shouldSelectCount1 ]
|
|
573
677
|
);
|
|
@@ -589,29 +693,40 @@ describe( 'useSelect', () => {
|
|
|
589
693
|
expect( selectCount1 ).toHaveBeenCalledTimes( 0 );
|
|
590
694
|
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
591
695
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
592
|
-
'count2'
|
|
696
|
+
'count2:0'
|
|
593
697
|
);
|
|
594
698
|
|
|
595
699
|
act( () => screen.getByText( 'Toggle' ).click() );
|
|
596
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
|
+
|
|
597
712
|
expect( selectCount1 ).toHaveBeenCalledTimes( 2 );
|
|
598
713
|
expect( selectCount2 ).toHaveBeenCalledTimes( 2 );
|
|
599
714
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
600
|
-
'count1'
|
|
715
|
+
'count1:1'
|
|
601
716
|
);
|
|
602
717
|
} );
|
|
603
718
|
|
|
604
719
|
it( "handles subscriptions to the parent's stores", () => {
|
|
605
|
-
registry.registerStore( 'parent-store', counterStore );
|
|
720
|
+
registry.registerStore( 'parent-store', counterStore() );
|
|
606
721
|
|
|
607
722
|
const subRegistry = createRegistry( {}, registry );
|
|
608
|
-
subRegistry.registerStore( 'child-store', counterStore );
|
|
723
|
+
subRegistry.registerStore( 'child-store', counterStore() );
|
|
609
724
|
|
|
610
725
|
const TestComponent = jest.fn( () => {
|
|
611
726
|
const state = useSelect(
|
|
612
727
|
( select ) => ( {
|
|
613
|
-
parentCount: select( 'parent-store' ).
|
|
614
|
-
childCount: select( 'child-store' ).
|
|
728
|
+
parentCount: select( 'parent-store' ).get(),
|
|
729
|
+
childCount: select( 'child-store' ).get(),
|
|
615
730
|
} ),
|
|
616
731
|
[]
|
|
617
732
|
);
|
|
@@ -636,7 +751,7 @@ describe( 'useSelect', () => {
|
|
|
636
751
|
);
|
|
637
752
|
|
|
638
753
|
act( () => {
|
|
639
|
-
registry.dispatch( 'parent-store' ).
|
|
754
|
+
registry.dispatch( 'parent-store' ).inc();
|
|
640
755
|
} );
|
|
641
756
|
|
|
642
757
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
@@ -645,13 +760,13 @@ describe( 'useSelect', () => {
|
|
|
645
760
|
} );
|
|
646
761
|
|
|
647
762
|
it( 'handles non-existing stores', () => {
|
|
648
|
-
registry.registerStore( 'store-1', counterStore );
|
|
763
|
+
registry.registerStore( 'store-1', counterStore() );
|
|
649
764
|
|
|
650
765
|
const TestComponent = jest.fn( () => {
|
|
651
766
|
const state = useSelect(
|
|
652
767
|
( select ) => ( {
|
|
653
|
-
count1: select( 'store-1' ).
|
|
654
|
-
count2: select( 'store-2' )?.
|
|
768
|
+
count1: select( 'store-1' ).get(),
|
|
769
|
+
count2: select( 'store-2' )?.get() ?? 'blank',
|
|
655
770
|
} ),
|
|
656
771
|
[]
|
|
657
772
|
);
|
|
@@ -674,7 +789,7 @@ describe( 'useSelect', () => {
|
|
|
674
789
|
);
|
|
675
790
|
|
|
676
791
|
act( () => {
|
|
677
|
-
registry.dispatch( 'store-1' ).
|
|
792
|
+
registry.dispatch( 'store-1' ).inc();
|
|
678
793
|
} );
|
|
679
794
|
|
|
680
795
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent(
|
|
@@ -689,8 +804,7 @@ describe( 'useSelect', () => {
|
|
|
689
804
|
const TestComponent = jest.fn( () => {
|
|
690
805
|
const state = useSelect(
|
|
691
806
|
( select ) =>
|
|
692
|
-
select( 'not-yet-registered-store' )?.
|
|
693
|
-
'blank',
|
|
807
|
+
select( 'not-yet-registered-store' )?.get() ?? 'blank',
|
|
694
808
|
[]
|
|
695
809
|
);
|
|
696
810
|
|
|
@@ -708,7 +822,7 @@ describe( 'useSelect', () => {
|
|
|
708
822
|
act( () => {
|
|
709
823
|
registry.registerStore(
|
|
710
824
|
'not-yet-registered-store',
|
|
711
|
-
counterStore
|
|
825
|
+
counterStore()
|
|
712
826
|
);
|
|
713
827
|
} );
|
|
714
828
|
|
|
@@ -716,7 +830,7 @@ describe( 'useSelect', () => {
|
|
|
716
830
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( 'blank' );
|
|
717
831
|
|
|
718
832
|
act( () => {
|
|
719
|
-
registry.dispatch( 'not-yet-registered-store' ).
|
|
833
|
+
registry.dispatch( 'not-yet-registered-store' ).inc();
|
|
720
834
|
} );
|
|
721
835
|
|
|
722
836
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1' );
|
|
@@ -731,9 +845,8 @@ describe( 'useSelect', () => {
|
|
|
731
845
|
const TestComponent = jest.fn( () => {
|
|
732
846
|
const state = useSelect(
|
|
733
847
|
( select ) =>
|
|
734
|
-
select(
|
|
735
|
-
|
|
736
|
-
)?.getCounter() ?? 'blank',
|
|
848
|
+
select( 'not-yet-registered-child-store' )?.get() ??
|
|
849
|
+
'blank',
|
|
737
850
|
[]
|
|
738
851
|
);
|
|
739
852
|
|
|
@@ -753,7 +866,7 @@ describe( 'useSelect', () => {
|
|
|
753
866
|
act( () => {
|
|
754
867
|
registry.registerStore(
|
|
755
868
|
'not-yet-registered-child-store',
|
|
756
|
-
counterStore
|
|
869
|
+
counterStore()
|
|
757
870
|
);
|
|
758
871
|
} );
|
|
759
872
|
|
|
@@ -761,9 +874,7 @@ describe( 'useSelect', () => {
|
|
|
761
874
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( 'blank' );
|
|
762
875
|
|
|
763
876
|
act( () => {
|
|
764
|
-
registry
|
|
765
|
-
.dispatch( 'not-yet-registered-child-store' )
|
|
766
|
-
.increment();
|
|
877
|
+
registry.dispatch( 'not-yet-registered-child-store' ).inc();
|
|
767
878
|
} );
|
|
768
879
|
|
|
769
880
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1' );
|
|
@@ -780,11 +891,11 @@ describe( 'useSelect', () => {
|
|
|
780
891
|
let counter = 0;
|
|
781
892
|
|
|
782
893
|
const selectors = {
|
|
783
|
-
|
|
894
|
+
get: () => counter,
|
|
784
895
|
};
|
|
785
896
|
|
|
786
897
|
const actions = {
|
|
787
|
-
|
|
898
|
+
inc: () => {
|
|
788
899
|
counter += 1;
|
|
789
900
|
storeChanged();
|
|
790
901
|
},
|
|
@@ -808,7 +919,7 @@ describe( 'useSelect', () => {
|
|
|
808
919
|
|
|
809
920
|
const TestComponent = jest.fn( () => {
|
|
810
921
|
const state = useSelect(
|
|
811
|
-
( select ) => select( customStore ).
|
|
922
|
+
( select ) => select( customStore ).get(),
|
|
812
923
|
[]
|
|
813
924
|
);
|
|
814
925
|
|
|
@@ -824,7 +935,7 @@ describe( 'useSelect', () => {
|
|
|
824
935
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '0' );
|
|
825
936
|
|
|
826
937
|
act( () => {
|
|
827
|
-
registry.dispatch( customStore ).
|
|
938
|
+
registry.dispatch( customStore ).inc();
|
|
828
939
|
} );
|
|
829
940
|
|
|
830
941
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '1' );
|
|
@@ -834,25 +945,8 @@ describe( 'useSelect', () => {
|
|
|
834
945
|
} );
|
|
835
946
|
|
|
836
947
|
describe( 'async mode', () => {
|
|
837
|
-
function registerCounterStore( reg, initialCount = 0 ) {
|
|
838
|
-
reg.registerStore( 'counter', {
|
|
839
|
-
reducer: ( state = initialCount, action ) => {
|
|
840
|
-
if ( action.type === 'INCREMENT' ) {
|
|
841
|
-
return state + 1;
|
|
842
|
-
}
|
|
843
|
-
return state;
|
|
844
|
-
},
|
|
845
|
-
actions: {
|
|
846
|
-
inc: () => ( { type: 'INCREMENT' } ),
|
|
847
|
-
},
|
|
848
|
-
selectors: {
|
|
849
|
-
get: ( state ) => state,
|
|
850
|
-
},
|
|
851
|
-
} );
|
|
852
|
-
}
|
|
853
|
-
|
|
854
948
|
beforeEach( () => {
|
|
855
|
-
|
|
949
|
+
registry.registerStore( 'counter', counterStore() );
|
|
856
950
|
} );
|
|
857
951
|
|
|
858
952
|
it( 'renders with async mode', async () => {
|
|
@@ -1032,7 +1126,7 @@ describe( 'useSelect', () => {
|
|
|
1032
1126
|
|
|
1033
1127
|
it( 'cancels scheduled updates when registry changes', async () => {
|
|
1034
1128
|
const registry2 = createRegistry();
|
|
1035
|
-
|
|
1129
|
+
registry2.registerStore( 'counter', counterStore( 100 ) );
|
|
1036
1130
|
|
|
1037
1131
|
const selectSpy = jest.fn( ( select ) =>
|
|
1038
1132
|
select( 'counter' ).get()
|
|
@@ -1075,16 +1169,8 @@ describe( 'useSelect', () => {
|
|
|
1075
1169
|
} );
|
|
1076
1170
|
|
|
1077
1171
|
describe( 'usage without dependencies array', () => {
|
|
1078
|
-
function registerStore( name, initial ) {
|
|
1079
|
-
registry.registerStore( name, {
|
|
1080
|
-
reducer: ( s = initial, a ) => ( a.type === 'inc' ? s + 1 : s ),
|
|
1081
|
-
actions: { inc: () => ( { type: 'inc' } ) },
|
|
1082
|
-
selectors: { get: ( s ) => s },
|
|
1083
|
-
} );
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
1172
|
it( 'does not memoize the callback when there are no deps', () => {
|
|
1087
|
-
registerStore( 'store', 1 );
|
|
1173
|
+
registry.registerStore( 'store', counterStore( 1 ) );
|
|
1088
1174
|
|
|
1089
1175
|
const Status = ( { multiple } ) => {
|
|
1090
1176
|
const count = useSelect(
|
|
@@ -1108,9 +1194,9 @@ describe( 'useSelect', () => {
|
|
|
1108
1194
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '2' );
|
|
1109
1195
|
} );
|
|
1110
1196
|
|
|
1111
|
-
it( '
|
|
1112
|
-
registerStore( 'counter-1', 1 );
|
|
1113
|
-
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 ) );
|
|
1114
1200
|
|
|
1115
1201
|
const Status = ( { store } ) => {
|
|
1116
1202
|
const count = useSelect( ( select ) => select( store ).get() );
|
|
@@ -1137,21 +1223,17 @@ describe( 'useSelect', () => {
|
|
|
1137
1223
|
rerender( <App store="counter-2" /> );
|
|
1138
1224
|
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '10' );
|
|
1139
1225
|
|
|
1140
|
-
// update from counter-2 is
|
|
1226
|
+
// update from counter-2 is processed because component has subscribed to counter-2
|
|
1141
1227
|
act( () => {
|
|
1142
1228
|
registry.dispatch( 'counter-2' ).inc();
|
|
1143
1229
|
} );
|
|
1144
|
-
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '
|
|
1230
|
+
expect( screen.getByRole( 'status' ) ).toHaveTextContent( '11' );
|
|
1145
1231
|
} );
|
|
1146
1232
|
} );
|
|
1147
1233
|
|
|
1148
1234
|
describe( 'static store selection mode', () => {
|
|
1149
1235
|
it( 'can read the current value from store', () => {
|
|
1150
|
-
registry.registerStore( 'testStore',
|
|
1151
|
-
reducer: ( s = 0, a ) => ( a.type === 'INC' ? s + 1 : s ),
|
|
1152
|
-
actions: { inc: () => ( { type: 'INC' } ) },
|
|
1153
|
-
selectors: { get: ( s ) => s },
|
|
1154
|
-
} );
|
|
1236
|
+
registry.registerStore( 'testStore', counterStore() );
|
|
1155
1237
|
|
|
1156
1238
|
const record = jest.fn();
|
|
1157
1239
|
|