@ikatec/digisac-api-sdk 2.0.0 → 2.1.1
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/dist/apis/campaigns/types.d.ts +22 -5
- package/dist/apis/campaigns/types.d.ts.map +1 -1
- package/dist/apis/whatsappBusinessTemplates/types.d.ts +20 -3
- package/dist/apis/whatsappBusinessTemplates/types.d.ts.map +1 -1
- package/dist/core/BaseCrudApi.cjs.map +1 -1
- package/dist/core/BaseCrudApi.d.ts +2 -2
- package/dist/core/BaseCrudApi.d.ts.map +1 -1
- package/dist/core/BaseCrudApi.mjs.map +1 -1
- package/package.json +1 -1
- package/src/apis/authHistory/AuthHistoryApi.test.ts +110 -0
- package/src/apis/campaigns/CampaignsApi.test.ts +344 -0
- package/src/apis/campaigns/types.ts +26 -5
- package/src/apis/clientFeedback/ClientFeedbackApi.test.ts +76 -0
- package/src/apis/contacts/ContactsApi.test.ts +364 -0
- package/src/apis/me/MeApi.test.ts +372 -0
- package/src/apis/messages/MessagesApi.test.ts +460 -0
- package/src/apis/serviceAccessManagement/ServiceAccessManagementApi.test.ts +89 -0
- package/src/apis/stickerUsers/StickerUsersApi.test.ts +84 -0
- package/src/apis/terms/TermsApi.test.ts +196 -0
- package/src/apis/transcripts/TranscriptsApi.test.ts +63 -0
- package/src/apis/whatsappBusinessTemplates/types.ts +24 -3
- package/src/core/BaseCrudApi.ts +2 -2
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { ContactsApi } from './ContactsApi'
|
|
3
|
+
import type { ApiClient } from '../../core/ApiClient'
|
|
4
|
+
import type {
|
|
5
|
+
Contact,
|
|
6
|
+
CreateContactPayload,
|
|
7
|
+
ExportTemplatePayload,
|
|
8
|
+
CountContactsQuery,
|
|
9
|
+
ExistsContactsParams,
|
|
10
|
+
CountMediaResult,
|
|
11
|
+
} from './types'
|
|
12
|
+
import type { Paginated } from '../../core/types'
|
|
13
|
+
|
|
14
|
+
// ── Mock client factory ──────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
function createMockClient(): ApiClient {
|
|
17
|
+
return {
|
|
18
|
+
setAccessToken: vi.fn().mockReturnThis(),
|
|
19
|
+
request: vi.fn(),
|
|
20
|
+
get: vi.fn(),
|
|
21
|
+
post: vi.fn(),
|
|
22
|
+
put: vi.fn(),
|
|
23
|
+
patch: vi.fn(),
|
|
24
|
+
delete: vi.fn(),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ── Fixtures ─────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
const contact: Contact = {
|
|
31
|
+
id: 'cnt-1',
|
|
32
|
+
idFromService: null,
|
|
33
|
+
name: 'Alice',
|
|
34
|
+
internalName: null,
|
|
35
|
+
alternativeName: null,
|
|
36
|
+
isGroup: false,
|
|
37
|
+
isBroadcast: false,
|
|
38
|
+
isMe: false,
|
|
39
|
+
isMyContact: true,
|
|
40
|
+
hadChat: true,
|
|
41
|
+
visible: true,
|
|
42
|
+
status: 'online',
|
|
43
|
+
isSilenced: false,
|
|
44
|
+
data: {},
|
|
45
|
+
note: null,
|
|
46
|
+
unread: 0,
|
|
47
|
+
lastMessageAt: null,
|
|
48
|
+
unsubscribed: false,
|
|
49
|
+
lastContactMessageAt: null,
|
|
50
|
+
acceptedTermAt: null,
|
|
51
|
+
hsmExpirationTime: null,
|
|
52
|
+
block: null,
|
|
53
|
+
dataBlock: null,
|
|
54
|
+
origin: null,
|
|
55
|
+
archivedAt: null,
|
|
56
|
+
accountId: 'acc-1',
|
|
57
|
+
serviceId: 'svc-1',
|
|
58
|
+
defaultDepartmentId: null,
|
|
59
|
+
defaultUserId: null,
|
|
60
|
+
currentTicketId: null,
|
|
61
|
+
lastMessageId: null,
|
|
62
|
+
personId: null,
|
|
63
|
+
contactBlockListControlId: null,
|
|
64
|
+
createdAt: '2024-01-01T00:00:00Z',
|
|
65
|
+
updatedAt: '2024-01-01T00:00:00Z',
|
|
66
|
+
deletedAt: null,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const paginated: Paginated<Contact> = {
|
|
70
|
+
data: [contact],
|
|
71
|
+
total: 1,
|
|
72
|
+
limit: 10,
|
|
73
|
+
skip: 0,
|
|
74
|
+
currentPage: 1,
|
|
75
|
+
lastPage: 1,
|
|
76
|
+
from: 1,
|
|
77
|
+
to: 1,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Tests ────────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
describe('ContactsApi', () => {
|
|
83
|
+
let client: ReturnType<typeof createMockClient>
|
|
84
|
+
let api: ContactsApi
|
|
85
|
+
|
|
86
|
+
beforeEach(() => {
|
|
87
|
+
client = createMockClient()
|
|
88
|
+
api = new ContactsApi(client)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// ── getMany ──────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
describe('getMany', () => {
|
|
94
|
+
it('calls client.get with /contacts when no query is provided', async () => {
|
|
95
|
+
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
96
|
+
const result = await api.getMany()
|
|
97
|
+
expect(client.get).toHaveBeenCalledWith('/contacts', undefined)
|
|
98
|
+
expect(result).toEqual(paginated)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('serializes query parameters', async () => {
|
|
102
|
+
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
103
|
+
await api.getMany({ page: 2, perPage: 5 })
|
|
104
|
+
const url = vi.mocked(client.get).mock.calls[0][0] as string
|
|
105
|
+
expect(url).toContain('/contacts?')
|
|
106
|
+
expect(url).toContain('page=2')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('forwards custom headers', async () => {
|
|
110
|
+
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
111
|
+
const headers = { 'X-Custom': 'value' }
|
|
112
|
+
await api.getMany(undefined, headers)
|
|
113
|
+
expect(client.get).toHaveBeenCalledWith('/contacts', headers)
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// ── getById ──────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
describe('getById', () => {
|
|
120
|
+
it('calls client.get with /contacts/:id', async () => {
|
|
121
|
+
vi.mocked(client.get).mockResolvedValue(contact)
|
|
122
|
+
const result = await api.getById('cnt-1')
|
|
123
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/cnt-1', undefined)
|
|
124
|
+
expect(result).toEqual(contact)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('forwards custom headers', async () => {
|
|
128
|
+
vi.mocked(client.get).mockResolvedValue(contact)
|
|
129
|
+
const headers = { 'X-Tenant': 'abc' }
|
|
130
|
+
await api.getById('cnt-1', undefined, headers)
|
|
131
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/cnt-1', headers)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// ── create ───────────────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
describe('create', () => {
|
|
138
|
+
it('calls client.post with /contacts and body', async () => {
|
|
139
|
+
vi.mocked(client.post).mockResolvedValue(contact)
|
|
140
|
+
const body: CreateContactPayload = { serviceId: 'svc-1', name: 'Alice' }
|
|
141
|
+
const result = await api.create(body)
|
|
142
|
+
expect(client.post).toHaveBeenCalledWith('/contacts', body, undefined)
|
|
143
|
+
expect(result).toEqual(contact)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('forwards custom headers', async () => {
|
|
147
|
+
vi.mocked(client.post).mockResolvedValue(contact)
|
|
148
|
+
const headers = { 'X-Req': 'r-1' }
|
|
149
|
+
await api.create({ serviceId: 'svc-1' }, headers)
|
|
150
|
+
expect(client.post).toHaveBeenCalledWith('/contacts', { serviceId: 'svc-1' }, headers)
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
// ── updateById ───────────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
describe('updateById', () => {
|
|
157
|
+
it('calls client.put with /contacts/:id and body', async () => {
|
|
158
|
+
vi.mocked(client.put).mockResolvedValue(contact)
|
|
159
|
+
const result = await api.updateById('cnt-1', { name: 'Alice Updated' })
|
|
160
|
+
expect(client.put).toHaveBeenCalledWith(
|
|
161
|
+
'/contacts/cnt-1',
|
|
162
|
+
{ name: 'Alice Updated' },
|
|
163
|
+
undefined,
|
|
164
|
+
)
|
|
165
|
+
expect(result).toEqual(contact)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('forwards custom headers', async () => {
|
|
169
|
+
vi.mocked(client.put).mockResolvedValue(contact)
|
|
170
|
+
const headers = { 'If-Match': 'etag' }
|
|
171
|
+
await api.updateById('cnt-1', { name: 'x' }, headers)
|
|
172
|
+
expect(client.put).toHaveBeenCalledWith('/contacts/cnt-1', { name: 'x' }, headers)
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
// ── deleteById ───────────────────────────────────────────────────
|
|
177
|
+
|
|
178
|
+
describe('deleteById', () => {
|
|
179
|
+
it('calls client.delete with /contacts/:id', async () => {
|
|
180
|
+
vi.mocked(client.delete).mockResolvedValue(contact)
|
|
181
|
+
const result = await api.deleteById('cnt-1')
|
|
182
|
+
expect(client.delete).toHaveBeenCalledWith('/contacts/cnt-1', undefined)
|
|
183
|
+
expect(result).toEqual(contact)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('forwards custom headers', async () => {
|
|
187
|
+
vi.mocked(client.delete).mockResolvedValue(contact)
|
|
188
|
+
const headers = { 'X-Reason': 'cleanup' }
|
|
189
|
+
await api.deleteById('cnt-1', headers)
|
|
190
|
+
expect(client.delete).toHaveBeenCalledWith('/contacts/cnt-1', headers)
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
// ── exportTemplate ───────────────────────────────────────────────
|
|
195
|
+
|
|
196
|
+
describe('exportTemplate', () => {
|
|
197
|
+
it('calls client.post with /contacts/export-template and body', async () => {
|
|
198
|
+
vi.mocked(client.post).mockResolvedValue({ ok: true })
|
|
199
|
+
const body: ExportTemplatePayload = { serviceType: 'whatsapp', type: 'csv' }
|
|
200
|
+
const result = await api.exportTemplate(body)
|
|
201
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/export-template', body, undefined)
|
|
202
|
+
expect(result).toEqual({ ok: true })
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('forwards custom headers', async () => {
|
|
206
|
+
vi.mocked(client.post).mockResolvedValue(null)
|
|
207
|
+
const headers = { 'X-Custom': 'h' }
|
|
208
|
+
const body: ExportTemplatePayload = { serviceType: 'webchat', type: 'csv' }
|
|
209
|
+
await api.exportTemplate(body, headers)
|
|
210
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/export-template', body, headers)
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
// ── count ────────────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
describe('count', () => {
|
|
217
|
+
it('calls client.get with /contacts/count when no query is provided', async () => {
|
|
218
|
+
vi.mocked(client.get).mockResolvedValue({ count: 42 })
|
|
219
|
+
const result = await api.count()
|
|
220
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/count', undefined)
|
|
221
|
+
expect(result).toEqual({ count: 42 })
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('serializes query parameters', async () => {
|
|
225
|
+
vi.mocked(client.get).mockResolvedValue({ count: 10 })
|
|
226
|
+
const query: CountContactsQuery = { where: { name: 'Alice' } }
|
|
227
|
+
await api.count(query)
|
|
228
|
+
const url = vi.mocked(client.get).mock.calls[0][0] as string
|
|
229
|
+
expect(url).toContain('/contacts/count?')
|
|
230
|
+
expect(url).toContain('where')
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('forwards custom headers', async () => {
|
|
234
|
+
vi.mocked(client.get).mockResolvedValue({ count: 0 })
|
|
235
|
+
const headers = { 'X-Custom': 'h' }
|
|
236
|
+
await api.count(undefined, headers)
|
|
237
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/count', headers)
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
// ── countPost ────────────────────────────────────────────────────
|
|
242
|
+
|
|
243
|
+
describe('countPost', () => {
|
|
244
|
+
it('calls client.post with /contacts/count and body', async () => {
|
|
245
|
+
vi.mocked(client.post).mockResolvedValue({ count: 5 })
|
|
246
|
+
const body: CountContactsQuery = { where: { name: 'Alice' } }
|
|
247
|
+
const result = await api.countPost(body)
|
|
248
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/count', body, undefined)
|
|
249
|
+
expect(result).toEqual({ count: 5 })
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('forwards custom headers', async () => {
|
|
253
|
+
vi.mocked(client.post).mockResolvedValue({ count: 0 })
|
|
254
|
+
const headers = { 'X-Custom': 'h' }
|
|
255
|
+
await api.countPost({}, headers)
|
|
256
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/count', {}, headers)
|
|
257
|
+
})
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
// ── forward ──────────────────────────────────────────────────────
|
|
261
|
+
|
|
262
|
+
describe('forward', () => {
|
|
263
|
+
it('calls client.get with /contacts/forward when no query is provided', async () => {
|
|
264
|
+
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
265
|
+
const result = await api.forward()
|
|
266
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/forward', undefined)
|
|
267
|
+
expect(result).toEqual(paginated)
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
it('serializes query parameters', async () => {
|
|
271
|
+
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
272
|
+
await api.forward({ page: 1, perPage: 10 })
|
|
273
|
+
const url = vi.mocked(client.get).mock.calls[0][0] as string
|
|
274
|
+
expect(url).toContain('/contacts/forward?')
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('forwards custom headers', async () => {
|
|
278
|
+
vi.mocked(client.get).mockResolvedValue(paginated)
|
|
279
|
+
const headers = { 'X-Custom': 'h' }
|
|
280
|
+
await api.forward(undefined, headers)
|
|
281
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/forward', headers)
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
// ── exists ───────────────────────────────────────────────────────
|
|
286
|
+
|
|
287
|
+
describe('exists', () => {
|
|
288
|
+
it('calls client.get with /contacts/exists and query params', async () => {
|
|
289
|
+
vi.mocked(client.get).mockResolvedValue({ '1234567890': true })
|
|
290
|
+
const params: ExistsContactsParams = { serviceId: 'svc-1', numbers: ['1234567890'] }
|
|
291
|
+
const result = await api.exists(params)
|
|
292
|
+
const url = vi.mocked(client.get).mock.calls[0][0] as string
|
|
293
|
+
expect(url).toContain('/contacts/exists?')
|
|
294
|
+
expect(url).toContain('serviceId=svc-1')
|
|
295
|
+
expect(result).toEqual({ '1234567890': true })
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
it('forwards custom headers', async () => {
|
|
299
|
+
vi.mocked(client.get).mockResolvedValue({})
|
|
300
|
+
const headers = { 'X-Custom': 'h' }
|
|
301
|
+
await api.exists({ serviceId: 'svc-1', numbers: [] }, headers)
|
|
302
|
+
expect(vi.mocked(client.get).mock.calls[0][1]).toEqual(headers)
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
// ── countMedia ───────────────────────────────────────────────────
|
|
307
|
+
|
|
308
|
+
describe('countMedia', () => {
|
|
309
|
+
it('calls client.get with /contacts/:id/media/count', async () => {
|
|
310
|
+
const mediaResult: CountMediaResult = { image: 5, video: 2 }
|
|
311
|
+
vi.mocked(client.get).mockResolvedValue(mediaResult)
|
|
312
|
+
const result = await api.countMedia('cnt-1')
|
|
313
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/cnt-1/media/count', undefined)
|
|
314
|
+
expect(result).toEqual(mediaResult)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('forwards custom headers', async () => {
|
|
318
|
+
vi.mocked(client.get).mockResolvedValue({})
|
|
319
|
+
const headers = { 'X-Custom': 'h' }
|
|
320
|
+
await api.countMedia('cnt-1', headers)
|
|
321
|
+
expect(client.get).toHaveBeenCalledWith('/contacts/cnt-1/media/count', headers)
|
|
322
|
+
})
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
// ── list ─────────────────────────────────────────────────────────
|
|
326
|
+
|
|
327
|
+
describe('list', () => {
|
|
328
|
+
it('calls client.post with /contacts/list and body', async () => {
|
|
329
|
+
vi.mocked(client.post).mockResolvedValue(paginated)
|
|
330
|
+
const body = { where: { name: 'Alice' } }
|
|
331
|
+
const result = await api.list(body)
|
|
332
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/list', body, undefined)
|
|
333
|
+
expect(result).toEqual(paginated)
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
it('forwards custom headers', async () => {
|
|
337
|
+
vi.mocked(client.post).mockResolvedValue(paginated)
|
|
338
|
+
const headers = { 'X-Custom': 'h' }
|
|
339
|
+
await api.list({}, headers)
|
|
340
|
+
expect(client.post).toHaveBeenCalledWith('/contacts/list', {}, headers)
|
|
341
|
+
})
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
// ── Error propagation ────────────────────────────────────────────
|
|
345
|
+
|
|
346
|
+
describe('error propagation', () => {
|
|
347
|
+
it('propagates errors from getMany', async () => {
|
|
348
|
+
vi.mocked(client.get).mockRejectedValue(new Error('Network error'))
|
|
349
|
+
await expect(api.getMany()).rejects.toThrow('Network error')
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
it('propagates errors from count', async () => {
|
|
353
|
+
vi.mocked(client.get).mockRejectedValue(new Error('Forbidden'))
|
|
354
|
+
await expect(api.count()).rejects.toThrow('Forbidden')
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('propagates errors from exportTemplate', async () => {
|
|
358
|
+
vi.mocked(client.post).mockRejectedValue(new Error('Bad request'))
|
|
359
|
+
await expect(api.exportTemplate({ serviceType: 'whatsapp', type: 'csv' })).rejects.toThrow(
|
|
360
|
+
'Bad request',
|
|
361
|
+
)
|
|
362
|
+
})
|
|
363
|
+
})
|
|
364
|
+
})
|