11import { expect } from 'chai' ;
2+ import sinon from 'sinon' ;
3+ import config from '../../../src/config' ;
4+ import { messages } from '../../../src/messages' ;
5+ import * as errorHandler from '../../../src/utils/error-handler' ;
26import {
37 getOrganizations ,
48 getOrganizationsWhereUserIsAdmin ,
@@ -18,12 +22,66 @@ import {
1822 getTaxonomy ,
1923 createImportableCSV ,
2024} from '../../../src/utils/api-client' ;
25+ import type { ManagementClient , OrgUser } from '../../../src/types' ;
2126
22- // API client functions are tightly coupled to the Contentstack SDK
23- // These tests verify the function signatures and basic structure
24- // Full integration testing requires actual SDK mocking or E2E tests
27+ const ORG_UID = 'org-uid' ;
28+
29+ function makeUser ( index : number ) : OrgUser {
30+ return {
31+ email : `user${ index } @example.com` ,
32+ user_uid : `uid-${ index } ` ,
33+ invited_by : 'system' ,
34+ status : 'accepted' ,
35+ created_at : '2020-01-01T00:00:00.000Z' ,
36+ updated_at : '2020-01-01T00:00:00.000Z' ,
37+ } ;
38+ }
39+
40+ function createPaginatedMockClient (
41+ organization : {
42+ is_owner ?: boolean ;
43+ org_roles ?: Array < { admin ?: boolean } > ;
44+ } ,
45+ pages : OrgUser [ ] [ ] ,
46+ ) : { client : ManagementClient ; getInvitations : sinon . SinonStub ; invitationParams : Array < Record < string , number > > } {
47+ const invitationParams : Array < Record < string , number > > = [ ] ;
48+ const getInvitations = sinon . stub ( ) . callsFake ( async ( params : Record < string , number > ) => {
49+ invitationParams . push ( { ...params } ) ;
50+ const callIndex = getInvitations . callCount - 1 ;
51+ const items = pages [ callIndex ] ?? [ ] ;
52+ return { items } ;
53+ } ) ;
54+
55+ const organizationClient = { getInvitations } ;
56+ const organizationStub = sinon . stub ( ) . returns ( organizationClient ) ;
57+
58+ const client = {
59+ getUser : sinon . stub ( ) . resolves ( {
60+ organizations : [
61+ {
62+ uid : ORG_UID ,
63+ name : 'Test Org' ,
64+ ...organization ,
65+ } ,
66+ ] ,
67+ } ) ,
68+ organization : organizationStub ,
69+ } as unknown as ManagementClient ;
70+
71+ return { client, getInvitations, invitationParams } ;
72+ }
2573
2674describe ( 'api-client' , ( ) => {
75+ let waitStub : sinon . SinonStub ;
76+
77+ beforeEach ( ( ) => {
78+ waitStub = sinon . stub ( errorHandler , 'wait' ) . resolves ( ) ;
79+ } ) ;
80+
81+ afterEach ( ( ) => {
82+ waitStub . restore ( ) ;
83+ } ) ;
84+
2785 describe ( 'module exports' , ( ) => {
2886 it ( 'should export all expected functions' , ( ) => {
2987 expect ( getOrganizations ) . to . be . a ( 'function' ) ;
@@ -46,7 +104,62 @@ describe('api-client', () => {
46104 } ) ;
47105 } ) ;
48106
49- // Note: Full functional tests for api-client require mocking the @contentstack/management SDK
50- // This is complex due to the SDK's internal structure. These tests are better suited for
51- // integration testing with a test stack or using more sophisticated mocking tools.
107+ describe ( 'getOrgUsers' , ( ) => {
108+ it ( 'should paginate getInvitations for organization owners' , async ( ) => {
109+ const page1 = Array . from ( { length : config . limit } , ( _ , i ) => makeUser ( i ) ) ;
110+ const page2 = Array . from ( { length : config . limit } , ( _ , i ) => makeUser ( i + config . limit ) ) ;
111+ const page3 = Array . from ( { length : 25 } , ( _ , i ) => makeUser ( i + config . limit * 2 ) ) ;
112+
113+ const { client, getInvitations, invitationParams } = createPaginatedMockClient (
114+ { is_owner : true } ,
115+ [ page1 , page2 , page3 ] ,
116+ ) ;
117+
118+ const result = await getOrgUsers ( client , ORG_UID ) ;
119+
120+ expect ( result . items ) . to . have . lengthOf ( 225 ) ;
121+ expect ( getInvitations . callCount ) . to . equal ( 3 ) ;
122+ expect ( invitationParams [ 0 ] ) . to . deep . equal ( { skip : 0 , page : 1 , limit : config . limit } ) ;
123+ expect ( invitationParams [ 1 ] ) . to . deep . equal ( { skip : config . limit , page : 2 , limit : config . limit } ) ;
124+ expect ( invitationParams [ 2 ] ) . to . deep . equal ( {
125+ skip : config . limit * 2 ,
126+ page : 3 ,
127+ limit : config . limit ,
128+ } ) ;
129+ } ) ;
130+
131+ it ( 'should paginate getInvitations for organization admins' , async ( ) => {
132+ const page1 = Array . from ( { length : config . limit } , ( _ , i ) => makeUser ( i ) ) ;
133+ const page2 = Array . from ( { length : config . limit } , ( _ , i ) => makeUser ( i + config . limit ) ) ;
134+ const page3 = Array . from ( { length : 25 } , ( _ , i ) => makeUser ( i + config . limit * 2 ) ) ;
135+
136+ const { client, getInvitations, invitationParams } = createPaginatedMockClient (
137+ { is_owner : false , org_roles : [ { admin : true } ] } ,
138+ [ page1 , page2 , page3 ] ,
139+ ) ;
140+
141+ const result = await getOrgUsers ( client , ORG_UID ) ;
142+
143+ expect ( result . items ) . to . have . lengthOf ( 225 ) ;
144+ expect ( getInvitations . callCount ) . to . equal ( 3 ) ;
145+ expect ( invitationParams [ 0 ] ) . to . deep . equal ( { skip : 0 , page : 1 , limit : config . limit } ) ;
146+ } ) ;
147+
148+ it ( 'should reject when user is neither owner nor admin' , async ( ) => {
149+ const { client, getInvitations } = createPaginatedMockClient (
150+ { is_owner : false , org_roles : [ { admin : false } ] } ,
151+ [ [ ] ] ,
152+ ) ;
153+
154+ try {
155+ await getOrgUsers ( client , ORG_UID ) ;
156+ expect . fail ( 'Expected getOrgUsers to reject' ) ;
157+ } catch ( error ) {
158+ expect ( error ) . to . be . instanceOf ( Error ) ;
159+ expect ( ( error as Error ) . message ) . to . equal ( messages . ERROR_ADMIN_ACCESS_DENIED ) ;
160+ }
161+
162+ expect ( getInvitations . callCount ) . to . equal ( 0 ) ;
163+ } ) ;
164+ } ) ;
52165} ) ;
0 commit comments