@api-client/core 0.18.38 → 0.18.39

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.
Files changed (54) hide show
  1. package/build/src/browser.d.ts +1 -1
  2. package/build/src/browser.d.ts.map +1 -1
  3. package/build/src/browser.js.map +1 -1
  4. package/build/src/mocking/ModelingMock.d.ts +19 -0
  5. package/build/src/mocking/ModelingMock.d.ts.map +1 -0
  6. package/build/src/mocking/ModelingMock.js +19 -0
  7. package/build/src/mocking/ModelingMock.js.map +1 -0
  8. package/build/src/mocking/ProjectMock.js +1 -1
  9. package/build/src/mocking/ProjectMock.js.map +1 -1
  10. package/build/src/mocking/lib/File.d.ts +34 -0
  11. package/build/src/mocking/lib/File.d.ts.map +1 -0
  12. package/build/src/mocking/lib/File.js +64 -0
  13. package/build/src/mocking/lib/File.js.map +1 -0
  14. package/build/src/mocking/lib/Group.d.ts +16 -0
  15. package/build/src/mocking/lib/Group.d.ts.map +1 -0
  16. package/build/src/mocking/lib/Group.js +39 -0
  17. package/build/src/mocking/lib/Group.js.map +1 -0
  18. package/build/src/mocking/lib/Invitation.d.ts +16 -0
  19. package/build/src/mocking/lib/Invitation.d.ts.map +1 -0
  20. package/build/src/mocking/lib/Invitation.js +42 -0
  21. package/build/src/mocking/lib/Invitation.js.map +1 -0
  22. package/build/src/mocking/lib/Organization.d.ts +16 -0
  23. package/build/src/mocking/lib/Organization.d.ts.map +1 -0
  24. package/build/src/mocking/lib/Organization.js +34 -0
  25. package/build/src/mocking/lib/Organization.js.map +1 -0
  26. package/build/src/mocking/lib/Patch.d.ts +29 -0
  27. package/build/src/mocking/lib/Patch.d.ts.map +1 -0
  28. package/build/src/mocking/lib/Patch.js +102 -0
  29. package/build/src/mocking/lib/Patch.js.map +1 -0
  30. package/build/src/mocking/lib/Trash.d.ts +16 -0
  31. package/build/src/mocking/lib/Trash.d.ts.map +1 -0
  32. package/build/src/mocking/lib/Trash.js +39 -0
  33. package/build/src/mocking/lib/Trash.js.map +1 -0
  34. package/build/src/mocking/lib/User.d.ts +12 -12
  35. package/build/src/mocking/lib/User.d.ts.map +1 -1
  36. package/build/src/mocking/lib/User.js +29 -26
  37. package/build/src/mocking/lib/User.js.map +1 -1
  38. package/build/src/sdk/SdkMock.d.ts +125 -156
  39. package/build/src/sdk/SdkMock.d.ts.map +1 -1
  40. package/build/src/sdk/SdkMock.js +774 -596
  41. package/build/src/sdk/SdkMock.js.map +1 -1
  42. package/build/tsconfig.tsbuildinfo +1 -1
  43. package/data/models/example-generator-api.json +9 -9
  44. package/package.json +5 -3
  45. package/src/mocking/ModelingMock.ts +19 -0
  46. package/src/mocking/ProjectMock.ts +1 -1
  47. package/src/mocking/lib/File.ts +72 -0
  48. package/src/mocking/lib/Group.ts +52 -0
  49. package/src/mocking/lib/Invitation.ts +58 -0
  50. package/src/mocking/lib/Organization.ts +42 -0
  51. package/src/mocking/lib/Patch.ts +128 -0
  52. package/src/mocking/lib/Trash.ts +47 -0
  53. package/src/mocking/lib/User.ts +30 -29
  54. package/src/sdk/SdkMock.ts +966 -650
@@ -1,51 +1,47 @@
1
- import { nanoid } from '../nanoid.js'
1
+ import { type ResponseGenerator, setupWorker, type MockHandler, type SetupWorkerOptions } from '@jarrodek/amw'
2
2
  import type { IOrganization } from '../models/store/Organization.js'
3
3
  import type { GroupSchema } from '../models/store/Group.js'
4
4
  import type { IUser } from '../models/store/User.js'
5
5
  import type { InvitationSchema } from '../models/store/Invitation.js'
6
- import { OrganizationKind, GroupKind, InvitationKind } from '../models/kinds.js'
7
- import { Kind as UserKind } from '../models/store/User.js'
8
- import { File, type IFile, type FileBreadcrumb } from '../models/store/File.js'
9
- import { CertificateFileKind, DomainFileKind, FolderKind, ProjectKind } from '../models/kinds.js'
6
+ import { type IFile, type FileBreadcrumb } from '../models/store/File.js'
10
7
  import type { ContextListResult, IBulkOperationResult } from '../events/BaseEvents.js'
11
- import type { MediaPatchRevision } from '../patch/types.js'
12
- import type { IFolder } from '../models/Folder.js'
13
8
  import type { TrashEntry } from '../models/TrashEntry.js'
14
- import type { StoreSdk } from './StoreSdkWeb.js'
15
- import * as sinon from 'sinon'
16
- import { Exception } from '../exceptions/exception.js'
9
+ import { RouteBuilder } from './RouteBuilder.js'
10
+ import { ModelingMock } from '../mocking/ModelingMock.js'
17
11
 
