@wordpress/abilities 0.2.1-next.8b30e05b0.0 → 0.3.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +32 -40
  3. package/build/api.js +19 -66
  4. package/build/api.js.map +3 -3
  5. package/build/index.js.map +2 -2
  6. package/build/store/actions.js +41 -31
  7. package/build/store/actions.js.map +2 -2
  8. package/build/store/constants.js +6 -15
  9. package/build/store/constants.js.map +2 -2
  10. package/build/store/index.js +1 -27
  11. package/build/store/index.js.map +3 -3
  12. package/build/store/reducer.js +2 -22
  13. package/build/store/reducer.js.map +2 -2
  14. package/build/store/selectors.js +1 -1
  15. package/build/store/selectors.js.map +2 -2
  16. package/build/store/types.js +19 -0
  17. package/build/store/types.js.map +7 -0
  18. package/build/types.js.map +1 -1
  19. package/build-module/api.js +20 -57
  20. package/build-module/api.js.map +2 -2
  21. package/build-module/index.js.map +2 -2
  22. package/build-module/store/actions.js +43 -32
  23. package/build-module/store/actions.js.map +2 -2
  24. package/build-module/store/constants.js +4 -10
  25. package/build-module/store/constants.js.map +2 -2
  26. package/build-module/store/index.js +3 -34
  27. package/build-module/store/index.js.map +2 -2
  28. package/build-module/store/reducer.js +2 -24
  29. package/build-module/store/reducer.js.map +2 -2
  30. package/build-module/store/selectors.js +1 -1
  31. package/build-module/store/selectors.js.map +2 -2
  32. package/build-module/store/types.js +1 -0
  33. package/build-module/store/types.js.map +7 -0
  34. package/build-types/api.d.ts +16 -23
  35. package/build-types/api.d.ts.map +1 -1
  36. package/build-types/index.d.ts +1 -1
  37. package/build-types/index.d.ts.map +1 -1
  38. package/build-types/store/actions.d.ts +5 -27
  39. package/build-types/store/actions.d.ts.map +1 -1
  40. package/build-types/store/constants.d.ts +2 -5
  41. package/build-types/store/constants.d.ts.map +1 -1
  42. package/build-types/store/index.d.ts.map +1 -1
  43. package/build-types/store/reducer.d.ts +21 -11
  44. package/build-types/store/reducer.d.ts.map +1 -1
  45. package/build-types/store/selectors.d.ts +2 -1
  46. package/build-types/store/selectors.d.ts.map +1 -1
  47. package/build-types/store/types.d.ts +18 -0
  48. package/build-types/store/types.d.ts.map +1 -0
  49. package/build-types/types.d.ts +14 -24
  50. package/build-types/types.d.ts.map +1 -1
  51. package/package.json +4 -7
  52. package/src/api.ts +43 -123
  53. package/src/index.ts +0 -1
  54. package/src/store/actions.ts +61 -46
  55. package/src/store/constants.ts +4 -5
  56. package/src/store/index.ts +2 -34
  57. package/src/store/reducer.ts +27 -33
  58. package/src/store/selectors.ts +3 -7
  59. package/src/store/tests/actions.test.ts +100 -244
  60. package/src/store/tests/reducer.test.ts +0 -451
  61. package/src/store/tests/selectors.test.ts +1 -1
  62. package/src/store/types.ts +19 -0
  63. package/src/tests/api.test.ts +112 -158
  64. package/src/types.ts +14 -26
  65. package/build/store/resolvers.js +0 -107
  66. package/build/store/resolvers.js.map +0 -7
  67. package/build-module/store/resolvers.js +0 -84
  68. package/build-module/store/resolvers.js.map +0 -7
  69. package/build-types/store/resolvers.d.ts +0 -47
  70. package/build-types/store/resolvers.d.ts.map +0 -1
  71. package/src/store/resolvers.ts +0 -151
  72. package/src/store/tests/resolvers.test.ts +0 -642
