@@ -4,7 +4,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
44import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth' ;
55import {
66 useLibrary , usePermissionsByRole , useTeamMembers , useAssignTeamMembersRole , useRevokeUserRoles ,
7- useValidateUsers ,
7+ useValidateUsers , useScopes , useOrganizations ,
88} from './hooks' ;
99
1010jest . mock ( '@edx/frontend-platform/auth' , ( ) => ( {
@@ -346,6 +346,128 @@ describe('useValidateUsers', () => {
346346 } ) ;
347347} ) ;
348348
349+ describe ( 'useScopes' , ( ) => {
350+ beforeEach ( ( ) => {
351+ jest . clearAllMocks ( ) ;
352+ } ) ;
353+
354+ const makeScopesResponse = ( next : string | null = null ) => ( {
355+ results : [ {
356+ externalKey : 'lib:testorg:testlib' ,
357+ displayName : 'Test Library' ,
358+ org : { id : 1 , name : 'Test Org' , slug : 'testorg' } ,
359+ } ] ,
360+ count : 1 ,
361+ next,
362+ previous : null ,
363+ } ) ;
364+
365+ it ( 'returns pages data on success' , async ( ) => {
366+ getAuthenticatedHttpClient . mockReturnValue ( {
367+ get : jest . fn ( ) . mockResolvedValue ( { data : makeScopesResponse ( ) } ) ,
368+ } ) ;
369+
370+ const { result } = renderHook ( ( ) => useScopes ( { } ) , { wrapper : createWrapper ( ) } ) ;
371+
372+ await waitFor ( ( ) => expect ( result . current . isSuccess ) . toBe ( true ) ) ;
373+
374+ expect ( result . current . data ?. pages ) . toHaveLength ( 1 ) ;
375+ expect ( result . current . data ?. pages [ 0 ] . results ) . toHaveLength ( 1 ) ;
376+ } ) ;
377+
378+ it ( 'hasNextPage is false when next is null' , async ( ) => {
379+ getAuthenticatedHttpClient . mockReturnValue ( {
380+ get : jest . fn ( ) . mockResolvedValue ( { data : makeScopesResponse ( null ) } ) ,
381+ } ) ;
382+
383+ const { result } = renderHook ( ( ) => useScopes ( { } ) , { wrapper : createWrapper ( ) } ) ;
384+
385+ await waitFor ( ( ) => expect ( result . current . isSuccess ) . toBe ( true ) ) ;
386+ expect ( result . current . hasNextPage ) . toBe ( false ) ;
387+ } ) ;
388+
389+ it ( 'hasNextPage is true when next URL has page param' , async ( ) => {
390+ getAuthenticatedHttpClient . mockReturnValue ( {
391+ get : jest . fn ( ) . mockResolvedValue ( {
392+ data : makeScopesResponse ( 'http://localhost:8000/api/authz/v1/scopes/?page=2' ) ,
393+ } ) ,
394+ } ) ;
395+
396+ const { result } = renderHook ( ( ) => useScopes ( { } ) , { wrapper : createWrapper ( ) } ) ;
397+
398+ await waitFor ( ( ) => expect ( result . current . isSuccess ) . toBe ( true ) ) ;
399+ expect ( result . current . hasNextPage ) . toBe ( true ) ;
400+ } ) ;
401+
402+ it ( 'hasNextPage is false when next URL has no page param' , async ( ) => {
403+ getAuthenticatedHttpClient . mockReturnValue ( {
404+ get : jest . fn ( ) . mockResolvedValue ( {
405+ data : makeScopesResponse ( 'http://localhost:8000/api/authz/v1/scopes/' ) ,
406+ } ) ,
407+ } ) ;
408+
409+ const { result } = renderHook ( ( ) => useScopes ( { } ) , { wrapper : createWrapper ( ) } ) ;
410+
411+ await waitFor ( ( ) => expect ( result . current . isSuccess ) . toBe ( true ) ) ;
412+ expect ( result . current . hasNextPage ) . toBe ( false ) ;
413+ } ) ;
414+
415+ it ( 'hasNextPage is false when next is an invalid URL' , async ( ) => {
416+ getAuthenticatedHttpClient . mockReturnValue ( {
417+ get : jest . fn ( ) . mockResolvedValue ( {
418+ data : makeScopesResponse ( 'not-a-valid-url' ) ,
419+ } ) ,
420+ } ) ;
421+
422+ const { result } = renderHook ( ( ) => useScopes ( { } ) , { wrapper : createWrapper ( ) } ) ;
423+
424+ await waitFor ( ( ) => expect ( result . current . isSuccess ) . toBe ( true ) ) ;
425+ expect ( result . current . hasNextPage ) . toBe ( false ) ;
426+ } ) ;
427+
428+ it ( 'handles error when API call fails' , async ( ) => {
429+ getAuthenticatedHttpClient . mockReturnValue ( {
430+ get : jest . fn ( ) . mockRejectedValue ( new Error ( 'Network error' ) ) ,
431+ } ) ;
432+
433+ const { result } = renderHook ( ( ) => useScopes ( { } ) , { wrapper : createWrapper ( ) } ) ;
434+
435+ await waitFor ( ( ) => expect ( result . current . isError ) . toBe ( true ) ) ;
436+ expect ( result . current . error ) . toBeDefined ( ) ;
437+ } ) ;
438+ } ) ;
439+
440+ describe ( 'useOrganizations' , ( ) => {
441+ beforeEach ( ( ) => {
442+ jest . clearAllMocks ( ) ;
443+ } ) ;
444+
445+ const mockOrgs = [ {
446+ id : 1 , name : 'Org One' , shortName : 'org1' , description : '' , logo : null , active : true ,
447+ } ] ;
448+
449+ it ( 'returns organizations on success' , async ( ) => {
450+ getAuthenticatedHttpClient . mockReturnValue ( {
451+ get : jest . fn ( ) . mockResolvedValue ( { data : { results : mockOrgs } } ) ,
452+ } ) ;
453+
454+ const { result } = renderHook ( ( ) => useOrganizations ( ) , { wrapper : createWrapper ( ) } ) ;
455+
456+ await waitFor ( ( ) => expect ( result . current . isSuccess ) . toBe ( true ) ) ;
457+ expect ( result . current . data ) . toEqual ( mockOrgs ) ;
458+ } ) ;
459+
460+ it ( 'handles error when API fails' , async ( ) => {
461+ getAuthenticatedHttpClient . mockReturnValue ( {
462+ get : jest . fn ( ) . mockRejectedValue ( new Error ( 'Failed' ) ) ,
463+ } ) ;
464+
465+ const { result } = renderHook ( ( ) => useOrganizations ( ) , { wrapper : createWrapper ( ) } ) ;
466+
467+ await waitFor ( ( ) => expect ( result . current . isError ) . toBe ( true ) ) ;
468+ } ) ;
469+ } ) ;
470+
349471describe ( 'useRevokeUserRoles' , ( ) => {
350472 beforeEach ( ( ) => {
351473 jest . clearAllMocks ( ) ;
0 commit comments