18
- /**
19
- * Options for customizing mock responses.
20
- */
21
- export interface MockResponseOptions {
22
- /**
23
- * Custom response data to return instead of generated random data.
24
- */
25
- data?: unknown
12
+ export interface MockResult {
26
13
  /**
27
- * HTTP status code to return. Defaults to 200.
14
+ * Custom response generator for the mock intercept.
28
15
  */
29
- status?: number
16
+ response?: ResponseGenerator
30
17
  /**
31
- * Custom headers to include in the response.
18
+ * If true, the request body will be generated using the body generator.
19
+ * It is useful when only setting up response headers or status code, but
20
+ * the request body should still be generated, even when missing in the `response` option.
32
21
  */
33
- headers?: Record<string, string>
22
+ forceBody?: boolean
34
23
  }
35
24
 
36
- /**
37
- * A stub reference that can be used to restore the original behavior.
38
- */
39
- export interface StubReference {
25
+ export interface MockListResult extends MockResult {
26
+ /**
27
+ * Number of items to generate in the list response.
28
+ */
29
+ size?: number
40
30
  /**
41
- * Restores the original behavior.
31
+ * If true, the response will include a cursor for pagination.
32
+ * If false, the response will not include a cursor.
33
+ * If not set, a random choice will be made.
42
34
  */
43
- restore: () => void
35
+ cursor?: boolean
44
36
  }
45
37
 
46
38
  /**
47
- * SDK mocking utility for testing. Provides simple API to mock SDK calls
48
- * with random or custom responses.
39
+ * SDK mocking utility for testing. Uses Service Workers to intercept HTTP requests
40
+ * and provide mock responses for API calls.
41
+ *
42
+ * This class uses the `@jarrodek/amw` library to set up a Service Worker that intercepts
43
+ * fetch requests matching the configured routes. Each method adds an intercept for a specific
44
+ * API endpoint, returning either random generated data or custom responses.
49
45
  *
50
46
  * @example
51
47
  * ```typescript
@@ -53,193 +49,477 @@ export interface StubReference {
53
49
  * import { StoreSdk } from '@api-client/core/sdk/StoreSdkWeb.js';
54
50
  *
55
51
  * const sdk = new StoreSdk('http://localhost:8080');
56
- * const mocker = new SdkMock(sdk);
52
+ * const mocker = new SdkMock({
53
+ * swPath: '/mockServiceWorker.js', // Path to the Service Worker script
54
+ * base: 'http://localhost:8080' // Base URL matching the SDK
55
+ * });
57
56
  *
58
- * // Simple usage - returns random valid organization
59
- * const stub1 = mocker.organizations.list();
57
+ * // Initialize the Service Worker
58
+ * await mocker.setup();
60
59
  *
61
- * // Custom response
62
- * const stub2 = mocker.organizations.create({
63
- * data: { key: 'org-1', name: 'Test Org', ... }
60
+ * // Add intercept - returns random organizations
61
+ * await mocker.organizations.list();
62
+ *
63
+ * // Custom response with specific data
64
+ * await mocker.organizations.create({
65
+ * response: {
66
+ * status: 201,
67
+ * headers: { 'Content-Type': 'application/json', 'X-Custom-Header': 'value' },
68
+ * body: JSON.stringify({ key: 'custom-id', name: 'Custom Org' })
69
+ * }
64
70
  * });
65
71
  *
66
- * // Custom status and headers
67
- * const stub3 = mocker.users.me({
68
- * status: 404,
69
- * headers: { 'X-Custom': 'value' }
72
+ * // Control pagination in list responses
73
+ * await mocker.groups.list({
74
+ * size: 10, // Number of items to generate
75
+ * cursor: true // Include pagination cursor
70
76
  * });
71
77
  *
72
- * // Restore all stubs
73
- * mocker.restore();
78
+ * // Error simulation
79
+ * await mocker.users.me({
80
+ * response: {
81
+ * status: 404,
82
+ * headers: { 'Content-Type': 'application/json' },
83
+ * body: JSON.stringify({ error: 'Not found' })
84
+ * }
85
+ * });
86
+ *
87
+ * // Remove all intercepts (keep Service Worker active)
88
+ * await mocker.reset();
89
+ *
90
+ * // Stop and remove the Service Worker
91
+ * await mocker.teardown();
74
92
  * ```
75
93
  */
76
94
  export class SdkMock {
77
- private stubs: StubReference[] = []
95
+ handler?: MockHandler
96
+ gen = new ModelingMock()
97
+
98
+ constructor(public options?: SetupWorkerOptions) {}
99
+
100
+ /**
101
+ * Initializes the mock handler. It uses options provided in the constructor.
102
+ * It has to be called before using any of the mock methods.
103
+ */
104
+ async setup(): Promise<void> {
105
+ this.handler = await setupWorker(this.options)
106
+ }
107
+
108
+ /**
109
+ * Removes the mock worker and all intercepts.
110
+ */
111
+ async teardown(): Promise<void> {
112
+ await this.mock.stop()
113
+ }
114
+
115
+ /**
116
+ * Removes all added intercepts.
117
+ */
118
+ async reset(): Promise<void> {
119
+ await this.mock.reset()
120
+ }
121
+
122
+ get mock(): MockHandler {
123
+ if (!this.handler) {
124
+ throw new Error('Mock handler not initialized. Call setup() first.')
125
+ }
126
+ return this.handler
127
+ }
78
128
 
79
- constructor(private sdk: StoreSdk) {}
129
+ protected createCursorOption(init: MockListResult = {}): string | undefined {
130
+ if (init.cursor === false) {
131
+ return undefined
132
+ }
133
+ const hasCursor = init.cursor === true ? true : this.gen.faker.datatype.boolean()
134
+ if (!hasCursor) {
135
+ return undefined
136
+ }
137
+ return this.gen.faker.internet.jwt()
138
+ }
139
+
140
+ protected createDefaultResponse(
141
+ status: number,
142
+ headers?: Record<string, string>,
143
+ body?: () => string,
144
+ userConfig?: MockResult
145
+ ): ResponseGenerator {
146
+ let respond: ResponseGenerator
147
+ if (userConfig?.response) {
148
+ // user config takes precedence
149
+ respond = userConfig.response
150
+ } else {
151
+ respond = {}
152
+ }
153
+ // Set defaults if not provided in user config
154
+ if (!respond.status) {
155
+ respond.status = status
156
+ }
157
+ // only set headers if the user didn't configure the response only.
158
+ // The user may want to remove default headers.
159
+ if (!userConfig || !userConfig.response) {
160
+ respond.headers = headers
161
+ }
162
+ if (!respond.body && userConfig?.forceBody && body) {
163
+ // when body is missing and forceBody is set, generate the body
164
+ respond.body = body()
165
+ } else if (body && (!userConfig || !userConfig.response)) {
166
+ // we set the body by default when the user config is missing
167
+ respond.body = body()
168
+ }
169
+ return respond
170
+ }
80
171
 
81
172
  /**
82
173
  * Organization API mocks.
83
174
  */
84
175
  organizations = {
85
176
  /**
86
- * Mocks the `organizations.list()` method.
87
- * @param options Optional response customization.
88
- * @returns A stub reference that can be used to restore the original behavior.
177
+ * Adds an intercept to mock the `organizations.list()` method.
178
+ * @param options Optional response configuration
89
179
  */
90
- list: (options?: MockResponseOptions): StubReference => {
91
- return this.createStub('organizations', 'list', () => {
92
- const defaultData = {
93
- items: [this.generateOrganization(), this.generateOrganization()],
94
- nextPageToken: undefined,
95
- }
96
- if (options?.status !== undefined && options.status !== 200) {
97
- throw new Exception('Mocked error', { status: options.status })
98
- }
99
- return (options?.data ?? defaultData) as unknown
180
+ list: async (init?: MockListResult): Promise<void> => {
181
+ const { mock } = this
182
+ // const respond = init?.response ?? {
183
+ // status: 200,
184
+ // headers: { 'content-type': 'application/json' },
185
+ // body: JSON.stringify({
186
+ // items: this.gen.organization.organizations(init?.size ?? 5),
187
+ // cursor: this.createCursorOption(init),
188
+ // } as ContextListResult<IOrganization>),
189
+ // }
190
+ const respond = this.createDefaultResponse(
191
+ 200,
192
+ { 'content-type': 'application/json' },
193
+ () =>
194
+ JSON.stringify({
195
+ items: this.gen.organization.organizations(init?.size ?? 5),
196
+ cursor: this.createCursorOption(init),
197
+ } as ContextListResult<IOrganization>),
198
+ init
199
+ )
200
+ await mock.add({
201
+ match: {
202
+ uri: RouteBuilder.organizations(),
203
+ methods: ['GET'],
204
+ },
205
+ respond,
100
206
  })
101
207
  },
102
208
 
103
209
  /**
104
- * Mocks the `organizations.create()` method.
105
- * @param options Optional response customization.
106
- * @returns A stub reference that can be used to restore the original behavior.
210
+ * Adds an intercept to mock the `organizations.create()` method.
211
+ * @param options Optional response configuration
107
212
  */
108
- create: (options?: MockResponseOptions): StubReference => {
109
- return this.createStub('organizations', 'create', () => {
110
- const defaultData = this.generateOrganization()
111
- if (options?.status !== undefined && options.status !== 200) {
112
- throw new Exception('Mocked error', { status: options.status })
113
- }
114
- return (options?.data ?? defaultData) as unknown
213
+ create: async (init?: MockResult): Promise<void> => {
214
+ const { mock } = this
215
+ // const respond = init?.response ?? {
216
+ // status: 200,
217
+ // headers: { 'content-type': 'application/json' },
218
+ // body: JSON.stringify(this.gen.organization.organization()),
219
+ // }
220
+ const respond = this.createDefaultResponse(
221
+ 200,
222
+ { 'content-type': 'application/json' },
223
+ () => JSON.stringify(this.gen.organization.organization()),
224
+ init
225
+ )
226
+ await mock.add({
227
+ match: {
228
+ uri: RouteBuilder.organizations(),
229
+ methods: ['POST'],
230
+ },
231
+ respond,
115
232
  })
116
233
  },
117
234
 
118
235
  invitations: {
119
- list: (options?: MockResponseOptions): StubReference => {
120
- return this.createStub('organizations.invitations', 'list', () => {
121
- const defaultData = {
122
- items: [this.generateInvitation(), this.generateInvitation()],
123
- }
124
- if (options?.status !== undefined && options.status !== 200) {
125
- throw new Exception('Mocked error', { status: options.status })
126
- }
127
- return (options?.data ?? defaultData) as unknown
236
+ list: async (init?: MockListResult): Promise<void> => {
237
+ const { mock } = this
238
+ // const respond = init?.response ?? {
239
+ // status: 200,
240
+ // headers: { 'content-type': 'application/json' },
241
+ // body: JSON.stringify({
242
+ // items: this.gen.invitation.invitations(init?.size ?? 5),
243
+ // cursor: this.createCursorOption(init),
244
+ // } as ContextListResult<InvitationSchema>),
245
+ // }
246
+ const respond = this.createDefaultResponse(
247
+ 200,
248
+ { 'content-type': 'application/json' },
249
+ () => {
250
+ const obj: ContextListResult<InvitationSchema> = {
251
+ items: this.gen.invitation.invitations(init?.size ?? 5),
252
+ cursor: this.createCursorOption(init),
253
+ }
254
+ return JSON.stringify(obj)
255
+ },
256
+ init
257
+ )
258
+ await mock.add({
259
+ match: {
260
+ uri: RouteBuilder.invitations(':oid'),
261
+ methods: ['GET'],
262
+ },
263
+ respond,
128
264
  })
129
265
  },
130
- create: (options?: MockResponseOptions): StubReference => {
131
- return this.createStub('organizations.invitations', 'create', () => {
132
- const defaultData = this.generateInvitation()
133
- if (options?.status !== undefined && options.status !== 200) {
134
- throw new Exception('Mocked error', { status: options.status })
135
- }
136
- return (options?.data ?? defaultData) as unknown
266
+ create: async (init?: MockResult): Promise<void> => {
267
+ const { mock } = this
268
+ // const respond = init?.response ?? {
269
+ // status: 200,
270
+ // headers: { 'content-type': 'application/json' },
271
+ // body: JSON.stringify(this.gen.invitation.invitation()),
272
+ // }
273
+ const respond = this.createDefaultResponse(
274
+ 200,
275
+ { 'content-type': 'application/json' },
276
+ () => JSON.stringify(this.gen.invitation.invitation()),
277
+ init
278
+ )
279
+ await mock.add({
280
+ match: {
281
+ uri: RouteBuilder.invitations(':oid'),
282
+ methods: ['POST'],
283
+ },
284
+ respond,
137
285
  })
138
286
  },
139
- findByToken: (options?: MockResponseOptions): StubReference => {
140
- return this.createStub('organizations.invitations', 'findByToken', () => {
141
- const defaultData = this.generateInvitation()
142
- if (options?.status !== undefined && options.status !== 200) {
143
- throw new Exception('Mocked error', { status: options.status })
144
- }
145
- return (options?.data ?? defaultData) as unknown
287
+ findByToken: async (init?: MockResult): Promise<void> => {
288
+ const { mock } = this
289
+ // const respond = init?.response ?? {
290
+ // status: 200,
291
+ // headers: { 'content-type': 'application/json' },
292
+ // body: JSON.stringify(this.gen.invitation.invitation()),
293
+ // }
294
+ const respond = this.createDefaultResponse(
295
+ 200,
296
+ { 'content-type': 'application/json' },
297
+ () => JSON.stringify(this.gen.invitation.invitation()),
298
+ init
299
+ )
300
+
301
+ await mock.add({
302
+ match: {
303
+ uri: RouteBuilder.findInvitation(),
304
+ methods: ['GET'],
305
+ },
306
+ respond,
146
307
  })
147
308
  },
148
- decline: (options?: MockResponseOptions): StubReference => {
149
- return this.createStub('organizations.invitations', 'decline', () => {
150
- const defaultData = this.generateInvitation()
151
- if (options?.status !== undefined && options.status !== 200) {
152
- throw new Exception('Mocked error', { status: options.status })
153
- }
154
- return (options?.data ?? defaultData) as unknown
309
+ decline: async (init?: MockResult): Promise<void> => {
310
+ const { mock } = this
311
+ // const respond = init?.response ?? {
312
+ // status: 200,
313
+ // headers: { 'content-type': 'application/json' },
314
+ // body: JSON.stringify(this.gen.invitation.invitation()),
315
+ // }
316
+ const respond = this.createDefaultResponse(
317
+ 200,
318
+ { 'content-type': 'application/json' },
319
+ () => JSON.stringify(this.gen.invitation.invitation()),
320
+ init
321
+ )
322
+
323
+ await mock.add({
324
+ match: {
325
+ uri: RouteBuilder.declineInvitation(':oid', ':id'),
326
+ methods: ['POST'],
327
+ },
328
+ respond,
155
329
  })
156
330
  },
157
- delete: (options?: MockResponseOptions): StubReference => {
158
- return this.createStub('organizations.invitations', 'delete', () => {
159
- const defaultData = this.generateInvitation()
160
- if (options?.status !== undefined && options.status !== 200) {
161
- throw new Exception('Mocked error', { status: options.status })
162
- }
163
- return (options?.data ?? defaultData) as unknown
331
+ delete: async (init?: MockResult): Promise<void> => {
332
+ const { mock } = this
333
+ // const respond = init?.response ?? {
334
+ // status: 200,
335
+ // headers: { 'content-type': 'application/json' },
336
+ // body: JSON.stringify(this.gen.invitation.invitation()),
337
+ // }
338
+ const respond = this.createDefaultResponse(
339
+ 200,
340
+ { 'content-type': 'application/json' },
341
+ () => JSON.stringify(this.gen.invitation.invitation()),
342
+ init
343
+ )
344
+
345
+ await mock.add({
346
+ match: {
347
+ uri: RouteBuilder.invitation(':oid', ':id'),
348
+ methods: ['DELETE'],
349
+ },
350
+ respond,
164
351
  })
165
352
  },
166
- patch: (options?: MockResponseOptions): StubReference => {
167
- return this.createStub('organizations.invitations', 'patch', () => {
168
- const defaultData = this.generateInvitation()
169
- if (options?.status !== undefined && options.status !== 200) {
170
- throw new Exception('Mocked error', { status: options.status })
171
- }
172
- return (options?.data ?? defaultData) as unknown
353
+ patch: async (init?: MockResult): Promise<void> => {
354
+ const { mock } = this
355
+ // const respond = init?.response ?? {
356
+ // status: 200,
357
+ // headers: { 'content-type': 'application/json' },
358
+ // body: JSON.stringify(this.gen.invitation.invitation()),
359
+ // }
360
+ const respond = this.createDefaultResponse(
361
+ 200,
362
+ { 'content-type': 'application/json' },
363
+ () => JSON.stringify(this.gen.invitation.invitation()),
364
+ init
365
+ )
366
+ await mock.add({
367
+ match: {
368
+ uri: RouteBuilder.invitation(':oid', ':id'),
369
+ methods: ['PATCH'],
370
+ },
371
+ respond,
173
372
  })
174
373
  },
175
- resend: (options?: MockResponseOptions): StubReference => {
176
- return this.createStub('organizations.invitations', 'resend', () => {
177
- const defaultData = this.generateInvitation()
178
- if (options?.status !== undefined && options.status !== 200) {
179
- throw new Exception('Mocked error', { status: options.status })
180
- }
181
- return (options?.data ?? defaultData) as unknown
374
+ resend: async (init?: MockResult): Promise<void> => {
375
+ const { mock } = this
376
+ // const respond = init?.response ?? {
377
+ // status: 200,
378
+ // headers: { 'content-type': 'application/json' },
379
+ // body: JSON.stringify(this.gen.invitation.invitation()),
380
+ // }
381
+ const respond = this.createDefaultResponse(
382
+ 200,
383
+ { 'content-type': 'application/json' },
384
+ () => JSON.stringify(this.gen.invitation.invitation()),
385
+ init
386
+ )
387
+
388
+ await mock.add({
389
+ match: {
390
+ uri: RouteBuilder.resendInvitation(':oid', ':id'),
391
+ methods: ['PUT'],
392
+ },
393
+ respond,
182
394
  })
183
395
  },
184
396
  },
185
397
 
186
398
  users: {
187
- list: (options?: MockResponseOptions): StubReference => {
188
- return this.createStub('organizations.users', 'list', () => {
189
- const defaultData = {
190
- items: [this.generateUser(), this.generateUser()],
191
- }
192
- if (options?.status !== undefined && options.status !== 200) {
193
- throw new Exception('Mocked error', { status: options.status })
194
- }
195
- return (options?.data ?? defaultData) as unknown
399
+ list: async (init?: MockListResult): Promise<void> => {
400
+ const { mock } = this
401
+ // const respond = init?.response ?? {
402
+ // status: 200,
403
+ // headers: { 'content-type': 'application/json' },
404
+ // body: JSON.stringify({
405
+ // items: this.gen.user.users(init?.size ?? 5),
406
+ // cursor: this.createCursorOption(init),
407
+ // } as ContextListResult<IUser>),
408
+ // }
409
+ const respond = this.createDefaultResponse(
410
+ 200,
411
+ { 'content-type': 'application/json' },
412
+ () => {
413
+ const obj: ContextListResult<IUser> = {
414
+ items: this.gen.user.users(init?.size ?? 5),
415
+ cursor: this.createCursorOption(init),
416
+ }
417
+ return JSON.stringify(obj)
418
+ },
419
+ init
420
+ )
421
+ await mock.add({
422
+ match: {
423
+ uri: RouteBuilder.organizationUsers(':oid'),
424
+ methods: ['GET'],
425
+ },
426
+ respond,
196
427
  })
197
428
  },
198
- read: (options?: MockResponseOptions): StubReference => {
199
- return this.createStub('organizations.users', 'read', () => {
200
- const defaultData = this.generateUser()
201
- if (options?.status !== undefined && options.status !== 200) {
202
- throw new Exception('Mocked error', { status: options.status })
203
- }
204
- return (options?.data ?? defaultData) as unknown
429
+ read: async (init?: MockResult): Promise<void> => {
430
+ const { mock } = this
431
+ // const respond = init?.response ?? {
432
+ // status: 200,
433
+ // headers: { 'content-type': 'application/json' },
434
+ // body: JSON.stringify(this.gen.user.user()),
435
+ // }
436
+ const respond = this.createDefaultResponse(
437
+ 200,
438
+ { 'content-type': 'application/json' },
439
+ () => JSON.stringify(this.gen.user.user()),
440
+ init
441
+ )
442
+ await mock.add({
443
+ match: {
444
+ uri: RouteBuilder.organizationUser(':oid', ':id'),
445
+ methods: ['GET'],
446
+ },
447
+ respond,
205
448
  })
206
449
  },
207
- readBatch: (options?: MockResponseOptions): StubReference => {
208
- return this.createStub('organizations.users', 'readBatch', () => {
209
- const defaultData = {
210
- items: [this.generateUser(), this.generateUser()],
211
- }
212
- if (options?.status !== undefined && options.status !== 200) {
213
- throw new Exception('Mocked error', { status: options.status })
214
- }
215
- return (options?.data ?? defaultData) as unknown
450
+ readBatch: async (init?: MockListResult): Promise<void> => {
451
+ const { mock } = this
452
+ const path = RouteBuilder.organizationUserBatch(':oid')
453
+ const respond = init?.response ?? {
454
+ status: 200,
455
+ headers: { 'content-type': 'application/json' },
456
+ body: JSON.stringify({
457
+ items: this.gen.user.users(init?.size ?? 5),
458
+ cursor: this.createCursorOption(init),
459
+ } as ContextListResult<IUser>),
460
+ }
461
+ await mock.add({
462
+ match: {
463
+ uri: path,
464
+ methods: ['POST'],
465
+ },
466
+ respond,
216
467
  })
217
468
  },
218
- activate: (options?: MockResponseOptions): StubReference => {
219
- return this.createStub('organizations.users', 'activate', () => {
220
- const defaultData = this.generateUser()
221
- if (options?.status !== undefined && options.status !== 200) {
222
- throw new Exception('Mocked error', { status: options.status })
223
- }
224
- return (options?.data ?? defaultData) as unknown
469
+ activate: async (init?: MockResult): Promise<void> => {
470
+ const { mock } = this
471
+ // const respond = init?.response ?? {
472
+ // status: 200,
473
+ // headers: { 'content-type': 'application/json' },
474
+ // body: JSON.stringify(this.gen.user.user()),
475
+ // }
476
+ const respond = this.createDefaultResponse(
477
+ 200,
478
+ { 'content-type': 'application/json' },
479
+ () => JSON.stringify(this.gen.user.user()),
480
+ init
481
+ )
482
+ await mock.add({
483
+ match: {
484
+ uri: RouteBuilder.organizationUserActivate(':oid', ':id'),
485
+ methods: ['POST'],
486
+ },
487
+ respond,
225
488
  })
226
489
  },
227
- deactivate: (options?: MockResponseOptions): StubReference => {
228
- return this.createStub('organizations.users', 'deactivate', () => {
229
- const defaultData = this.generateUser()
230
- if (options?.status !== undefined && options.status !== 200) {
231
- throw new Exception('Mocked error', { status: options.status })
232
- }
233
- return (options?.data ?? defaultData) as unknown
490
+ deactivate: async (init?: MockResult): Promise<void> => {
491
+ const { mock } = this
492
+ // const respond = init?.response ?? {
493
+ // status: 200,
494
+ // headers: { 'content-type': 'application/json' },
495
+ // body: JSON.stringify(this.gen.user.user()),
496
+ // }
497
+ const respond = this.createDefaultResponse(
498
+ 200,
499
+ { 'content-type': 'application/json' },
500
+ () => JSON.stringify(this.gen.user.user()),
501
+ init
502
+ )
503
+ await mock.add({
504
+ match: {
505
+ uri: RouteBuilder.organizationUserDeactivate(':oid', ':id'),
506
+ methods: ['POST'],
507
+ },
508
+ respond,
234
509
  })
235
510
  },
236
- delete: (options?: MockResponseOptions): StubReference => {
237
- return this.createStub('organizations.users', 'delete', () => {
238
- const status = options?.status ?? 204
239
- if (status !== 204) {
240
- throw new Exception('Mocked error', { status })
241
- }
242
- return undefined
511
+ delete: async (init?: MockResult): Promise<void> => {
512
+ const { mock } = this
513
+ // const respond = init?.response ?? {
514
+ // status: 204,
515
+ // }
516
+ const respond = this.createDefaultResponse(204, undefined, undefined, init)
517
+ await mock.add({
518
+ match: {
519
+ uri: RouteBuilder.organizationUser(':oid', ':id'),
520
+ methods: ['DELETE'],
521
+ },
522
+ respond,
243
523
  })
244
524
  },
245
525
  },
@@ -252,105 +532,156 @@ export class SdkMock {
252
532
  /**
253
533
  * Mocks the `groups.list()` method.
254
534
  * @param options Optional response customization.
255
- * @returns A stub reference that can be used to restore the original behavior.
256
535
  */
257
- list: (options?: MockResponseOptions): StubReference => {
258
- return this.createStub('groups', 'list', () => {
259
- const defaultData = {
260
- items: [this.generateGroup(), this.generateGroup()],
261
- nextPageToken: undefined,
262
- }
263
- if (options?.status !== undefined && options.status !== 200) {
264
- throw new Exception('Mocked error', { status: options.status })
265
- }
266
- return (options?.data ?? defaultData) as unknown
536
+ list: async (init?: MockListResult): Promise<void> => {
537
+ const { mock } = this
538
+ // const respond = init?.response ?? {
539
+ // status: 200,
540
+ // headers: { 'content-type': 'application/json' },
541
+ // body: JSON.stringify({
542
+ // items: this.gen.group.groups(init?.size ?? 5),
543
+ // cursor: this.createCursorOption(init),
544
+ // } as ContextListResult<GroupSchema>),
545
+ // }
546
+ const respond = this.createDefaultResponse(
547
+ 200,
548
+ { 'content-type': 'application/json' },
549
+ () => {
550
+ const obj: ContextListResult<GroupSchema> = {
551
+ items: this.gen.group.groups(init?.size ?? 5),
552
+ cursor: this.createCursorOption(init),
553
+ }
554
+ return JSON.stringify(obj)
555
+ },
556
+ init
557
+ )
558
+ await mock.add({
559
+ match: {
560
+ uri: RouteBuilder.groups(':oid'),
561
+ methods: ['GET'],
562
+ },
563
+ respond,
267
564
  })
268
565
  },
269
566
 
270
567
  /**
271
568
  * Mocks the `groups.create()` method.
272
569
  * @param options Optional response customization.
273
- * @returns A stub reference that can be used to restore the original behavior.
274
570
  */
275
- create: (options?: MockResponseOptions): StubReference => {
276
- return this.createStub('groups', 'create', () => {
277
- const defaultData = this.generateGroup()
278
- const status = options?.status ?? 201
279
- if (status !== 201) {
280
- throw new Exception('Mocked error', { status })
281
- }
282
- return (options?.data ?? defaultData) as unknown
283
- })
284
- },
285
-
286
- /**
287
- * Mocks the `groups.read()` method.
288
- * @param options Optional response customization.
289
- * @returns A stub reference that can be used to restore the original behavior.
290
- */
291
- read: (options?: MockResponseOptions): StubReference => {
292
- return this.createStub('groups', 'read', () => {
293
- const defaultData = this.generateGroup()
294
- if (options?.status !== undefined && options.status !== 200) {
295
- throw new Exception('Mocked error', { status: options.status })
296
- }
297
- return (options?.data ?? defaultData) as unknown
571
+ create: async (init?: MockResult): Promise<void> => {
572
+ const { mock } = this
573
+ // const respond = init?.response ?? {
574
+ // status: 201,
575
+ // headers: { 'content-type': 'application/json' },
576
+ // body: JSON.stringify(this.gen.group.group()),
577
+ // }
578
+ const respond = this.createDefaultResponse(
579
+ 201,
580
+ { 'content-type': 'application/json' },
581
+ () => JSON.stringify(this.gen.group.group()),
582
+ init
583
+ )
584
+ await mock.add({
585
+ match: {
586
+ uri: RouteBuilder.groups(':oid'),
587
+ methods: ['POST'],
588
+ },
589
+ respond,
298
590
  })
299
591
  },
300
592
 
301
593
  /**
302
594
  * Mocks the `groups.update()` method.
303
595
  * @param options Optional response customization.
304
- * @returns A stub reference that can be used to restore the original behavior.
305
596
  */
306
- update: (options?: MockResponseOptions): StubReference => {
307
- return this.createStub('groups', 'update', () => {
308
- const defaultData = this.generateGroup()
309
- if (options?.status !== undefined && options.status !== 200) {
310
- throw new Exception('Mocked error', { status: options.status })
311
- }
312
- return (options?.data ?? defaultData) as unknown
597
+ update: async (init?: MockResult): Promise<void> => {
598
+ const { mock } = this
599
+ // const respond = init?.response ?? {
600
+ // status: 200,
601
+ // headers: { 'content-type': 'application/json' },
602
+ // body: JSON.stringify(this.gen.group.group()),
603
+ // }
604
+ const respond = this.createDefaultResponse(
605
+ 200,
606
+ { 'content-type': 'application/json' },
607
+ () => JSON.stringify(this.gen.group.group()),
608
+ init
609
+ )
610
+ await mock.add({
611
+ match: {
612
+ uri: RouteBuilder.group(':oid', ':key'),
613
+ methods: ['PATCH'],
614
+ },
615
+ respond,
313
616
  })
314
617
  },
315
618
 
316
619
  /**
317
620
  * Mocks the `groups.delete()` method.
318
621
  * @param options Optional response customization.
319
- * @returns A stub reference that can be used to restore the original behavior.
320
622
  */
321
- delete: (options?: MockResponseOptions): StubReference => {
322
- return this.createStub('groups', 'delete', () => {
323
- const status = options?.status ?? 204
324
- if (status !== 204) {
325
- throw new Exception('Mocked error', { status })
326
- }
327
- return undefined
623
+ delete: async (init?: MockResult): Promise<void> => {
624
+ const { mock } = this
625
+ // const respond = init?.response ?? {
626
+ // status: 204,
627
+ // }
628
+ const respond = this.createDefaultResponse(204, undefined, undefined, init)
629
+ await mock.add({
630
+ match: {
631
+ uri: RouteBuilder.group(':oid', ':key'),
632
+ methods: ['DELETE'],
633
+ },
634
+ respond,
328
635
  })
329
636
  },
330
637
 
331
638
  /**
332
639
  * Mocks the `groups.addUsers()` method.
333
640
  */
334
- addUsers: (options?: MockResponseOptions): StubReference => {
335
- return this.createStub('groups', 'addUsers', () => {
336
- const defaultData = this.generateGroup()
337
- if (options?.status !== undefined && options.status !== 200) {
338
- throw new Exception('Mocked error', { status: options.status })
339
- }
340
- return (options?.data ?? defaultData) as unknown
641
+ addUsers: async (init?: MockResult): Promise<void> => {
642
+ const { mock } = this
643
+ // const respond = init?.response ?? {
644
+ // status: 200,
645
+ // headers: { 'content-type': 'application/json' },
646
+ // body: JSON.stringify(this.gen.group.group()),
647
+ // }
648
+ const respond = this.createDefaultResponse(
649
+ 200,
650
+ { 'content-type': 'application/json' },
651
+ () => JSON.stringify(this.gen.group.group()),
652
+ init
653
+ )
654
+ await mock.add({
655
+ match: {
656
+ uri: RouteBuilder.groupUsers(':oid', ':key'),
657
+ methods: ['POST'],
658
+ },
659
+ respond,
341
660
  })
342
661
  },
343
662
 
344
663
  /**
345
664
  * Mocks the `groups.removeUsers()` method.
346
665
  */
347
- removeUsers: (options?: MockResponseOptions): StubReference => {
348
- return this.createStub('groups', 'removeUsers', () => {
349
- const defaultData = this.generateGroup()
350
- if (options?.status !== undefined && options.status !== 200) {
351
- throw new Exception('Mocked error', { status: options.status })
352
- }
353
- return (options?.data ?? defaultData) as unknown
666
+ removeUsers: async (init?: MockResult): Promise<void> => {
667
+ const { mock } = this
668
+ // const respond = init?.response ?? {
669
+ // status: 200,
670
+ // headers: { 'content-type': 'application/json' },
671
+ // body: JSON.stringify(this.gen.group.group()),
672
+ // }
673
+ const respond = this.createDefaultResponse(
674
+ 200,
675
+ { 'content-type': 'application/json' },
676
+ () => JSON.stringify(this.gen.group.group()),
677
+ init
678
+ )
679
+ await mock.add({
680
+ match: {
681
+ uri: RouteBuilder.groupUsers(':oid', ':key'),
682
+ methods: ['DELETE'],
683
+ },
684
+ respond,
354
685
  })
355
686
  },
356
687
  }
@@ -362,15 +693,26 @@ export class SdkMock {
362
693
  /**
363
694
  * Mocks the `user.me()` method.
364
695
  * @param options Optional response customization.
365
- * @returns A stub reference that can be used to restore the original behavior.
366
696
  */
367
- me: (options?: MockResponseOptions): StubReference => {
368
- return this.createStub('user', 'me', () => {
369
- const defaultData = this.generateUser()
370
- if (options?.status !== undefined && options.status !== 200) {
371
- throw new Exception(`Mocked error. Status: ${options.status}`, { status: options.status })
372
- }
373
- return (options?.data ?? defaultData) as unknown
697
+ me: async (init?: MockResult): Promise<void> => {
698
+ const { mock } = this
699
+ // const respond = init?.response ?? {
700
+ // status: 200,
701
+ // headers: { 'content-type': 'application/json' },
702
+ // body: JSON.stringify(this.gen.user.user()),
703
+ // }
704
+ const respond = this.createDefaultResponse(
705
+ 200,
706
+ { 'content-type': 'application/json' },
707
+ () => JSON.stringify(this.gen.user.user()),
708
+ init
709
+ )
710
+ await mock.add({
711
+ match: {
712
+ uri: RouteBuilder.usersMe(),
713
+ methods: ['GET'],
714
+ },
715
+ respond,
374
716
  })
375
717
  },
376
718
  }
@@ -382,232 +724,394 @@ export class SdkMock {
382
724
  /**
383
725
  * Mocks the `file.list()` method.
384
726
  */
385
- list: (options?: MockResponseOptions): StubReference => {
386
- return this.createStub('file', 'list', () => {
387
- const defaultData: ContextListResult<IFile> = {
388
- items: [this.generateFile(), this.generateFile()],
389
- }
390
- if (options?.status !== undefined && options.status !== 200) {
391
- throw new Exception('Mocked error', { status: options.status })
392
- }
393
- return (options?.data ?? defaultData) as unknown
727
+ list: async (init?: MockListResult): Promise<void> => {
728
+ const { mock } = this
729
+ // const respond = init?.response ?? {
730
+ // status: 200,
731
+ // headers: { 'content-type': 'application/json' },
732
+ // body: JSON.stringify({
733
+ // items: this.gen.file.files(init?.size ?? 5),
734
+ // cursor: this.createCursorOption(init),
735
+ // } as ContextListResult<IFile>),
736
+ // }
737
+ const respond = this.createDefaultResponse(
738
+ 200,
739
+ { 'content-type': 'application/json' },
740
+ () => {
741
+ const obj: ContextListResult<IFile> = {
742
+ items: this.gen.file.files(init?.size ?? 5),
743
+ cursor: this.createCursorOption(init),
744
+ }
745
+ return JSON.stringify(obj)
746
+ },
747
+ init
748
+ )
749
+ await mock.add({
750
+ match: {
751
+ uri: RouteBuilder.files(':oid'),
752
+ methods: ['GET'],
753
+ },
754
+ respond,
394
755
  })
395
756
  },
396
757
 
397
758
  /**
398
759
  * Mocks the `file.createMeta()` method.
399
760
  */
400
- createMeta: (options?: MockResponseOptions): StubReference => {
401
- return this.createStub('file', 'createMeta', () => {
402
- const defaultData: IFile = this.generateFile()
403
- const status = options?.status ?? 201
404
- if (status !== 201) {
405
- throw new Exception('Mocked error', { status })
406
- }
407
- return (options?.data ?? defaultData) as unknown
761
+ createMeta: async (init?: MockResult): Promise<void> => {
762
+ const { mock } = this
763
+ // const respond = init?.response ?? {
764
+ // status: 201,
765
+ // headers: { 'content-type': 'application/json' },
766
+ // body: JSON.stringify(this.gen.file.file()),
767
+ // }
768
+ const respond = this.createDefaultResponse(
769
+ 201,
770
+ { 'content-type': 'application/json' },
771
+ () => JSON.stringify(this.gen.file.file()),
772
+ init
773
+ )
774
+ await mock.add({
775
+ match: {
776
+ uri: RouteBuilder.files(':oid'),
777
+ methods: ['POST'],
778
+ },
779
+ respond,
408
780
  })
409
781
  },
410
782
 
411
783
  /**
412
784
  * Mocks the `file.createMedia()` method.
413
785
  */
414
- createMedia: (options?: MockResponseOptions): StubReference => {
415
- return this.createStub('file', 'createMedia', () => {
416
- const status = options?.status ?? 200
417
- if (status !== 200) {
418
- throw new Exception('Mocked error', { status })
419
- }
420
- return undefined
786
+ createMedia: async (init?: MockResult): Promise<void> => {
787
+ const { mock } = this
788
+ // const respond = init?.response ?? {
789
+ // status: 200,
790
+ // }
791
+ const respond = this.createDefaultResponse(200, undefined, undefined, init)
792
+ await mock.add({
793
+ match: {
794
+ uri: RouteBuilder.fileMedia(':oid', ':id'),
795
+ methods: ['PUT'],
796
+ },
797
+ respond,
421
798
  })
422
799
  },
423
800
 
424
801
  /**
425
802
  * Mocks the `file.create()` method.
426
803
  */
427
- create: (options?: MockResponseOptions): StubReference => {
428
- return this.createStub('file', 'create', () => {
429
- const status = options?.status ?? 201
430
- if (status !== 201) {
431
- throw new Exception('Mocked error', { status })
432
- }
433
- const defaultData: IFile = this.generateFile()
434
- return (options?.data ?? defaultData) as unknown
435
- })
804
+ create: async (init?: MockResult): Promise<void> => {
805
+ await this.file.createMeta(init)
806
+ // When SDK's file.create() is called, it responds with
807
+ // what the result of file.createMeta() would be.
808
+ // Because of that, we don't need to configure the media request.
809
+ await this.file.createMedia()
436
810
  },
437
811
 
438
812
  /**
439
813
  * Mocks the `file.createFolder()` method.
440
814
  */
441
- createFolder: (options?: MockResponseOptions): StubReference => {
442
- return this.createStub('file', 'createFolder', () => {
443
- const status = options?.status ?? 201
444
- if (status !== 201) {
445
- throw new Exception('Mocked error', { status })
446
- }
447
- const defaultData: IFolder = this.generateFolder()
448
- return (options?.data ?? defaultData) as unknown
815
+ createFolder: async (init?: MockResult): Promise<void> => {
816
+ const { mock } = this
817
+ // const respond = init?.response ?? {
818
+ // status: 201,
819
+ // headers: { 'content-type': 'application/json' },
820
+ // body: JSON.stringify(this.gen.file.folder()),
821
+ // }
822
+ const respond = this.createDefaultResponse(
823
+ 201,
824
+ { 'content-type': 'application/json' },
825
+ () => JSON.stringify(this.gen.file.folder()),
826
+ init
827
+ )
828
+ await mock.add({
829
+ match: {
830
+ uri: RouteBuilder.files(':oid'),
831
+ methods: ['POST'],
832
+ },
833
+ respond,
449
834
  })
450
835
  },
451
836
 
452
837
  /**
453
838
  * Mocks the `file.read()` method.
454
839
  */
455
- read: (options?: MockResponseOptions): StubReference => {
456
- return this.createStub('file', 'read', () => {
457
- const defaultData: IFile = this.generateFile()
458
- if (options?.status !== undefined && options.status !== 200) {
459
- throw new Exception('Mocked error', { status: options.status })
460
- }
461
- return (options?.data ?? defaultData) as unknown
840
+ read: async (init?: MockResult): Promise<void> => {
841
+ const { mock } = this
842
+ // const respond = init?.response ?? {
843
+ // status: 200,
844
+ // headers: { 'content-type': 'application/json' },
845
+ // body: JSON.stringify(this.gen.file.file()),
846
+ // }
847
+ const respond = this.createDefaultResponse(
848
+ 200,
849
+ { 'content-type': 'application/json' },
850
+ () => JSON.stringify(this.gen.file.file()),
851
+ init
852
+ )
853
+ await mock.add({
854
+ match: {
855
+ uri: RouteBuilder.file(':oid', ':id'),
856
+ methods: ['GET'],
857
+ },
858
+ respond,
462
859
  })
463
860
  },
464
861
 
465
862
  /**
466
863
  * Mocks the `file.readMedia()` method.
467
864
  */
468
- readMedia: (options?: MockResponseOptions): StubReference => {
469
- return this.createStub('file', 'readMedia', () => {
470
- if (options?.status !== undefined && options.status !== 200) {
471
- throw new Exception('Mocked error', { status: options.status })
472
- }
473
- const defaultData = { media: { ok: true }, version: 1 }
474
- return (options?.data ?? defaultData) as unknown
865
+ readMedia: async (init?: MockResult): Promise<void> => {
866
+ const { mock } = this
867
+ // const respond = init?.response ?? {
868
+ // status: 200,
869
+ // headers: {
870
+ // 'content-type': 'application/json',
871
+ // 'x-version': `${this.gen.faker.number.int({ min: 1, max: 100 })}`,
872
+ // },
873
+ // body: JSON.stringify({ data: this.gen.faker.lorem.sentences() }),
874
+ // }
875
+ const respond = this.createDefaultResponse(
876
+ 200,
877
+ {
878
+ 'content-type': 'application/json',
879
+ 'x-version': `${this.gen.faker.number.int({ min: 1, max: 100 })}`,
880
+ },
881
+ () => JSON.stringify({ data: this.gen.faker.lorem.sentences() }),
882
+ init
883
+ )
884
+ await mock.add({
885
+ match: {
886
+ uri: RouteBuilder.fileMedia(':oid', ':id'),
887
+ methods: ['GET'],
888
+ },
889
+ respond,
475
890
  })
476
891
  },
477
892
 
478
893
  /**
479
894
  * Mocks the `file.readBulk()` method.
480
895
  */
481
- readBulk: (options?: MockResponseOptions): StubReference => {
482
- return this.createStub('file', 'readBulk', () => {
483
- const defaultData: IBulkOperationResult<IFile> = {
484
- items: [this.generateFile(), undefined],
485
- }
486
- if (options?.status !== undefined && options.status !== 200) {
487
- throw new Exception('Mocked error', { status: options.status })
488
- }
489
- return (options?.data ?? defaultData) as unknown
896
+ readBulk: async (init?: MockListResult): Promise<void> => {
897
+ const { mock } = this
898
+ // const respond = init?.response ?? {
899
+ // status: 200,
900
+ // headers: { 'content-type': 'application/json' },
901
+ // body: JSON.stringify({
902
+ // items: this.gen.file.files(init?.size ?? 5),
903
+ // } as IBulkOperationResult<IFile>),
904
+ // }
905
+ const respond = this.createDefaultResponse(
906
+ 200,
907
+ { 'content-type': 'application/json' },
908
+ () => {
909
+ const obj: IBulkOperationResult<IFile> = {
910
+ items: this.gen.file.files(init?.size ?? 5),
911
+ }
912
+ return JSON.stringify(obj)
913
+ },
914
+ init
915
+ )
916
+ await mock.add({
917
+ match: {
918
+ uri: RouteBuilder.filesBatch(':oid'),
919
+ methods: ['POST'],
920
+ },
921
+ respond,
490
922
  })
491
923
  },
492
924
 
493
925
  /**
494
926
  * Mocks the `file.patch()` method.
495
927
  */
496
- patch: (options?: MockResponseOptions): StubReference => {
497
- return this.createStub('file', 'patch', () => {
498
- const defaultData: IFile = this.generateFile()
499
- if (options?.status !== undefined && options.status !== 200) {
500
- throw new Exception('Mocked error', { status: options.status })
501
- }
502
- return (options?.data ?? defaultData) as unknown
928
+ patch: async (init?: MockResult): Promise<void> => {
929
+ const { mock } = this
930
+ // const respond = init?.response ?? {
931
+ // status: 200,
932
+ // headers: { 'content-type': 'application/json' },
933
+ // body: JSON.stringify(this.gen.file.file()),
934
+ // }
935
+ const respond = this.createDefaultResponse(
936
+ 200,
937
+ { 'content-type': 'application/json' },
938
+ () => JSON.stringify(this.gen.file.file()),
939
+ init
940
+ )
941
+ await mock.add({
942
+ match: {
943
+ uri: RouteBuilder.file(':oid', ':id'),
944
+ methods: ['PATCH'],
945
+ },
946
+ respond,
503
947
  })
504
948
  },
505
949
 
506
950
  /**
507
951
  * Mocks the `file.patchMedia()` method.
508
952
  */
509
- patchMedia: (options?: MockResponseOptions): StubReference => {
510
- return this.createStub('file', 'patchMedia', () => {
511
- const defaultData: MediaPatchRevision = this.generateMediaPatchRevision()
512
- if (options?.status !== undefined && options.status !== 200) {
513
- throw new Exception('Mocked error', { status: options.status })
514
- }
515
- return (options?.data ?? defaultData) as unknown
953
+ patchMedia: async (init?: MockResult): Promise<void> => {
954
+ const { mock } = this
955
+ // const respond = init?.response ?? {
956
+ // status: 200,
957
+ // headers: { 'content-type': 'application/json' },
958
+ // body: JSON.stringify(this.gen.patch.mediaPatchRevision()),
959
+ // }
960
+ const respond = this.createDefaultResponse(
961
+ 200,
962
+ { 'content-type': 'application/json' },
963
+ () => JSON.stringify(this.gen.patch.mediaPatchRevision()),
964
+ init
965
+ )
966
+ await mock.add({
967
+ match: {
968
+ uri: RouteBuilder.fileMedia(':oid', ':id'),
969
+ methods: ['PATCH'],
970
+ },
971
+ respond,
516
972
  })
517
973
  },
518
974
 
519
975
  /**
520
976
  * Mocks the `file.delete()` method.
521
977
  */
522
- delete: (options?: MockResponseOptions): StubReference => {
523
- return this.createStub('file', 'delete', () => {
524
- const status = options?.status ?? 204
525
- if (status !== 204) {
526
- throw new Exception('Mocked error', { status })
527
- }
528
- return undefined
978
+ delete: async (init?: MockResult): Promise<void> => {
979
+ const { mock } = this
980
+ // const respond = init?.response ?? {
981
+ // status: 204,
982
+ // }
983
+ const respond = this.createDefaultResponse(204, undefined, undefined, init)
984
+ await mock.add({
985
+ match: {
986
+ uri: RouteBuilder.file(':oid', ':id'),
987
+ methods: ['DELETE'],
988
+ },
989
+ respond,
529
990
  })
530
991
  },
531
992
 
532
993
  /**
533
994
  * Mocks the `file.deleteBulk()` method.
534
995
  */
535
- deleteBulk: (options?: MockResponseOptions): StubReference => {
536
- return this.createStub('file', 'deleteBulk', () => {
537
- const status = options?.status ?? 204
538
- if (status !== 204) {
539
- throw new Exception('Mocked error', { status })
540
- }
541
- return undefined
996
+ deleteBulk: async (init?: MockResult): Promise<void> => {
997
+ const { mock } = this
998
+ // const respond = init?.response ?? {
999
+ // status: 204,
1000
+ // }
1001
+ const respond = this.createDefaultResponse(204, undefined, undefined, init)
1002
+ await mock.add({
1003
+ match: {
1004
+ uri: RouteBuilder.files(':oid'),
1005
+ methods: ['DELETE'],
1006
+ },
1007
+ respond,
542
1008
  })
543
1009
  },
544
1010
 
545
1011
  /**
546
1012
  * Mocks the `file.patchUsers()` method.
547
1013
  */
548
- patchUsers: (options?: MockResponseOptions): StubReference => {
549
- return this.createStub('file', 'patchUsers', () => {
550
- const defaultData: IFile = this.generateFile()
551
- if (options?.status !== undefined && options.status !== 200) {
552
- throw new Exception('Mocked error', { status: options.status })
553
- }
554
- return (options?.data ?? defaultData) as unknown
1014
+ patchUsers: async (init?: MockResult): Promise<void> => {
1015
+ const { mock } = this
1016
+ // const respond = init?.response ?? {
1017
+ // status: 200,
1018
+ // headers: { 'content-type': 'application/json' },
1019
+ // body: JSON.stringify(this.gen.file.file()),
1020
+ // }
1021
+ const respond = this.createDefaultResponse(
1022
+ 200,
1023
+ { 'content-type': 'application/json' },
1024
+ () => JSON.stringify(this.gen.file.file()),
1025
+ init
1026
+ )
1027
+ await mock.add({
1028
+ match: {
1029
+ uri: RouteBuilder.filesAccess(':oid', ':id'),
1030
+ methods: ['PATCH'],
1031
+ },
1032
+ respond,
555
1033
  })
556
1034
  },
557
1035
 
558
1036
  /**
559
1037
  * Mocks the `file.addUser()` method.
560
1038
  */
561
- addUser: (options?: MockResponseOptions): StubReference => {
562
- return this.createStub('file', 'addUser', () => {
563
- const defaultData: IFile = this.generateFile()
564
- if (options?.status !== undefined && options.status !== 200) {
565
- throw new Exception('Mocked error', { status: options.status })
566
- }
567
- return (options?.data ?? defaultData) as unknown
568
- })
1039
+ addUser: async (init?: MockResult): Promise<void> => {
1040
+ await this.file.patchUsers(init)
569
1041
  },
570
1042
 
571
1043
  /**
572
1044
  * Mocks the `file.removeUser()` method.
573
1045
  */
574
- removeUser: (options?: MockResponseOptions): StubReference => {
575
- return this.createStub('file', 'removeUser', () => {
576
- const defaultData: IFile = this.generateFile()
577
- if (options?.status !== undefined && options.status !== 200) {
578
- throw new Exception('Mocked error', { status: options.status })
579
- }
580
- return (options?.data ?? defaultData) as unknown
581
- })
1046
+ removeUser: async (init?: MockResult): Promise<void> => {
1047
+ await this.file.patchUsers(init)
582
1048
  },
583
1049
 
584
1050
  /**
585
1051
  * Mocks the `file.listUsers()` method.
586
1052
  */
587
- listUsers: (options?: MockResponseOptions): StubReference => {
588
- return this.createStub('file', 'listUsers', () => {
589
- const defaultData: ContextListResult<IUser> = {
590
- items: [this.generateUser(), this.generateUser()],
591
- }
592
- if (options?.status !== undefined && options.status !== 200) {
593
- throw new Exception('Mocked error', { status: options.status })
594
- }
595
- return (options?.data ?? defaultData) as unknown
1053
+ listUsers: async (init?: MockListResult): Promise<void> => {
1054
+ const { mock } = this
1055
+ // const respond = init?.response ?? {
1056
+ // status: 200,
1057
+ // headers: { 'content-type': 'application/json' },
1058
+ // body: JSON.stringify({
1059
+ // items: this.gen.user.users(init?.size ?? 5),
1060
+ // cursor: this.createCursorOption(init),
1061
+ // } as ContextListResult<IUser>),
1062
+ // }
1063
+ const respond = this.createDefaultResponse(
1064
+ 200,
1065
+ { 'content-type': 'application/json' },
1066
+ () => {
1067
+ const obj: ContextListResult<IUser> = {
1068
+ items: this.gen.user.users(init?.size ?? 5),
1069
+ cursor: this.createCursorOption(init),
1070
+ }
1071
+ return JSON.stringify(obj)
1072
+ },
1073
+ init
1074
+ )
1075
+ await mock.add({
1076
+ match: {
1077
+ uri: RouteBuilder.fileUsers(':oid', ':id'),
1078
+ methods: ['GET'],
1079
+ },
1080
+ respond,
596
1081
  })
597
1082
  },
598
1083
 
599
1084
  /**
600
1085
  * Mocks the `file.breadcrumbs()` method.
601
1086
  */
602
- breadcrumbs: (options?: MockResponseOptions): StubReference => {
603
- return this.createStub('file', 'breadcrumbs', () => {
604
- const defaultData: ContextListResult<FileBreadcrumb> = {
605
- items: this.generateBreadcrumbs(),
606
- }
607
- if (options?.status !== undefined && options.status !== 200) {
608
- throw new Exception('Mocked error', { status: options.status })
609
- }
610
- return (options?.data ?? defaultData) as unknown
1087
+ breadcrumbs: async (init?: MockListResult): Promise<void> => {
1088
+ const { mock } = this
1089
+ // const respond = init?.response ?? {
1090
+ // status: 200,
1091
+ // headers: { 'content-type': 'application/json' },
1092
+ // body: JSON.stringify({
1093
+ // items: this.gen.file.fileBreadcrumbs(init?.size ?? 5),
1094
+ // cursor: this.createCursorOption(init),
1095
+ // } as ContextListResult<FileBreadcrumb>),
1096
+ // }
1097
+ const respond = this.createDefaultResponse(
1098
+ 200,
1099
+ { 'content-type': 'application/json' },
1100
+ () => {
1101
+ const obj: ContextListResult<FileBreadcrumb> = {
1102
+ items: this.gen.file.fileBreadcrumbs(init?.size ?? 5),
1103
+ cursor: this.createCursorOption(init),
1104
+ }
1105
+ return JSON.stringify(obj)
1106
+ },
1107
+ init
1108
+ )
1109
+ await mock.add({
1110
+ match: {
1111
+ uri: RouteBuilder.fileBreadcrumbs(':oid', ':id'),
1112
+ methods: ['GET'],
1113
+ },
1114
+ respond,
611
1115
  })
612
1116
  },
613
1117
  }
@@ -616,15 +1120,34 @@ export class SdkMock {
616
1120
  * Shared API mocks.
617
1121
  */
618
1122
  shared = {
619
- list: (options?: MockResponseOptions): StubReference => {
620
- return this.createStub('shared', 'list', () => {
621
- const defaultData: ContextListResult<IFile> = {
622
- items: [this.generateFile(), this.generateFile()],
623
- }
624
- if (options?.status !== undefined && options.status !== 200) {
625
- throw new Exception('Mocked error', { status: options.status })
626
- }
627
- return (options?.data ?? defaultData) as unknown
1123
+ list: async (init?: MockListResult): Promise<void> => {
1124
+ const { mock } = this
1125
+ // const respond = init?.response ?? {
1126
+ // status: 200,
1127
+ // headers: { 'content-type': 'application/json' },
1128
+ // body: JSON.stringify({
1129
+ // items: this.gen.file.files(init?.size ?? 5),
1130
+ // cursor: this.createCursorOption(init),
1131
+ // } as ContextListResult<IFile>),
1132
+ // }
1133
+ const respond = this.createDefaultResponse(
1134
+ 200,
1135
+ { 'content-type': 'application/json' },
1136
+ () => {
1137
+ const obj: ContextListResult<IFile> = {
1138
+ items: this.gen.file.files(init?.size ?? 5),
1139
+ cursor: this.createCursorOption(init),
1140
+ }
1141
+ return JSON.stringify(obj)
1142
+ },
1143
+ init
1144
+ )
1145
+ await mock.add({
1146
+ match: {
1147
+ uri: RouteBuilder.shared(':oid'),
1148
+ methods: ['GET'],
1149
+ },
1150
+ respond,
628
1151
  })
629
1152
  },
630
1153
  }
@@ -633,284 +1156,77 @@ export class SdkMock {
633
1156
  * Trash API mocks.
634
1157
  */
635
1158
  trash = {
636
- list: (options?: MockResponseOptions): StubReference => {
637
- return this.createStub('trash', 'list', () => {
638
- const defaultData: ContextListResult<TrashEntry> = {
639
- items: [this.generateTrashEntry(), this.generateTrashEntry()],
640
- }
641
- if (options?.status !== undefined && options.status !== 200) {
642
- throw new Exception('Mocked error', { status: options.status })
643
- }
644
- return (options?.data ?? defaultData) as unknown
1159
+ list: async (init?: MockListResult): Promise<void> => {
1160
+ const { mock } = this
1161
+ // const respond = init?.response ?? {
1162
+ // status: 200,
1163
+ // headers: { 'content-type': 'application/json' },
1164
+ // body: JSON.stringify({
1165
+ // items: this.gen.trash.trashEntries(init?.size ?? 5),
1166
+ // cursor: this.createCursorOption(init),
1167
+ // } as ContextListResult<TrashEntry>),
1168
+ // }
1169
+ const respond = this.createDefaultResponse(
1170
+ 200,
1171
+ { 'content-type': 'application/json' },
1172
+ () => {
1173
+ const obj: ContextListResult<TrashEntry> = {
1174
+ items: this.gen.trash.trashEntries(init?.size ?? 5),
1175
+ cursor: this.createCursorOption(init),
1176
+ }
1177
+ return JSON.stringify(obj)
1178
+ },
1179
+ init
1180
+ )
1181
+ await mock.add({
1182
+ match: {
1183
+ uri: RouteBuilder.trash(':oid'),
1184
+ methods: ['GET'],
1185
+ },
1186
+ respond,
645
1187
  })
646
1188
  },
647
- delete: (options?: MockResponseOptions): StubReference => {
648
- return this.createStub('trash', 'delete', () => {
649
- const status = options?.status ?? 204
650
- if (status !== 204) {
651
- throw new Exception('Mocked error', { status })
652
- }
653
- return undefined
1189
+ delete: async (init?: MockResult): Promise<void> => {
1190
+ const { mock } = this
1191
+ // const respond = init?.response ?? {
1192
+ // status: 204,
1193
+ // }
1194
+ const respond = this.createDefaultResponse(204, undefined, undefined, init)
1195
+ await mock.add({
1196
+ match: {
1197
+ uri: RouteBuilder.trashBatchDelete(':oid'),
1198
+ methods: ['DELETE'],
1199
+ },
1200
+ respond,
654
1201
  })
655
1202
  },
656
- restore: (options?: MockResponseOptions): StubReference => {
657
- return this.createStub('trash', 'restore', () => {
658
- const status = options?.status ?? 204
659
- if (status !== 204) {
660
- throw new Exception('Mocked error', { status })
661
- }
662
- return undefined
1203
+ restore: async (init?: MockResult): Promise<void> => {
1204
+ const { mock } = this
1205
+ // const respond = init?.response ?? {
1206
+ // status: 204,
1207
+ // }
1208
+ const respond = this.createDefaultResponse(204, undefined, undefined, init)
1209
+ await mock.add({
1210
+ match: {
1211
+ uri: RouteBuilder.trashBatchRestore(':oid'),
1212
+ methods: ['POST'],
1213
+ },
1214
+ respond,
663
1215
  })
664
1216
  },
665
- empty: (options?: MockResponseOptions): StubReference => {
666
- return this.createStub('trash', 'empty', () => {
667
- const status = options?.status ?? 204
668
- if (status !== 204) {
669
- throw new Exception('Mocked error', { status })
670
- }
671
- return undefined
1217
+ empty: async (init?: MockResult): Promise<void> => {
1218
+ const { mock } = this
1219
+ // const respond = init?.response ?? {
1220
+ // status: 204,
1221
+ // }
1222
+ const respond = this.createDefaultResponse(204, undefined, undefined, init)
1223
+ await mock.add({
1224
+ match: {
1225
+ uri: RouteBuilder.trashEmpty(':oid'),
1226
+ methods: ['DELETE'],
1227
+ },
1228
+ respond,
672
1229
  })
673
1230
  },
674
1231
  }
675
-
676
- /**
677
- * Restores all stubs created by this mocker.
678
- */
679
- restore(): void {
680
- this.stubs.forEach((stub) => stub.restore())
681
- this.stubs = []
682
- }
683
-
684
- /**
685
- * Creates a stub for a specific SDK method.
686
- * @param api The API name (e.g., 'organizations', 'groups', 'user', 'auth').
687
- * @param method The method name to stub.
688
- * @param implementation The stub implementation that returns the mocked data.
689
- * @returns A stub reference.
690
- */
691
- private createStub(
692
- api:
693
- | 'organizations'
694
- | 'groups'
695
- | 'user'
696
- | 'auth'
697
- | 'file'
698
- | 'shared'
699
- | 'trash'
700
- | 'organizations.invitations'
701
- | 'organizations.users',
702
- method: string,
703
- implementation: () => unknown
704
- ): StubReference {
705
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
706
- let target: any = this.sdk
707
- const parts = api.split('.')
708
- for (const part of parts) {
709
- target = target[part]
710
- if (!target) {
711
- throw new Error(`API '${api}' not found in SDK`)
712
- }
713
- }
714
-
715
- const original = target[method]
716
- if (typeof original !== 'function') {
717
- throw new Error(`Method '${method}' not found in ${api} API`)
718
- }
719
-
720
- // Create stub using sinon
721
- const stub = sinon.stub(target, method).callsFake(async () => implementation())
722
-
723
- const stubRef: StubReference = {
724
- restore: () => {
725
- if (stub) {
726
- stub.restore()
727
- }
728
- const index = this.stubs.indexOf(stubRef)
729
- if (index > -1) {
730
- this.stubs.splice(index, 1)
731
- }
732
- },
733
- }
734
-
735
- this.stubs.push(stubRef)
736
- return stubRef
737
- }
738
-
739
- /**
740
- * Generates a random organization object.
741
- */
742
- private generateOrganization(): IOrganization {
743
- return {
744
- kind: OrganizationKind,
745
- key: nanoid(),
746
- name: `Organization ${this.randomString()}`,
747
- createdBy: nanoid(),
748
- createdDate: Date.now() - Math.random() * 1000 * 60 * 60 * 24 * 30,
749
- grantType: this.randomChoice(['owner', 'manager', 'editor', 'viewer'] as const),
750
- }
751
- }
752
-
753
- /**
754
- * Generates a random group object.
755
- */
756
- private generateGroup(): GroupSchema {
757
- return {
758
- kind: GroupKind,
759
- key: nanoid(),
760
- name: `Group ${this.randomString()}`,
761
- description: `Description for ${this.randomString()}`,
762
- owner: nanoid(),
763
- oid: nanoid(),
764
- users: [],
765
- createdAt: Date.now() - Math.random() * 1000 * 60 * 60 * 24 * 30,
766
- updatedAt: Date.now() - Math.random() * 1000 * 60 * 60 * 24 * 7,
767
- icon: `https://example.com/icon-${nanoid()}.png`,
768
- color: this.randomColor(),
769
- }
770
- }
771
-
772
- /**
773
- * Generates a random user object.
774
- */
775
- private generateUser(): IUser {
776
- const firstName = this.randomString()
777
- const lastName = this.randomString()
778
- return {
779
- kind: UserKind,
780
- key: nanoid(),
781
- name: `${firstName} ${lastName}`,
782
- email: [
783
- {
784
- email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`,
785
- verified: true,
786
- },
787
- ],
788
- status: 'active',
789
- created: Date.now() - Math.random() * 1000 * 60 * 60 * 24 * 365,
790
- updated: Date.now() - Math.random() * 1000 * 60 * 60 * 24 * 7,
791
- }
792
- }
793
-
794
- /**
795
- * Generates a random file meta object.
796
- */
797
- private generateFile(): IFile {
798
- const kind = this.randomChoice([ProjectKind, DomainFileKind, CertificateFileKind, FolderKind] as const)
799
- const name = `File ${this.randomString()}`
800
- return File.createSchema({ kind, info: { name } })
801
- }
802
-
803
- /**
804
- * Generates a random folder meta object.
805
- */
806
- private generateFolder(): IFolder {
807
- const file = File.createSchema({ kind: FolderKind, info: { name: `Folder ${this.randomString()}` } }) as IFolder
808
- return file
809
- }
810
-
811
- /**
812
- * Generates a random media patch revision object.
813
- */
814
- private generateMediaPatchRevision(): MediaPatchRevision {
815
- const version = Math.floor(Math.random() * 10) + 1
816
- return {
817
- id: nanoid(),
818
- timestamp: Date.now(),
819
- patch: [],
820
- version,
821
- revert: [],
822
- newVersion: version + 1,
823
- }
824
- }
825
-
826
- /**
827
- * Generates a random breadcrumbs list.
828
- */
829
- private generateBreadcrumbs(): FileBreadcrumb[] {
830
- const depth = 2 + Math.floor(Math.random() * 2) // 2-3
831
- const items: FileBreadcrumb[] = []
832
- for (let i = 0; i < depth; i += 1) {
833
- items.push({ key: nanoid(), kind: i === depth - 1 ? ProjectKind : FolderKind, name: this.randomString() })
834
- }
835
- return items
836
- }
837
-
838
- /**
839
- * Generates a random invitation object.
840
- */
841
- private generateInvitation(): InvitationSchema {
842
- const firstName = this.randomString()
843
- const lastName = this.randomString()
844
- const now = Date.now()
845
- return {
846
- kind: InvitationKind,
847
- key: nanoid(),
848
- uid: nanoid(),
849
- oid: nanoid(),
850
- email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`,
851
- name: `${firstName} ${lastName}`,
852
- token: nanoid(),
853
- expiresAt: now + 7 * 24 * 60 * 60 * 1000,
854
- status: 'pending',
855
- grantType: this.randomChoice(['owner', 'manager', 'editor', 'viewer'] as const),
856
- createdAt: now - Math.random() * 1000 * 60 * 60 * 24,
857
- updatedAt: now - Math.random() * 1000 * 60 * 60,
858
- resent: 0,
859
- lastSentAt: now - Math.random() * 1000 * 60 * 60,
860
- }
861
- }
862
-
863
- /**
864
- * Generates a random trash entry.
865
- */
866
- private generateTrashEntry(): TrashEntry {
867
- return {
868
- key: nanoid(),
869
- refKey: nanoid(),
870
- kind: this.randomChoice([ProjectKind, DomainFileKind, CertificateFileKind, FolderKind] as const),
871
- name: `Deleted ${this.randomString()}`,
872
- info: { byMe: false, time: Date.now() - Math.floor(Math.random() * 1000000), user: nanoid(), name: 'User' },
873
- capabilities: { canDelete: true, canRestore: true },
874
- }
875
- }
876
-
877
- /**
878
- * Generates a random string.
879
- */
880
- private randomString(): string {
881
- const words = [
882
- 'Alpha',
883
- 'Beta',
884
- 'Gamma',
885
- 'Delta',
886
- 'Epsilon',
887
- 'Zeta',
888
- 'Theta',
889
- 'Lambda',
890
- 'Sigma',
891
- 'Omega',
892
- 'Phoenix',
893
- 'Dragon',
894
- 'Tiger',
895
- 'Eagle',
896
- 'Falcon',
897
- ]
898
- return words[Math.floor(Math.random() * words.length)]
899
- }
900
-
901
- /**
902
- * Returns a random choice from an array.
903
- */
904
- private randomChoice<T>(choices: readonly T[]): T {
905
- return choices[Math.floor(Math.random() * choices.length)]
906
- }
907
-
908
- /**
909
- * Generates a random hex color.
910
- */
911
- private randomColor(): string {
912
- return `#${Math.floor(Math.random() * 16777215)
913
- .toString(16)
914
- .padStart(6, '0')}`
915
- }
916
1232
  }