@@ -1,642 +0,0 @@
1
- /**
2
- * Tests for store resolvers.
3
- */
4
-
5
- /**
6
- * WordPress dependencies
7
- */
8
- import { store as coreStore } from '@wordpress/core-data';
9
-
10
- /**
11
- * Internal dependencies
12
- */
13
- import {
14
- getAbilities,
15
- getAbility,
16
- getAbilityCategories,
17
- getAbilityCategory,
18
- } from '../resolvers';
19
- import { receiveAbilities, receiveCategories } from '../actions';
20
- import { ENTITY_KIND, ENTITY_NAME, ENTITY_NAME_CATEGORIES } from '../constants';
21
- import type { Ability, AbilityCategory } from '../../types';
22
-
23
- // Mock the WordPress core data store
24
- jest.mock( '@wordpress/core-data', () => ( {
25
- store: 'core',
26
- } ) );
27
-
28
- describe( 'Store Resolvers', () => {
29
- let mockDispatch: jest.Mock;
30
- let mockRegistry: any;
31
- let mockSelect: any;
32
-
33
- beforeEach( () => {
34
- mockDispatch = jest.fn();
35
- mockSelect = jest.fn();
36
- mockRegistry = {
37
- resolveSelect: jest.fn(),
38
- select: jest.fn(),
39
- };
40
- } );
41
-
42
- describe( 'getAbilities', () => {
43
- it( 'should fetch and dispatch abilities from the server', async () => {
44
- const mockAbilities: Ability[] = [
45
- {
46
- name: 'test/ability1',
47
- label: 'Test Ability 1',
48
- description: 'First test ability',
49
- category: 'test-category',
50
- input_schema: { type: 'object' },
51
- output_schema: { type: 'object' },
52
- },
53
- ];
54
-
55
- const mockResolveSelect = {
56
- getEntityRecords: jest.fn().mockResolvedValue( mockAbilities ),
57
- };
58
-
59
- const mockSelectInstance = {
60
- getAbilities: jest.fn().mockReturnValue( [] ), // Store is empty
61
- };
62
-
63
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
64
-
65
- const resolver = getAbilities();
66
- await resolver( {
67
- dispatch: mockDispatch,
68
- registry: mockRegistry,
69
- select: mockSelectInstance,
70
- } );
71
-
72
- expect( mockRegistry.resolveSelect ).toHaveBeenCalledWith(
73
- coreStore
74
- );
75
- expect( mockResolveSelect.getEntityRecords ).toHaveBeenCalledWith(
76
- ENTITY_KIND,
77
- ENTITY_NAME,
78
- { per_page: -1 }
79
- );
80
- expect( mockDispatch ).toHaveBeenCalledWith(
81
- receiveAbilities( mockAbilities )
82
- );
83
- } );
84
-
85
- it( 'should not fetch if store already has abilities', async () => {
86
- const existingAbilities: Ability[] = [
87
- {
88
- name: 'test/ability1',
89
- label: 'Test Ability 1',
90
- description: 'First test ability',
91
- category: 'data-retrieval',
92
- input_schema: { type: 'object' },
93
- output_schema: { type: 'object' },
94
- },
95
- ];
96
-
97
- const mockResolveSelect = {
98
- getEntityRecords: jest.fn(),
99
- };
100
-
101
- const mockSelectInstance = {
102
- getAbilities: jest.fn().mockReturnValue( existingAbilities ), // Store has data
103
- };
104
-
105
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
106
-
107
- const resolver = getAbilities( { category: 'data-retrieval' } );
108
- await resolver( {
109
- dispatch: mockDispatch,
110
- registry: mockRegistry,
111
- select: mockSelectInstance,
112
- } );
113
-
114
- // Should not fetch since store already has abilities
115
- expect( mockResolveSelect.getEntityRecords ).not.toHaveBeenCalled();
116
- expect( mockDispatch ).not.toHaveBeenCalled();
117
- } );
118
-
119
- it( 'should handle empty abilities', async () => {
120
- const mockResolveSelect = {
121
- getEntityRecords: jest.fn().mockResolvedValue( [] ),
122
- };
123
-
124
- const mockSelectInstance = {
125
- getAbilities: jest.fn().mockReturnValue( [] ), // Store is empty
126
- };
127
-
128
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
129
-
130
- const resolver = getAbilities();
131
- await resolver( {
132
- dispatch: mockDispatch,
133
- registry: mockRegistry,
134
- select: mockSelectInstance,
135
- } );
136
-
137
- expect( mockDispatch ).toHaveBeenCalledWith(
138
- receiveAbilities( [] )
139
- );
140
- } );
141
-
142
- it( 'should handle null response', async () => {
143
- const mockResolveSelect = {
144
- getEntityRecords: jest.fn().mockResolvedValue( null ),
145
- };
146
-
147
- const mockSelectInstance = {
148
- getAbilities: jest.fn().mockReturnValue( [] ), // Store is empty
149
- };
150
-
151
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
152
-
153
- const resolver = getAbilities();
154
- await resolver( {
155
- dispatch: mockDispatch,
156
- registry: mockRegistry,
157
- select: mockSelectInstance,
158
- } );
159
-
160
- expect( mockDispatch ).toHaveBeenCalledWith(
161
- receiveAbilities( [] )
162
- );
163
- } );
164
-
165
- it( 'should fetch all abilities in a single request', async () => {
166
- const allAbilities: Ability[] = [
167
- {
168
- name: 'test/ability1',
169
- label: 'Test Ability 1',
170
- description: 'First test ability',
171
- category: 'test-category',
172
- input_schema: { type: 'object' },
173
- output_schema: { type: 'object' },
174
- },
175
- {
176
- name: 'test/ability2',
177
- label: 'Test Ability 2',
178
- description: 'Second test ability',
179
- category: 'test-category',
180
- input_schema: { type: 'object' },
181
- output_schema: { type: 'object' },
182
- },
183
- {
184
- name: 'test/ability3',
185
- label: 'Test Ability 3',
186
- description: 'Third test ability',
187
- category: 'test-category',
188
- input_schema: { type: 'object' },
189
- output_schema: { type: 'object' },
190
- },
191
- ];
192
-
193
- const mockResolveSelect = {
194
- getEntityRecords: jest.fn().mockResolvedValue( allAbilities ),
195
- };
196
-
197
- const mockSelectInstance = {
198
- getAbilities: jest.fn().mockReturnValue( [] ), // Store is empty
199
- };
200
-
201
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
202
-
203
- const resolver = getAbilities();
204
- await resolver( {
205
- dispatch: mockDispatch,
206
- registry: mockRegistry,
207
- select: mockSelectInstance,
208
- } );
209
-
210
- // Should fetch all abilities in one request with per_page: -1
211
- expect( mockResolveSelect.getEntityRecords ).toHaveBeenCalledTimes(
212
- 1
213
- );
214
- expect(
215
- mockResolveSelect.getEntityRecords
216
- ).toHaveBeenNthCalledWith( 1, ENTITY_KIND, ENTITY_NAME, {
217
- per_page: -1,
218
- } );
219
-
220
- // Should dispatch all abilities
221
- expect( mockDispatch ).toHaveBeenCalledWith(
222
- receiveAbilities( allAbilities )
223
- );
224
- } );
225
- } );
226
-
227
- describe( 'getAbility', () => {
228
- it( 'should fetch and dispatch a specific ability', async () => {
229
- const mockAbility: Ability = {
230
- name: 'test/ability',
231
- label: 'Test Ability',
232
- description: 'Test ability description',
233
- category: 'test-category',
234
- input_schema: { type: 'object' },
235
- output_schema: { type: 'object' },
236
- };
237
-
238
- const mockResolveSelect = {
239
- getEntityRecord: jest.fn().mockResolvedValue( mockAbility ),
240
- };
241
-
242
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
243
- mockSelect.getAbility = jest.fn().mockReturnValue( null ); // Ability not in store
244
-
245
- const resolver = getAbility( 'test/ability' );
246
- await resolver( {
247
- dispatch: mockDispatch,
248
- registry: mockRegistry,
249
- select: mockSelect,
250
- } );
251
-
252
- expect( mockSelect.getAbility ).toHaveBeenCalledWith(
253
- 'test/ability'
254
- );
255
- expect( mockRegistry.resolveSelect ).toHaveBeenCalledWith(
256
- coreStore
257
- );
258
- expect( mockResolveSelect.getEntityRecord ).toHaveBeenCalledWith(
259
- ENTITY_KIND,
260
- ENTITY_NAME,
261
- 'test/ability'
262
- );
263
- // registerAbility returns a thunk, so we just verify dispatch was called
264
- expect( mockDispatch ).toHaveBeenCalled();
265
- expect( typeof mockDispatch.mock.calls[ 0 ][ 0 ] ).toBe(
266
- 'function'
267
- );
268
- } );
269
-
270
- it( 'should not fetch if ability already exists in store', async () => {
271
- const existingAbility: Ability = {
272
- name: 'test/ability',
273
- label: 'Test Ability',
274
- description: 'Already in store',
275
- category: 'test-category',
276
- input_schema: { type: 'object' },
277
- output_schema: { type: 'object' },
278
- callback: jest.fn(),
279
- };
280
-
281
- mockSelect.getAbility = jest
282
- .fn()
283
- .mockReturnValue( existingAbility );
284
-
285
- const resolver = getAbility( 'test/ability' );
286
- await resolver( {
287
- dispatch: mockDispatch,
288
- registry: mockRegistry,
289
- select: mockSelect,
290
- } );
291
-
292
- expect( mockSelect.getAbility ).toHaveBeenCalledWith(
293
- 'test/ability'
294
- );
295
- expect( mockRegistry.resolveSelect ).not.toHaveBeenCalled();
296
- expect( mockDispatch ).not.toHaveBeenCalled();
297
- } );
298
-
299
- it( 'should handle non-existent abilities', async () => {
300
- const mockResolveSelect = {
301
- getEntityRecord: jest.fn().mockResolvedValue( null ),
302
- };
303
-
304
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
305
- mockSelect.getAbility = jest.fn().mockReturnValue( null );
306
-
307
- const resolver = getAbility( 'non-existent' );
308
- await resolver( {
309
- dispatch: mockDispatch,
310
- registry: mockRegistry,
311
- select: mockSelect,
312
- } );
313
-
314
- expect( mockResolveSelect.getEntityRecord ).toHaveBeenCalledWith(
315
- ENTITY_KIND,
316
- ENTITY_NAME,
317
- 'non-existent'
318
- );
319
- expect( mockDispatch ).not.toHaveBeenCalled();
320
- } );
321
-
322
- it( 'should handle valid namespaced ability names', async () => {
323
- const mockAbility: Ability = {
324
- name: 'my-plugin/feature-action',
325
- label: 'Namespaced Action',
326
- description: 'Namespaced ability',
327
- category: 'test-category',
328
- input_schema: { type: 'object' },
329
- output_schema: { type: 'object' },
330
- };
331
-
332
- const mockResolveSelect = {
333
- getEntityRecord: jest.fn().mockResolvedValue( mockAbility ),
334
- };
335
-
336
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
337
- mockSelect.getAbility = jest.fn().mockReturnValue( null );
338
-
339
- const resolver = getAbility( 'my-plugin/feature-action' );
340
- await resolver( {
341
- dispatch: mockDispatch,
342
- registry: mockRegistry,
343
- select: mockSelect,
344
- } );
345
-
346
- expect( mockResolveSelect.getEntityRecord ).toHaveBeenCalledWith(
347
- ENTITY_KIND,
348
- ENTITY_NAME,
349
- 'my-plugin/feature-action'
350
- );
351
- // registerAbility returns a thunk, so we just verify dispatch was called
352
- expect( mockDispatch ).toHaveBeenCalled();
353
- expect( typeof mockDispatch.mock.calls[ 0 ][ 0 ] ).toBe(
354
- 'function'
355
- );
356
- } );
357
- } );
358
-
359
- describe( 'getAbilityCategories', () => {
360
- it( 'should fetch and dispatch categories from the server', async () => {
361
- const mockCategories: AbilityCategory[] = [
362
- {
363
- slug: 'data-retrieval',
364
- label: 'Data Retrieval',
365
- description: 'Abilities that retrieve data',
366
- },
367
- {
368
- slug: 'user-management',
369
- label: 'User Management',
370
- description: 'Abilities for managing users',
371
- },
372
- ];
373
-
374
- const mockResolveSelect = {
375
- getEntityRecords: jest.fn().mockResolvedValue( mockCategories ),
376
- };
377
-
378
- const mockSelectInstance = {
379
- getAbilityCategories: jest.fn().mockReturnValue( [] ),
380
- };
381
-
382
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
383
-
384
- const resolver = getAbilityCategories();
385
- await resolver( {
386
- dispatch: mockDispatch,
387
- registry: mockRegistry,
388
- select: mockSelectInstance,
389
- } );
390
-
391
- expect( mockRegistry.resolveSelect ).toHaveBeenCalledWith(
392
- coreStore
393
- );
394
- expect( mockResolveSelect.getEntityRecords ).toHaveBeenCalledWith(
395
- ENTITY_KIND,
396
- ENTITY_NAME_CATEGORIES,
397
- { per_page: -1 }
398
- );
399
- expect( mockDispatch ).toHaveBeenCalledWith(
400
- receiveCategories( mockCategories )
401
- );
402
- } );
403
-
404
- it( 'should not fetch if store already has categories', async () => {
405
- const existingCategories: AbilityCategory[] = [
406
- {
407
- slug: 'data-retrieval',
408
- label: 'Data Retrieval',
409
- description: 'Abilities that retrieve data',
410
- },
411
- ];
412
-
413
- const mockResolveSelect = {
414
- getEntityRecords: jest.fn(),
415
- };
416
-
417
- const mockSelectInstance = {
418
- getAbilityCategories: jest
419
- .fn()
420
- .mockReturnValue( existingCategories ),
421
- };
422
-
423
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
424
-
425
- const resolver = getAbilityCategories();
426
- await resolver( {
427
- dispatch: mockDispatch,
428
- registry: mockRegistry,
429
- select: mockSelectInstance,
430
- } );
431
-
432
- // Should not fetch since store already has categories
433
- expect( mockResolveSelect.getEntityRecords ).not.toHaveBeenCalled();
434
- expect( mockDispatch ).not.toHaveBeenCalled();
435
- } );
436
-
437
- it( 'should fetch from server even when only client-registered categories exist', async () => {
438
- // This tests the scenario where a client category is registered first
439
- // The resolver should still fetch server categories
440
- const clientOnlyCategories: AbilityCategory[] = [
441
- {
442
- slug: 'client-category',
443
- label: 'Client Category',
444
- description: 'A category registered on the client',
445
- meta: {
446
- _clientRegistered: true,
447
- },
448
- },
449
- ];
450
-
451
- const serverCategories: AbilityCategory[] = [
452
- {
453
- slug: 'data-retrieval',
454
- label: 'Data Retrieval',
455
- description: 'Server category',
456
- },
457
- {
458
- slug: 'user-management',
459
- label: 'User Management',
460
- description: 'Another server category',
461
- },
462
- ];
463
-
464
- const mockResolveSelect = {
465
- getEntityRecords: jest
466
- .fn()
467
- .mockResolvedValue( serverCategories ),
468
- };
469
-
470
- const mockSelectInstance = {
471
- getAbilityCategories: jest
472
- .fn()
473
- .mockReturnValue( clientOnlyCategories ),
474
- };
475
-
476
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
477
-
478
- const resolver = getAbilityCategories();
479
- await resolver( {
480
- dispatch: mockDispatch,
481
- registry: mockRegistry,
482
- select: mockSelectInstance,
483
- } );
484
-
485
- // Should fetch from server because only client categories exist
486
- expect( mockRegistry.resolveSelect ).toHaveBeenCalledWith(
487
- coreStore
488
- );
489
- expect( mockResolveSelect.getEntityRecords ).toHaveBeenCalledWith(
490
- ENTITY_KIND,
491
- ENTITY_NAME_CATEGORIES,
492
- { per_page: -1 }
493
- );
494
- expect( mockDispatch ).toHaveBeenCalledWith(
495
- receiveCategories( serverCategories )
496
- );
497
- } );
498
-
499
- it( 'should handle null response', async () => {
500
- const mockResolveSelect = {
501
- getEntityRecords: jest.fn().mockResolvedValue( null ),
502
- };
503
-
504
- const mockSelectInstance = {
505
- getAbilityCategories: jest.fn().mockReturnValue( [] ),
506
- };
507
-
508
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
509
-
510
- const resolver = getAbilityCategories();
511
- await resolver( {
512
- dispatch: mockDispatch,
513
- registry: mockRegistry,
514
- select: mockSelectInstance,
515
- } );
516
-
517
- expect( mockDispatch ).toHaveBeenCalledWith(
518
- receiveCategories( [] )
519
- );
520
- } );
521
- } );
522
-
523
- describe( 'getAbilityCategory', () => {
524
- it( 'should fetch and dispatch a specific category', async () => {
525
- const mockCategory: AbilityCategory = {
526
- slug: 'data-retrieval',
527
- label: 'Data Retrieval',
528
- description: 'Abilities that retrieve data',
529
- };
530
-
531
- const mockResolveSelect = {
532
- getEntityRecord: jest.fn().mockResolvedValue( mockCategory ),
533
- };
534
-
535
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
536
- mockSelect.getAbilityCategory = jest.fn().mockReturnValue( null );
537
-
538
- const resolver = getAbilityCategory( 'data-retrieval' );
539
- await resolver( {
540
- dispatch: mockDispatch,
541
- registry: mockRegistry,
542
- select: mockSelect,
543
- } );
544
-
545
- expect( mockSelect.getAbilityCategory ).toHaveBeenCalledWith(
546
- 'data-retrieval'
547
- );
548
- expect( mockRegistry.resolveSelect ).toHaveBeenCalledWith(
549
- coreStore
550
- );
551
- expect( mockResolveSelect.getEntityRecord ).toHaveBeenCalledWith(
552
- ENTITY_KIND,
553
- ENTITY_NAME_CATEGORIES,
554
- 'data-retrieval'
555
- );
556
- // registerAbilityCategory returns a thunk, so we just verify dispatch was called
557
- expect( mockDispatch ).toHaveBeenCalled();
558
- expect( typeof mockDispatch.mock.calls[ 0 ][ 0 ] ).toBe(
559
- 'function'
560
- );
561
- } );
562
-
563
- it( 'should not fetch if category already exists in store', async () => {
564
- const existingCategory: AbilityCategory = {
565
- slug: 'data-retrieval',
566
- label: 'Data Retrieval',
567
- description: 'Already in store',
568
- };
569
-
570
- mockSelect.getAbilityCategory = jest
571
- .fn()
572
- .mockReturnValue( existingCategory );
573
-
574
- const resolver = getAbilityCategory( 'data-retrieval' );
575
- await resolver( {
576
- dispatch: mockDispatch,
577
- registry: mockRegistry,
578
- select: mockSelect,
579
- } );
580
-
581
- expect( mockSelect.getAbilityCategory ).toHaveBeenCalledWith(
582
- 'data-retrieval'
583
- );
584
- expect( mockRegistry.resolveSelect ).not.toHaveBeenCalled();
585
- expect( mockDispatch ).not.toHaveBeenCalled();
586
- } );
587
-
588
- it( 'should handle non-existent categories', async () => {
589
- const mockResolveSelect = {
590
- getEntityRecord: jest.fn().mockResolvedValue( null ),
591
- };
592
-
593
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
594
- mockSelect.getAbilityCategory = jest.fn().mockReturnValue( null );
595
-
596
- const resolver = getAbilityCategory( 'non-existent' );
597
- await resolver( {
598
- dispatch: mockDispatch,
599
- registry: mockRegistry,
600
- select: mockSelect,
601
- } );
602
-
603
- expect( mockResolveSelect.getEntityRecord ).toHaveBeenCalledWith(
604
- ENTITY_KIND,
605
- ENTITY_NAME_CATEGORIES,
606
- 'non-existent'
607
- );
608
- expect( mockDispatch ).not.toHaveBeenCalled();
609
- } );
610
-
611
- it( 'should handle categories with meta', async () => {
612
- const mockCategory: AbilityCategory = {
613
- slug: 'user-management',
614
- label: 'User Management',
615
- description: 'Abilities for managing users',
616
- meta: {
617
- priority: 'high',
618
- },
619
- };
620
-
621
- const mockResolveSelect = {
622
- getEntityRecord: jest.fn().mockResolvedValue( mockCategory ),
623
- };
624
-
625
- mockRegistry.resolveSelect.mockReturnValue( mockResolveSelect );
626
- mockSelect.getAbilityCategory = jest.fn().mockReturnValue( null );
627
-
628
- const resolver = getAbilityCategory( 'user-management' );
629
- await resolver( {
630
- dispatch: mockDispatch,
631
- registry: mockRegistry,
632
- select: mockSelect,
633
- } );
634
-
635
- // registerAbilityCategory returns a thunk, so we just verify dispatch was called
636
- expect( mockDispatch ).toHaveBeenCalled();
637
- expect( typeof mockDispatch.mock.calls[ 0 ][ 0 ] ).toBe(
638
- 'function'
639
- );
640
- } );
641
- } );
642
- } );