@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
|
@@ -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
|
-
} );
|
|
File without changes
|