@wordpress/abilities 0.2.1-next.8b30e05b0.0 → 0.2.1-next.8fd3f8831.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/README.md +32 -40
- package/build/{api.js → api.cjs} +22 -69
- package/build/api.cjs.map +7 -0
- package/build/{index.js → index.cjs} +4 -4
- package/build/{index.js.map → index.cjs.map} +2 -2
- package/build/store/{actions.js → actions.cjs} +43 -33
- package/build/store/actions.cjs.map +7 -0
- package/build/store/{constants.js → constants.cjs} +7 -16
- package/build/store/constants.cjs.map +7 -0
- package/build/store/{index.js → index.cjs} +6 -32
- package/build/store/index.cjs.map +7 -0
- package/build/store/{reducer.js → reducer.cjs} +4 -24
- package/build/store/reducer.cjs.map +7 -0
- package/build/store/{selectors.js → selectors.cjs} +2 -2
- package/build/store/selectors.cjs.map +7 -0
- package/build/store/types.cjs +19 -0
- package/build/store/types.cjs.map +7 -0
- package/build/{types.js → types.cjs} +1 -1
- package/build/types.cjs.map +7 -0
- package/build/{validation.js → validation.cjs} +3 -3
- package/build-module/api.js +22 -59
- package/build-module/api.js.map +2 -2
- package/build-module/index.js +3 -3
- package/build-module/index.js.map +2 -2
- package/build-module/store/actions.js +44 -33
- package/build-module/store/actions.js.map +2 -2
- package/build-module/store/constants.js +4 -10
- package/build-module/store/constants.js.map +2 -2
- package/build-module/store/index.js +6 -37
- package/build-module/store/index.js.map +2 -2
- package/build-module/store/reducer.js +3 -25
- package/build-module/store/reducer.js.map +2 -2
- package/build-module/store/selectors.js +1 -1
- package/build-module/store/selectors.js.map +2 -2
- package/build-module/store/types.js +1 -0
- package/build-module/store/types.js.map +7 -0
- package/build-types/api.d.ts +16 -23
- package/build-types/api.d.ts.map +1 -1
- package/build-types/index.d.ts +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/store/actions.d.ts +5 -27
- package/build-types/store/actions.d.ts.map +1 -1
- package/build-types/store/constants.d.ts +2 -5
- package/build-types/store/constants.d.ts.map +1 -1
- package/build-types/store/index.d.ts.map +1 -1
- package/build-types/store/reducer.d.ts +21 -11
- package/build-types/store/reducer.d.ts.map +1 -1
- package/build-types/store/selectors.d.ts +2 -1
- package/build-types/store/selectors.d.ts.map +1 -1
- package/build-types/store/types.d.ts +18 -0
- package/build-types/store/types.d.ts.map +1 -0
- package/build-types/types.d.ts +14 -24
- package/build-types/types.d.ts.map +1 -1
- package/package.json +8 -10
- package/src/api.ts +43 -123
- package/src/index.ts +0 -1
- package/src/store/actions.ts +61 -46
- package/src/store/constants.ts +4 -5
- package/src/store/index.ts +2 -34
- package/src/store/reducer.ts +27 -33
- package/src/store/selectors.ts +3 -7
- package/src/store/tests/actions.test.ts +100 -244
- package/src/store/tests/reducer.test.ts +0 -451
- package/src/store/tests/selectors.test.ts +1 -1
- package/src/store/types.ts +19 -0
- package/src/tests/api.test.ts +112 -158
- package/src/types.ts +14 -26
- package/build/api.js.map +0 -7
- package/build/store/actions.js.map +0 -7
- package/build/store/constants.js.map +0 -7
- package/build/store/index.js.map +0 -7
- package/build/store/reducer.js.map +0 -7
- package/build/store/resolvers.js +0 -107
- package/build/store/resolvers.js.map +0 -7
- package/build/store/selectors.js.map +0 -7
- package/build/types.js.map +0 -7
- package/build-module/store/resolvers.js +0 -84
- package/build-module/store/resolvers.js.map +0 -7
- package/build-types/store/resolvers.d.ts +0 -47
- package/build-types/store/resolvers.d.ts.map +0 -1
- package/src/store/resolvers.ts +0 -151
- package/src/store/tests/resolvers.test.ts +0 -642
- /package/build/{validation.js.map → validation.cjs.map} +0 -0
|
@@ -2,27 +2,18 @@
|
|
|
2
2
|
* Tests for store actions.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* WordPress dependencies
|
|
7
|
-
*/
|
|
8
|
-
import { resolveSelect } from '@wordpress/data';
|
|
9
|
-
|
|
10
5
|
/**
|
|
11
6
|
* Internal dependencies
|
|
12
7
|
*/
|
|
13
8
|
import {
|
|
14
|
-
receiveAbilities,
|
|
15
9
|
registerAbility,
|
|
16
10
|
unregisterAbility,
|
|
17
|
-
receiveCategories,
|
|
18
11
|
registerAbilityCategory,
|
|
19
12
|
unregisterAbilityCategory,
|
|
20
13
|
} from '../actions';
|
|
21
14
|
import {
|
|
22
|
-
RECEIVE_ABILITIES,
|
|
23
15
|
REGISTER_ABILITY,
|
|
24
16
|
UNREGISTER_ABILITY,
|
|
25
|
-
RECEIVE_CATEGORIES,
|
|
26
17
|
REGISTER_ABILITY_CATEGORY,
|
|
27
18
|
UNREGISTER_ABILITY_CATEGORY,
|
|
28
19
|
} from '../constants';
|
|
@@ -32,52 +23,7 @@ import type {
|
|
|
32
23
|
AbilityCategoryArgs,
|
|
33
24
|
} from '../../types';
|
|
34
25
|
|
|
35
|
-
// Mock the WordPress data store
|
|
36
|
-
jest.mock( '@wordpress/data', () => ( {
|
|
37
|
-
resolveSelect: jest.fn(),
|
|
38
|
-
} ) );
|
|
39
|
-
|
|
40
26
|
describe( 'Store Actions', () => {
|
|
41
|
-
describe( 'receiveAbilities', () => {
|
|
42
|
-
it( 'should create an action to receive abilities', () => {
|
|
43
|
-
const abilities: Ability[] = [
|
|
44
|
-
{
|
|
45
|
-
name: 'test/ability1',
|
|
46
|
-
label: 'Test Ability 1',
|
|
47
|
-
description: 'First test ability',
|
|
48
|
-
category: 'test-category',
|
|
49
|
-
input_schema: { type: 'object' },
|
|
50
|
-
output_schema: { type: 'object' },
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'test/ability2',
|
|
54
|
-
label: 'Test Ability 2',
|
|
55
|
-
description: 'Second test ability',
|
|
56
|
-
category: 'test-category',
|
|
57
|
-
input_schema: { type: 'object' },
|
|
58
|
-
output_schema: { type: 'object' },
|
|
59
|
-
},
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
const action = receiveAbilities( abilities );
|
|
63
|
-
|
|
64
|
-
expect( action ).toEqual( {
|
|
65
|
-
type: RECEIVE_ABILITIES,
|
|
66
|
-
abilities,
|
|
67
|
-
} );
|
|
68
|
-
} );
|
|
69
|
-
|
|
70
|
-
it( 'should handle empty abilities array', () => {
|
|
71
|
-
const abilities: Ability[] = [];
|
|
72
|
-
const action = receiveAbilities( abilities );
|
|
73
|
-
|
|
74
|
-
expect( action ).toEqual( {
|
|
75
|
-
type: RECEIVE_ABILITIES,
|
|
76
|
-
abilities: [],
|
|
77
|
-
} );
|
|
78
|
-
} );
|
|
79
|
-
} );
|
|
80
|
-
|
|
81
27
|
describe( 'registerAbility', () => {
|
|
82
28
|
let mockSelect: any;
|
|
83
29
|
let mockDispatch: jest.Mock;
|
|
@@ -119,16 +65,9 @@ describe( 'Store Actions', () => {
|
|
|
119
65
|
} ),
|
|
120
66
|
};
|
|
121
67
|
mockDispatch = jest.fn();
|
|
122
|
-
|
|
123
|
-
// Mock resolveSelect to return categories
|
|
124
|
-
( resolveSelect as jest.Mock ).mockReturnValue( {
|
|
125
|
-
getAbilityCategories: jest
|
|
126
|
-
.fn()
|
|
127
|
-
.mockResolvedValue( defaultCategories ),
|
|
128
|
-
} );
|
|
129
68
|
} );
|
|
130
69
|
|
|
131
|
-
it( 'should register a valid client ability',
|
|
70
|
+
it( 'should register a valid client ability', () => {
|
|
132
71
|
const ability: Ability = {
|
|
133
72
|
name: 'test/ability',
|
|
134
73
|
label: 'Test Ability',
|
|
@@ -150,15 +89,18 @@ describe( 'Store Actions', () => {
|
|
|
150
89
|
};
|
|
151
90
|
|
|
152
91
|
const action = registerAbility( ability );
|
|
153
|
-
|
|
92
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
154
93
|
|
|
155
94
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
156
95
|
type: REGISTER_ABILITY,
|
|
157
|
-
ability
|
|
96
|
+
ability: {
|
|
97
|
+
...ability,
|
|
98
|
+
meta: { annotations: { clientRegistered: true } },
|
|
99
|
+
},
|
|
158
100
|
} );
|
|
159
101
|
} );
|
|
160
102
|
|
|
161
|
-
it( 'should register server-side abilities',
|
|
103
|
+
it( 'should register server-side abilities', () => {
|
|
162
104
|
const ability: Ability = {
|
|
163
105
|
name: 'test/server-ability',
|
|
164
106
|
label: 'Server Ability',
|
|
@@ -169,15 +111,18 @@ describe( 'Store Actions', () => {
|
|
|
169
111
|
};
|
|
170
112
|
|
|
171
113
|
const action = registerAbility( ability );
|
|
172
|
-
|
|
114
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
173
115
|
|
|
174
116
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
175
117
|
type: REGISTER_ABILITY,
|
|
176
|
-
ability
|
|
118
|
+
ability: {
|
|
119
|
+
...ability,
|
|
120
|
+
meta: { annotations: { clientRegistered: true } },
|
|
121
|
+
},
|
|
177
122
|
} );
|
|
178
123
|
} );
|
|
179
124
|
|
|
180
|
-
it( 'should validate and reject ability without name',
|
|
125
|
+
it( 'should validate and reject ability without name', () => {
|
|
181
126
|
const ability: Ability = {
|
|
182
127
|
name: '',
|
|
183
128
|
label: 'Test Ability',
|
|
@@ -188,13 +133,13 @@ describe( 'Store Actions', () => {
|
|
|
188
133
|
|
|
189
134
|
const action = registerAbility( ability );
|
|
190
135
|
|
|
191
|
-
|
|
136
|
+
expect( () =>
|
|
192
137
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
193
|
-
).
|
|
138
|
+
).toThrow( 'Ability name is required' );
|
|
194
139
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
195
140
|
} );
|
|
196
141
|
|
|
197
|
-
it( 'should validate and reject ability with invalid name format',
|
|
142
|
+
it( 'should validate and reject ability with invalid name format', () => {
|
|
198
143
|
const testCases = [
|
|
199
144
|
'invalid', // No namespace
|
|
200
145
|
'my-plugin/feature/action', // Multiple slashes
|
|
@@ -215,9 +160,9 @@ describe( 'Store Actions', () => {
|
|
|
215
160
|
|
|
216
161
|
const action = registerAbility( ability );
|
|
217
162
|
|
|
218
|
-
|
|
163
|
+
expect( () =>
|
|
219
164
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
220
|
-
).
|
|
165
|
+
).toThrow(
|
|
221
166
|
'Ability name must be a string containing a namespace prefix'
|
|
222
167
|
);
|
|
223
168
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
@@ -225,7 +170,7 @@ describe( 'Store Actions', () => {
|
|
|
225
170
|
}
|
|
226
171
|
} );
|
|
227
172
|
|
|
228
|
-
it( 'should validate and reject ability without label',
|
|
173
|
+
it( 'should validate and reject ability without label', () => {
|
|
229
174
|
const ability: Ability = {
|
|
230
175
|
name: 'test/ability',
|
|
231
176
|
label: '',
|
|
@@ -236,13 +181,13 @@ describe( 'Store Actions', () => {
|
|
|
236
181
|
|
|
237
182
|
const action = registerAbility( ability );
|
|
238
183
|
|
|
239
|
-
|
|
184
|
+
expect( () =>
|
|
240
185
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
241
|
-
).
|
|
186
|
+
).toThrow( 'Ability "test/ability" must have a label' );
|
|
242
187
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
243
188
|
} );
|
|
244
189
|
|
|
245
|
-
it( 'should validate and reject ability without description',
|
|
190
|
+
it( 'should validate and reject ability without description', () => {
|
|
246
191
|
const ability: Ability = {
|
|
247
192
|
name: 'test/ability',
|
|
248
193
|
label: 'Test Ability',
|
|
@@ -253,15 +198,13 @@ describe( 'Store Actions', () => {
|
|
|
253
198
|
|
|
254
199
|
const action = registerAbility( ability );
|
|
255
200
|
|
|
256
|
-
|
|
201
|
+
expect( () =>
|
|
257
202
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
258
|
-
).
|
|
259
|
-
'Ability "test/ability" must have a description'
|
|
260
|
-
);
|
|
203
|
+
).toThrow( 'Ability "test/ability" must have a description' );
|
|
261
204
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
262
205
|
} );
|
|
263
206
|
|
|
264
|
-
it( 'should validate and reject ability without category',
|
|
207
|
+
it( 'should validate and reject ability without category', () => {
|
|
265
208
|
const ability: Ability = {
|
|
266
209
|
name: 'test/ability',
|
|
267
210
|
label: 'Test Ability',
|
|
@@ -272,13 +215,13 @@ describe( 'Store Actions', () => {
|
|
|
272
215
|
|
|
273
216
|
const action = registerAbility( ability );
|
|
274
217
|
|
|
275
|
-
|
|
218
|
+
expect( () =>
|
|
276
219
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
277
|
-
).
|
|
220
|
+
).toThrow( 'Ability "test/ability" must have a category' );
|
|
278
221
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
279
222
|
} );
|
|
280
223
|
|
|
281
|
-
it( 'should validate and reject ability with invalid category format',
|
|
224
|
+
it( 'should validate and reject ability with invalid category format', () => {
|
|
282
225
|
const testCases = [
|
|
283
226
|
'Data-Retrieval', // Uppercase letters
|
|
284
227
|
'data_retrieval', // Underscores not allowed
|
|
@@ -300,9 +243,9 @@ describe( 'Store Actions', () => {
|
|
|
300
243
|
|
|
301
244
|
const action = registerAbility( ability );
|
|
302
245
|
|
|
303
|
-
|
|
246
|
+
expect( () =>
|
|
304
247
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
305
|
-
).
|
|
248
|
+
).toThrow(
|
|
306
249
|
'Ability "test/ability" has an invalid category. Category must be lowercase alphanumeric with dashes only'
|
|
307
250
|
);
|
|
308
251
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
@@ -310,7 +253,7 @@ describe( 'Store Actions', () => {
|
|
|
310
253
|
}
|
|
311
254
|
} );
|
|
312
255
|
|
|
313
|
-
it( 'should accept ability with valid category format',
|
|
256
|
+
it( 'should accept ability with valid category format', () => {
|
|
314
257
|
const validCategories = [
|
|
315
258
|
'data-retrieval',
|
|
316
259
|
'user-management',
|
|
@@ -345,30 +288,28 @@ describe( 'Store Actions', () => {
|
|
|
345
288
|
},
|
|
346
289
|
];
|
|
347
290
|
|
|
348
|
-
// Mock
|
|
291
|
+
// Mock select to return categories
|
|
349
292
|
mockSelect.getAbilityCategories.mockReturnValue(
|
|
350
293
|
categoriesForTest
|
|
351
294
|
);
|
|
352
|
-
( resolveSelect as jest.Mock ).mockReturnValue( {
|
|
353
|
-
getAbilityCategories: jest
|
|
354
|
-
.fn()
|
|
355
|
-
.mockResolvedValue( categoriesForTest ),
|
|
356
|
-
} );
|
|
357
295
|
|
|
358
296
|
mockSelect.getAbility.mockReturnValue( null );
|
|
359
297
|
mockDispatch.mockClear();
|
|
360
298
|
|
|
361
299
|
const action = registerAbility( ability );
|
|
362
|
-
|
|
300
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
363
301
|
|
|
364
302
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
365
303
|
type: REGISTER_ABILITY,
|
|
366
|
-
ability
|
|
304
|
+
ability: {
|
|
305
|
+
...ability,
|
|
306
|
+
meta: { annotations: { clientRegistered: true } },
|
|
307
|
+
},
|
|
367
308
|
} );
|
|
368
309
|
}
|
|
369
310
|
} );
|
|
370
311
|
|
|
371
|
-
it( 'should validate and reject ability with non-existent category',
|
|
312
|
+
it( 'should validate and reject ability with non-existent category', () => {
|
|
372
313
|
mockSelect.getAbilityCategories.mockReturnValue( [
|
|
373
314
|
{
|
|
374
315
|
slug: 'test-category',
|
|
@@ -392,15 +333,15 @@ describe( 'Store Actions', () => {
|
|
|
392
333
|
|
|
393
334
|
const action = registerAbility( ability );
|
|
394
335
|
|
|
395
|
-
|
|
336
|
+
expect( () =>
|
|
396
337
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
397
|
-
).
|
|
338
|
+
).toThrow(
|
|
398
339
|
'Ability "test/ability" references non-existent category "non-existent-category". Please register the category first.'
|
|
399
340
|
);
|
|
400
341
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
401
342
|
} );
|
|
402
343
|
|
|
403
|
-
it( 'should accept ability with existing category',
|
|
344
|
+
it( 'should accept ability with existing category', () => {
|
|
404
345
|
const categoriesForTest = [
|
|
405
346
|
{
|
|
406
347
|
slug: 'test-category',
|
|
@@ -417,11 +358,6 @@ describe( 'Store Actions', () => {
|
|
|
417
358
|
mockSelect.getAbilityCategories.mockReturnValue(
|
|
418
359
|
categoriesForTest
|
|
419
360
|
);
|
|
420
|
-
( resolveSelect as jest.Mock ).mockReturnValue( {
|
|
421
|
-
getAbilityCategories: jest
|
|
422
|
-
.fn()
|
|
423
|
-
.mockResolvedValue( categoriesForTest ),
|
|
424
|
-
} );
|
|
425
361
|
|
|
426
362
|
const ability: Ability = {
|
|
427
363
|
name: 'test/ability',
|
|
@@ -432,17 +368,18 @@ describe( 'Store Actions', () => {
|
|
|
432
368
|
};
|
|
433
369
|
|
|
434
370
|
const action = registerAbility( ability );
|
|
435
|
-
|
|
371
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
436
372
|
|
|
437
|
-
// resolveSelect should have been called to load categories
|
|
438
|
-
expect( resolveSelect ).toHaveBeenCalledWith( 'core/abilities' );
|
|
439
373
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
440
374
|
type: REGISTER_ABILITY,
|
|
441
|
-
ability
|
|
375
|
+
ability: {
|
|
376
|
+
...ability,
|
|
377
|
+
meta: { annotations: { clientRegistered: true } },
|
|
378
|
+
},
|
|
442
379
|
} );
|
|
443
380
|
} );
|
|
444
381
|
|
|
445
|
-
it( 'should validate and reject ability with invalid callback',
|
|
382
|
+
it( 'should validate and reject ability with invalid callback', () => {
|
|
446
383
|
const ability: Ability = {
|
|
447
384
|
name: 'test/ability',
|
|
448
385
|
label: 'Test Ability',
|
|
@@ -453,15 +390,15 @@ describe( 'Store Actions', () => {
|
|
|
453
390
|
|
|
454
391
|
const action = registerAbility( ability );
|
|
455
392
|
|
|
456
|
-
|
|
393
|
+
expect( () =>
|
|
457
394
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
458
|
-
).
|
|
395
|
+
).toThrow(
|
|
459
396
|
'Ability "test/ability" has an invalid callback. Callback must be a function'
|
|
460
397
|
);
|
|
461
398
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
462
399
|
} );
|
|
463
400
|
|
|
464
|
-
it( 'should validate and reject already registered ability',
|
|
401
|
+
it( 'should validate and reject already registered ability', () => {
|
|
465
402
|
const existingAbility: Ability = {
|
|
466
403
|
name: 'test/ability',
|
|
467
404
|
label: 'Existing Ability',
|
|
@@ -481,45 +418,11 @@ describe( 'Store Actions', () => {
|
|
|
481
418
|
|
|
482
419
|
const action = registerAbility( ability );
|
|
483
420
|
|
|
484
|
-
|
|
421
|
+
expect( () =>
|
|
485
422
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
486
|
-
).
|
|
423
|
+
).toThrow( 'Ability "test/ability" is already registered' );
|
|
487
424
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
488
425
|
} );
|
|
489
|
-
|
|
490
|
-
it( 'should load categories using resolveSelect before validation', async () => {
|
|
491
|
-
const categories = [
|
|
492
|
-
{
|
|
493
|
-
slug: 'test-category',
|
|
494
|
-
label: 'Test Category',
|
|
495
|
-
description: 'Test category',
|
|
496
|
-
},
|
|
497
|
-
];
|
|
498
|
-
|
|
499
|
-
// Mock resolveSelect to return categories directly
|
|
500
|
-
( resolveSelect as jest.Mock ).mockReturnValue( {
|
|
501
|
-
getAbilityCategories: jest.fn().mockResolvedValue( categories ),
|
|
502
|
-
} );
|
|
503
|
-
|
|
504
|
-
const ability: Ability = {
|
|
505
|
-
name: 'test/ability',
|
|
506
|
-
label: 'Test Ability',
|
|
507
|
-
description: 'Test description',
|
|
508
|
-
category: 'test-category',
|
|
509
|
-
callback: jest.fn(),
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
const action = registerAbility( ability );
|
|
513
|
-
await action( { select: mockSelect, dispatch: mockDispatch } );
|
|
514
|
-
|
|
515
|
-
// Should have called resolveSelect to load categories
|
|
516
|
-
expect( resolveSelect ).toHaveBeenCalledWith( 'core/abilities' );
|
|
517
|
-
// Should have successfully registered
|
|
518
|
-
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
519
|
-
type: REGISTER_ABILITY,
|
|
520
|
-
ability,
|
|
521
|
-
} );
|
|
522
|
-
} );
|
|
523
426
|
} );
|
|
524
427
|
|
|
525
428
|
describe( 'unregisterAbility', () => {
|
|
@@ -544,40 +447,6 @@ describe( 'Store Actions', () => {
|
|
|
544
447
|
} );
|
|
545
448
|
} );
|
|
546
449
|
|
|
547
|
-
describe( 'receiveCategories', () => {
|
|
548
|
-
it( 'should create an action to receive categories', () => {
|
|
549
|
-
const categories: AbilityCategory[] = [
|
|
550
|
-
{
|
|
551
|
-
slug: 'data-retrieval',
|
|
552
|
-
label: 'Data Retrieval',
|
|
553
|
-
description: 'Abilities that retrieve data',
|
|
554
|
-
},
|
|
555
|
-
{
|
|
556
|
-
slug: 'user-management',
|
|
557
|
-
label: 'User Management',
|
|
558
|
-
description: 'Abilities for managing users',
|
|
559
|
-
},
|
|
560
|
-
];
|
|
561
|
-
|
|
562
|
-
const action = receiveCategories( categories );
|
|
563
|
-
|
|
564
|
-
expect( action ).toEqual( {
|
|
565
|
-
type: RECEIVE_CATEGORIES,
|
|
566
|
-
categories,
|
|
567
|
-
} );
|
|
568
|
-
} );
|
|
569
|
-
|
|
570
|
-
it( 'should handle empty categories array', () => {
|
|
571
|
-
const categories: AbilityCategory[] = [];
|
|
572
|
-
const action = receiveCategories( categories );
|
|
573
|
-
|
|
574
|
-
expect( action ).toEqual( {
|
|
575
|
-
type: RECEIVE_CATEGORIES,
|
|
576
|
-
categories: [],
|
|
577
|
-
} );
|
|
578
|
-
} );
|
|
579
|
-
} );
|
|
580
|
-
|
|
581
450
|
describe( 'registerAbilityCategory', () => {
|
|
582
451
|
let mockSelect: any;
|
|
583
452
|
let mockDispatch: jest.Mock;
|
|
@@ -589,14 +458,9 @@ describe( 'Store Actions', () => {
|
|
|
589
458
|
getAbilityCategories: jest.fn().mockReturnValue( [] ),
|
|
590
459
|
};
|
|
591
460
|
mockDispatch = jest.fn();
|
|
592
|
-
|
|
593
|
-
// Mock resolveSelect to return a mock that resolves the getAbilityCategories call
|
|
594
|
-
( resolveSelect as jest.Mock ).mockReturnValue( {
|
|
595
|
-
getAbilityCategories: jest.fn().mockResolvedValue( undefined ),
|
|
596
|
-
} );
|
|
597
461
|
} );
|
|
598
462
|
|
|
599
|
-
it( 'should register a valid category',
|
|
463
|
+
it( 'should register a valid category', () => {
|
|
600
464
|
const slug = 'test-category';
|
|
601
465
|
const args: AbilityCategoryArgs = {
|
|
602
466
|
label: 'Test Category',
|
|
@@ -604,7 +468,7 @@ describe( 'Store Actions', () => {
|
|
|
604
468
|
};
|
|
605
469
|
|
|
606
470
|
const action = registerAbilityCategory( slug, args );
|
|
607
|
-
|
|
471
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
608
472
|
|
|
609
473
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
610
474
|
type: REGISTER_ABILITY_CATEGORY,
|
|
@@ -612,24 +476,25 @@ describe( 'Store Actions', () => {
|
|
|
612
476
|
slug,
|
|
613
477
|
label: args.label,
|
|
614
478
|
description: args.description,
|
|
615
|
-
meta: {
|
|
616
|
-
_clientRegistered: true,
|
|
617
|
-
},
|
|
479
|
+
meta: { annotations: { clientRegistered: true } },
|
|
618
480
|
},
|
|
619
481
|
} );
|
|
620
482
|
} );
|
|
621
483
|
|
|
622
|
-
it( 'should register a category with meta',
|
|
484
|
+
it( 'should register a category with meta and filter to only annotations', () => {
|
|
623
485
|
const slug = 'test-category';
|
|
624
486
|
const args: AbilityCategoryArgs = {
|
|
625
487
|
label: 'Test Category',
|
|
626
488
|
description: 'A test category',
|
|
627
|
-
meta: {
|
|
489
|
+
meta: {
|
|
490
|
+
annotations: { serverRegistered: true },
|
|
491
|
+
},
|
|
628
492
|
};
|
|
629
493
|
|
|
630
494
|
const action = registerAbilityCategory( slug, args );
|
|
631
|
-
|
|
495
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
632
496
|
|
|
497
|
+
// Should only keep annotations, not add clientRegistered since serverRegistered is true
|
|
633
498
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
634
499
|
type: REGISTER_ABILITY_CATEGORY,
|
|
635
500
|
category: {
|
|
@@ -637,14 +502,13 @@ describe( 'Store Actions', () => {
|
|
|
637
502
|
label: args.label,
|
|
638
503
|
description: args.description,
|
|
639
504
|
meta: {
|
|
640
|
-
|
|
641
|
-
_clientRegistered: true,
|
|
505
|
+
annotations: { serverRegistered: true },
|
|
642
506
|
},
|
|
643
507
|
},
|
|
644
508
|
} );
|
|
645
509
|
} );
|
|
646
510
|
|
|
647
|
-
it( 'should validate and reject empty slug',
|
|
511
|
+
it( 'should validate and reject empty slug', () => {
|
|
648
512
|
const args: AbilityCategoryArgs = {
|
|
649
513
|
label: 'Test',
|
|
650
514
|
description: 'Test',
|
|
@@ -652,13 +516,13 @@ describe( 'Store Actions', () => {
|
|
|
652
516
|
|
|
653
517
|
const action = registerAbilityCategory( '', args );
|
|
654
518
|
|
|
655
|
-
|
|
519
|
+
expect( () =>
|
|
656
520
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
657
|
-
).
|
|
521
|
+
).toThrow( 'Category slug is required' );
|
|
658
522
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
659
523
|
} );
|
|
660
524
|
|
|
661
|
-
it( 'should validate and reject invalid slug formats',
|
|
525
|
+
it( 'should validate and reject invalid slug formats', () => {
|
|
662
526
|
const testCases = [
|
|
663
527
|
'Data-Retrieval', // Uppercase
|
|
664
528
|
'data_retrieval', // Underscores
|
|
@@ -679,9 +543,9 @@ describe( 'Store Actions', () => {
|
|
|
679
543
|
for ( const invalidSlug of testCases ) {
|
|
680
544
|
const action = registerAbilityCategory( invalidSlug, args );
|
|
681
545
|
|
|
682
|
-
|
|
546
|
+
expect( () =>
|
|
683
547
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
684
|
-
).
|
|
548
|
+
).toThrow(
|
|
685
549
|
'Category slug must contain only lowercase alphanumeric characters and dashes'
|
|
686
550
|
);
|
|
687
551
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
@@ -689,7 +553,7 @@ describe( 'Store Actions', () => {
|
|
|
689
553
|
}
|
|
690
554
|
} );
|
|
691
555
|
|
|
692
|
-
it( 'should accept valid slug formats',
|
|
556
|
+
it( 'should accept valid slug formats', () => {
|
|
693
557
|
const validSlugs = [
|
|
694
558
|
'data-retrieval',
|
|
695
559
|
'user-management',
|
|
@@ -710,7 +574,7 @@ describe( 'Store Actions', () => {
|
|
|
710
574
|
mockDispatch.mockClear();
|
|
711
575
|
|
|
712
576
|
const action = registerAbilityCategory( validSlug, args );
|
|
713
|
-
|
|
577
|
+
action( { select: mockSelect, dispatch: mockDispatch } );
|
|
714
578
|
|
|
715
579
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
716
580
|
type: REGISTER_ABILITY_CATEGORY,
|
|
@@ -718,15 +582,13 @@ describe( 'Store Actions', () => {
|
|
|
718
582
|
slug: validSlug,
|
|
719
583
|
label: args.label,
|
|
720
584
|
description: args.description,
|
|
721
|
-
meta: {
|
|
722
|
-
_clientRegistered: true,
|
|
723
|
-
},
|
|
585
|
+
meta: { annotations: { clientRegistered: true } },
|
|
724
586
|
},
|
|
725
587
|
} );
|
|
726
588
|
}
|
|
727
589
|
} );
|
|
728
590
|
|
|
729
|
-
it( 'should validate and reject missing label',
|
|
591
|
+
it( 'should validate and reject missing label', () => {
|
|
730
592
|
const slug = 'test-category';
|
|
731
593
|
const args = {
|
|
732
594
|
label: '',
|
|
@@ -735,15 +597,15 @@ describe( 'Store Actions', () => {
|
|
|
735
597
|
|
|
736
598
|
const action = registerAbilityCategory( slug, args );
|
|
737
599
|
|
|
738
|
-
|
|
600
|
+
expect( () =>
|
|
739
601
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
740
|
-
).
|
|
602
|
+
).toThrow(
|
|
741
603
|
'The category properties must contain a `label` string.'
|
|
742
604
|
);
|
|
743
605
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
744
606
|
} );
|
|
745
607
|
|
|
746
|
-
it( 'should validate and reject non-string label',
|
|
608
|
+
it( 'should validate and reject non-string label', () => {
|
|
747
609
|
const slug = 'test-category';
|
|
748
610
|
const args = {
|
|
749
611
|
label: 123 as any,
|
|
@@ -752,15 +614,15 @@ describe( 'Store Actions', () => {
|
|
|
752
614
|
|
|
753
615
|
const action = registerAbilityCategory( slug, args );
|
|
754
616
|
|
|
755
|
-
|
|
617
|
+
expect( () =>
|
|
756
618
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
757
|
-
).
|
|
619
|
+
).toThrow(
|
|
758
620
|
'The category properties must contain a `label` string.'
|
|
759
621
|
);
|
|
760
622
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
761
623
|
} );
|
|
762
624
|
|
|
763
|
-
it( 'should validate and reject missing description',
|
|
625
|
+
it( 'should validate and reject missing description', () => {
|
|
764
626
|
const slug = 'test-category';
|
|
765
627
|
const args = {
|
|
766
628
|
label: 'Test',
|
|
@@ -769,15 +631,15 @@ describe( 'Store Actions', () => {
|
|
|
769
631
|
|
|
770
632
|
const action = registerAbilityCategory( slug, args );
|
|
771
633
|
|
|
772
|
-
|
|
634
|
+
expect( () =>
|
|
773
635
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
774
|
-
).
|
|
636
|
+
).toThrow(
|
|
775
637
|
'The category properties must contain a `description` string.'
|
|
776
638
|
);
|
|
777
639
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
778
640
|
} );
|
|
779
641
|
|
|
780
|
-
it( 'should validate and reject non-string description',
|
|
642
|
+
it( 'should validate and reject non-string description', () => {
|
|
781
643
|
const slug = 'test-category';
|
|
782
644
|
const args = {
|
|
783
645
|
label: 'Test',
|
|
@@ -786,15 +648,15 @@ describe( 'Store Actions', () => {
|
|
|
786
648
|
|
|
787
649
|
const action = registerAbilityCategory( slug, args );
|
|
788
650
|
|
|
789
|
-
|
|
651
|
+
expect( () =>
|
|
790
652
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
791
|
-
).
|
|
653
|
+
).toThrow(
|
|
792
654
|
'The category properties must contain a `description` string.'
|
|
793
655
|
);
|
|
794
656
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
795
657
|
} );
|
|
796
658
|
|
|
797
|
-
it( 'should validate and reject non-object meta',
|
|
659
|
+
it( 'should validate and reject non-object meta', () => {
|
|
798
660
|
const slug = 'test-category';
|
|
799
661
|
const args = {
|
|
800
662
|
label: 'Test',
|
|
@@ -804,15 +666,15 @@ describe( 'Store Actions', () => {
|
|
|
804
666
|
|
|
805
667
|
const action = registerAbilityCategory( slug, args );
|
|
806
668
|
|
|
807
|
-
|
|
669
|
+
expect( () =>
|
|
808
670
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
809
|
-
).
|
|
671
|
+
).toThrow(
|
|
810
672
|
'The category properties should provide a valid `meta` object.'
|
|
811
673
|
);
|
|
812
674
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
813
675
|
} );
|
|
814
676
|
|
|
815
|
-
it( 'should validate and reject array as meta',
|
|
677
|
+
it( 'should validate and reject array as meta', () => {
|
|
816
678
|
const slug = 'test-category';
|
|
817
679
|
const args = {
|
|
818
680
|
label: 'Test',
|
|
@@ -822,15 +684,15 @@ describe( 'Store Actions', () => {
|
|
|
822
684
|
|
|
823
685
|
const action = registerAbilityCategory( slug, args );
|
|
824
686
|
|
|
825
|
-
|
|
687
|
+
expect( () =>
|
|
826
688
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
827
|
-
).
|
|
689
|
+
).toThrow(
|
|
828
690
|
'The category properties should provide a valid `meta` object.'
|
|
829
691
|
);
|
|
830
692
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
831
693
|
} );
|
|
832
694
|
|
|
833
|
-
it( 'should validate and reject already registered category',
|
|
695
|
+
it( 'should validate and reject already registered category', () => {
|
|
834
696
|
const existingCategory: AbilityCategory = {
|
|
835
697
|
slug: 'test-category',
|
|
836
698
|
label: 'Existing Category',
|
|
@@ -846,15 +708,13 @@ describe( 'Store Actions', () => {
|
|
|
846
708
|
|
|
847
709
|
const action = registerAbilityCategory( 'test-category', args );
|
|
848
710
|
|
|
849
|
-
|
|
711
|
+
expect( () =>
|
|
850
712
|
action( { select: mockSelect, dispatch: mockDispatch } )
|
|
851
|
-
).
|
|
852
|
-
'Category "test-category" is already registered.'
|
|
853
|
-
);
|
|
713
|
+
).toThrow( 'Category "test-category" is already registered.' );
|
|
854
714
|
expect( mockDispatch ).not.toHaveBeenCalled();
|
|
855
715
|
} );
|
|
856
716
|
|
|
857
|
-
it( 'should allow registering ability after registering category',
|
|
717
|
+
it( 'should allow registering ability after registering category', () => {
|
|
858
718
|
// First register a category
|
|
859
719
|
const categorySlug = 'new-category';
|
|
860
720
|
const categoryArgs: AbilityCategoryArgs = {
|
|
@@ -866,7 +726,7 @@ describe( 'Store Actions', () => {
|
|
|
866
726
|
categorySlug,
|
|
867
727
|
categoryArgs
|
|
868
728
|
);
|
|
869
|
-
|
|
729
|
+
categoryAction( {
|
|
870
730
|
select: mockSelect,
|
|
871
731
|
dispatch: mockDispatch,
|
|
872
732
|
} );
|
|
@@ -878,9 +738,7 @@ describe( 'Store Actions', () => {
|
|
|
878
738
|
slug: categorySlug,
|
|
879
739
|
label: categoryArgs.label,
|
|
880
740
|
description: categoryArgs.description,
|
|
881
|
-
meta: {
|
|
882
|
-
_clientRegistered: true,
|
|
883
|
-
},
|
|
741
|
+
meta: { annotations: { clientRegistered: true } },
|
|
884
742
|
},
|
|
885
743
|
} );
|
|
886
744
|
|
|
@@ -895,11 +753,6 @@ describe( 'Store Actions', () => {
|
|
|
895
753
|
mockSelect.getAbilityCategories = jest
|
|
896
754
|
.fn()
|
|
897
755
|
.mockReturnValue( categoriesWithNew );
|
|
898
|
-
( resolveSelect as jest.Mock ).mockReturnValue( {
|
|
899
|
-
getAbilityCategories: jest
|
|
900
|
-
.fn()
|
|
901
|
-
.mockResolvedValue( categoriesWithNew ),
|
|
902
|
-
} );
|
|
903
756
|
mockSelect.getAbility = jest.fn().mockReturnValue( null );
|
|
904
757
|
mockDispatch.mockClear();
|
|
905
758
|
|
|
@@ -913,7 +766,7 @@ describe( 'Store Actions', () => {
|
|
|
913
766
|
};
|
|
914
767
|
|
|
915
768
|
const abilityAction = registerAbility( ability );
|
|
916
|
-
|
|
769
|
+
abilityAction( {
|
|
917
770
|
select: mockSelect,
|
|
918
771
|
dispatch: mockDispatch,
|
|
919
772
|
} );
|
|
@@ -921,7 +774,10 @@ describe( 'Store Actions', () => {
|
|
|
921
774
|
// Should successfully register with the new category
|
|
922
775
|
expect( mockDispatch ).toHaveBeenCalledWith( {
|
|
923
776
|
type: REGISTER_ABILITY,
|
|
924
|
-
ability
|
|
777
|
+
ability: {
|
|
778
|
+
...ability,
|
|
779
|
+
meta: { annotations: { clientRegistered: true } },
|
|
780
|
+
},
|
|
925
781
|
} );
|
|
926
782
|
} );
|
|
927
783
|
} );
|