55/**
66 * WordPress dependencies
77 */
8- import { dispatch , resolveSelect } from '@wordpress/data' ;
8+ import { dispatch , select , resolveSelect } from '@wordpress/data' ;
99import apiFetch from '@wordpress/api-fetch' ;
1010
1111/**
1212 * Internal dependencies
1313 */
1414import {
15- listAbilities ,
15+ getAbilities ,
1616 getAbility ,
1717 registerAbility ,
1818 unregisterAbility ,
1919 executeAbility ,
2020} from '../api' ;
2121import { store } from '../store' ;
22- import type { Ability , ClientAbility , ServerAbility } from '../types' ;
22+ import type { Ability } from '../types' ;
2323
2424// Mock WordPress dependencies
2525jest . mock ( '@wordpress/data' , ( ) => ( {
2626 dispatch : jest . fn ( ) ,
27+ select : jest . fn ( ) ,
2728 resolveSelect : jest . fn ( ) ,
2829} ) ) ;
2930
@@ -38,22 +39,20 @@ describe('API functions', () => {
3839 jest . clearAllMocks ( ) ;
3940 } ) ;
4041
41- describe ( 'listAbilities ' , ( ) => {
42+ describe ( 'getAbilities ' , ( ) => {
4243 it ( 'should resolve and return all abilities from the store' , async ( ) => {
4344 const mockAbilities : Ability [ ] = [
4445 {
4546 name : 'test/ability1' ,
4647 label : 'Test Ability 1' ,
4748 description : 'First test ability' ,
48- location : 'server' ,
4949 input_schema : { type : 'object' } ,
5050 output_schema : { type : 'object' } ,
5151 } ,
5252 {
5353 name : 'test/ability2' ,
5454 label : 'Test Ability 2' ,
5555 description : 'Second test ability' ,
56- location : 'client' ,
5756 input_schema : { type : 'object' } ,
5857 output_schema : { type : 'object' } ,
5958 } ,
@@ -64,7 +63,7 @@ describe('API functions', () => {
6463 getAbilities : mockGetAbilities ,
6564 } ) ;
6665
67- const result = await listAbilities ( ) ;
66+ const result = await getAbilities ( ) ;
6867
6968 expect ( resolveSelect ) . toHaveBeenCalledWith ( store ) ;
7069 expect ( mockGetAbilities ) . toHaveBeenCalled ( ) ;
@@ -78,7 +77,6 @@ describe('API functions', () => {
7877 name : 'test/ability' ,
7978 label : 'Test Ability' ,
8079 description : 'Test ability description' ,
81- location : 'server' ,
8280 input_schema : { type : 'object' } ,
8381 output_schema : { type : 'object' } ,
8482 } ;
@@ -115,11 +113,15 @@ describe('API functions', () => {
115113 registerAbility : mockRegisterAbility ,
116114 } ) ;
117115
116+ // Mock select to return no existing ability
117+ ( select as jest . Mock ) . mockReturnValue ( {
118+ getAbility : jest . fn ( ) . mockReturnValue ( null ) ,
119+ } ) ;
120+
118121 const ability = {
119122 name : 'test/client-ability' ,
120123 label : 'Client Ability' ,
121124 description : 'Test client ability' ,
122- location : 'client' as const ,
123125 input_schema : { type : 'object' } ,
124126 output_schema : { type : 'object' } ,
125127 callback : jest . fn ( ) ,
@@ -131,87 +133,68 @@ describe('API functions', () => {
131133 expect ( mockRegisterAbility ) . toHaveBeenCalledWith ( ability ) ;
132134 } ) ;
133135
134- it ( 'should throw error for server abilities' , ( ) => {
136+ it ( 'should throw error for abilities without callback ' , ( ) => {
135137 const mockRegisterAbility = jest . fn ( ) ;
136138 ( dispatch as jest . Mock ) . mockReturnValue ( {
137139 registerAbility : mockRegisterAbility ,
138140 } ) ;
139141
140- const ability : ServerAbility = {
141- name : 'test/server-ability' ,
142- label : 'Server Ability' ,
143- description : 'Test server ability' ,
144- location : 'server' ,
145- input_schema : { type : 'object' } ,
146- output_schema : { type : 'object' } ,
147- } ;
148-
149- // Use type assertion to bypass TypeScript check for testing runtime validation
150- expect ( ( ) =>
151- registerAbility ( ability as unknown as ClientAbility )
152- ) . toThrow (
153- 'Server abilities cannot be registered via registerAbility'
154- ) ;
155- } ) ;
156-
157- it ( 'should throw error for client abilities without callback' , ( ) => {
158- const mockRegisterAbility = jest . fn ( ) ;
159- ( dispatch as jest . Mock ) . mockReturnValue ( {
160- registerAbility : mockRegisterAbility ,
142+ // Mock select to return no existing ability
143+ ( select as jest . Mock ) . mockReturnValue ( {
144+ getAbility : jest . fn ( ) . mockReturnValue ( null ) ,
161145 } ) ;
162146
163147 // Create an incomplete client ability for testing runtime validation
164148 const ability = {
165149 name : 'test/client-ability' ,
166150 label : 'Client Ability' ,
167151 description : 'Test client ability' ,
168- location : 'client' as const ,
169152 input_schema : { type : 'object' } ,
170153 output_schema : { type : 'object' } ,
171154 // Missing callback property
172155 } ;
173156
174157 // Use type assertion to bypass TypeScript check
175158 expect ( ( ) =>
176- registerAbility ( ability as unknown as ClientAbility )
177- ) . toThrow ( 'Client abilities must include a callback function' ) ;
159+ registerAbility ( ability as unknown as Ability )
160+ ) . toThrow ( 'Abilities registered on the client require a callback function' ) ;
178161 } ) ;
179162
180163 it ( 'should throw error for ability without name' , ( ) => {
181- const ability : Partial < ClientAbility > = {
164+ const ability : Partial < Ability > = {
182165 label : 'Test Ability' ,
183166 description : 'Test ability' ,
184167 callback : jest . fn ( ) ,
185168 // Missing name property
186169 } ;
187170
188- expect ( ( ) => registerAbility ( ability as ClientAbility ) ) . toThrow (
171+ expect ( ( ) => registerAbility ( ability as Ability ) ) . toThrow (
189172 'Ability name is required'
190173 ) ;
191174 } ) ;
192175
193176 it ( 'should throw error for ability without label' , ( ) => {
194- const ability : Partial < ClientAbility > = {
177+ const ability : Partial < Ability > = {
195178 name : 'test/ability' ,
196179 description : 'Test ability' ,
197180 callback : jest . fn ( ) ,
198181 // Missing label property
199182 } ;
200183
201- expect ( ( ) => registerAbility ( ability as ClientAbility ) ) . toThrow (
184+ expect ( ( ) => registerAbility ( ability as Ability ) ) . toThrow (
202185 'Ability label is required'
203186 ) ;
204187 } ) ;
205188
206189 it ( 'should throw error for ability without description' , ( ) => {
207- const ability : Partial < ClientAbility > = {
190+ const ability : Partial < Ability > = {
208191 name : 'test/ability' ,
209192 label : 'Test Ability' ,
210193 callback : jest . fn ( ) ,
211194 // Missing description property
212195 } ;
213196
214- expect ( ( ) => registerAbility ( ability as ClientAbility ) ) . toThrow (
197+ expect ( ( ) => registerAbility ( ability as Ability ) ) . toThrow (
215198 'Ability description is required'
216199 ) ;
217200 } ) ;
@@ -237,7 +220,6 @@ describe('API functions', () => {
237220 name : 'test/server-ability' ,
238221 label : 'Server Ability' ,
239222 description : 'Test server ability' ,
240- location : 'server' ,
241223 input_schema : {
242224 type : 'object' ,
243225 properties : {
@@ -274,7 +256,6 @@ describe('API functions', () => {
274256 name : 'test/client-ability' ,
275257 label : 'Client Ability' ,
276258 description : 'Test client ability' ,
277- location : 'client' ,
278259 input_schema : { type : 'object' } ,
279260 output_schema : { type : 'object' } ,
280261 callback : mockCallback ,
@@ -311,7 +292,6 @@ describe('API functions', () => {
311292 name : 'test/client-ability' ,
312293 label : 'Client Ability' ,
313294 description : 'Test client ability' ,
314- location : 'client' ,
315295 input_schema : {
316296 type : 'object' ,
317297 properties : {
@@ -338,7 +318,6 @@ describe('API functions', () => {
338318 name : 'test/resource' ,
339319 label : 'Resource Ability' ,
340320 description : 'Test resource ability' ,
341- location : 'server' ,
342321 meta : { type : 'resource' } ,
343322 input_schema : {
344323 type : 'object' ,
@@ -373,7 +352,6 @@ describe('API functions', () => {
373352 name : 'test/resource' ,
374353 label : 'Resource Ability' ,
375354 description : 'Test resource ability' ,
376- location : 'server' ,
377355 meta : { type : 'resource' } ,
378356 input_schema : { type : 'object' } ,
379357 output_schema : { type : 'object' } ,
@@ -390,7 +368,7 @@ describe('API functions', () => {
390368 const result = await executeAbility ( 'test/resource' , { } ) ;
391369
392370 expect ( apiFetch ) . toHaveBeenCalledWith ( {
393- path : '/wp/v2/abilities/test/resource/run' ,
371+ path : '/wp/v2/abilities/test/resource/run? ' ,
394372 method : 'GET' ,
395373 } ) ;
396374 expect ( result ) . toEqual ( mockResponse ) ;
@@ -407,7 +385,6 @@ describe('API functions', () => {
407385 name : 'test/client-ability' ,
408386 label : 'Client Ability' ,
409387 description : 'Test client ability' ,
410- location : 'client' ,
411388 input_schema : { type : 'object' } ,
412389 output_schema : { type : 'object' } ,
413390 callback : mockCallback ,
@@ -440,7 +417,6 @@ describe('API functions', () => {
440417 name : 'test/server-ability' ,
441418 label : 'Server Ability' ,
442419 description : 'Test server ability' ,
443- location : 'server' ,
444420 input_schema : { type : 'object' } ,
445421 output_schema : { type : 'object' } ,
446422 } ;
@@ -464,27 +440,32 @@ describe('API functions', () => {
464440 consoleErrorSpy . mockRestore ( ) ;
465441 } ) ;
466442
467- it ( 'should throw error when client ability is missing callback during execution ' , async ( ) => {
443+ it ( 'should execute ability without callback as server ability ' , async ( ) => {
468444 const mockAbility : Ability = {
469- name : 'test/client-ability' ,
470- label : 'Client Ability' ,
471- description : 'Test client ability' ,
472- location : 'client' ,
445+ name : 'test/ability' ,
446+ label : 'Test Ability' ,
447+ description : 'Test ability without callback' ,
473448 input_schema : { type : 'object' } ,
474449 output_schema : { type : 'object' } ,
475- // Intentionally missing callback to test the edge case
476- } as Ability ;
450+ // No callback - should execute as server ability
451+ } ;
477452
478453 const mockGetAbility = jest . fn ( ) . mockResolvedValue ( mockAbility ) ;
479454 ( resolveSelect as jest . Mock ) . mockReturnValue ( {
480455 getAbility : mockGetAbility ,
481456 } ) ;
482457
483- await expect (
484- executeAbility ( 'test/client-ability' , { } )
485- ) . rejects . toThrow (
486- 'Client ability test/client-ability is missing callback function'
487- ) ;
458+ const mockResponse = { success : true } ;
459+ ( apiFetch as unknown as jest . Mock ) . mockResolvedValue ( mockResponse ) ;
460+
461+ const result = await executeAbility ( 'test/ability' , { data : 'test' } ) ;
462+
463+ expect ( apiFetch ) . toHaveBeenCalledWith ( {
464+ path : '/wp/v2/abilities/test/ability/run' ,
465+ method : 'POST' ,
466+ data : { input : { data : 'test' } } ,
467+ } ) ;
468+ expect ( result ) . toEqual ( mockResponse ) ;
488469 } ) ;
489470
490471 it ( 'should validate output for client abilities' , async ( ) => {
@@ -495,7 +476,6 @@ describe('API functions', () => {
495476 name : 'test/client-ability' ,
496477 label : 'Client Ability' ,
497478 description : 'Test client ability' ,
498- location : 'client' ,
499479 input_schema : { type : 'object' } ,
500480 output_schema : {
501481 type : 'object' ,
0 commit comments