@app-connect/core 1.7.8 → 1.7.10
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/handlers/auth.js +10 -4
- package/handlers/contact.js +42 -9
- package/handlers/log.js +4 -4
- package/index.js +101 -79
- package/lib/oauth.js +0 -2
- package/models/accountDataModel.js +34 -0
- package/package.json +70 -69
- package/releaseNotes.json +24 -0
- package/test/connector/registry.test.js +145 -0
- package/test/handlers/admin.test.js +583 -0
- package/test/handlers/auth.test.js +355 -0
- package/test/handlers/contact.test.js +852 -0
- package/test/handlers/log.test.js +868 -0
- package/test/lib/callLogComposer.test.js +1231 -0
- package/test/lib/debugTracer.test.js +328 -0
- package/test/lib/oauth.test.js +359 -0
- package/test/lib/ringcentral.test.js +473 -0
- package/test/lib/util.test.js +282 -0
- package/test/models/accountDataModel.test.js +98 -0
- package/test/models/dynamo/connectorSchema.test.js +189 -0
- package/test/models/models.test.js +539 -0
- package/test/setup.js +176 -176
|
@@ -0,0 +1,1231 @@
|
|
|
1
|
+
const {
|
|
2
|
+
composeCallLog,
|
|
3
|
+
upsertCallAgentNote,
|
|
4
|
+
upsertCallSessionId,
|
|
5
|
+
upsertRingCentralUserName,
|
|
6
|
+
upsertRingCentralNumberAndExtension,
|
|
7
|
+
upsertCallSubject,
|
|
8
|
+
upsertContactPhoneNumber,
|
|
9
|
+
upsertCallDateTime,
|
|
10
|
+
upsertCallDuration,
|
|
11
|
+
upsertCallResult,
|
|
12
|
+
upsertCallRecording,
|
|
13
|
+
upsertAiNote,
|
|
14
|
+
upsertTranscript,
|
|
15
|
+
upsertLegs,
|
|
16
|
+
upsertRingSenseTranscript,
|
|
17
|
+
upsertRingSenseSummary,
|
|
18
|
+
upsertRingSenseAIScore,
|
|
19
|
+
upsertRingSenseBulletedSummary,
|
|
20
|
+
upsertRingSenseLink,
|
|
21
|
+
} = require('../../lib/callLogComposer');
|
|
22
|
+
const { LOG_DETAILS_FORMAT_TYPE } = require('../../lib/constants');
|
|
23
|
+
|
|
24
|
+
describe('callLogComposer', () => {
|
|
25
|
+
describe('composeCallLog', () => {
|
|
26
|
+
const baseParams = {
|
|
27
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
28
|
+
existingBody: '',
|
|
29
|
+
callLog: {
|
|
30
|
+
sessionId: 'session-123',
|
|
31
|
+
direction: 'Outbound',
|
|
32
|
+
startTime: '2024-01-15T10:30:00Z',
|
|
33
|
+
duration: 120,
|
|
34
|
+
result: 'Completed',
|
|
35
|
+
from: { phoneNumber: '+1234567890', name: 'John Doe' },
|
|
36
|
+
to: { phoneNumber: '+0987654321', name: 'Jane Smith' }
|
|
37
|
+
},
|
|
38
|
+
contactInfo: { phoneNumber: '+0987654321' },
|
|
39
|
+
user: { userSettings: {}, timezoneOffset: '+00:00' },
|
|
40
|
+
note: 'Test note',
|
|
41
|
+
subject: 'Test Call',
|
|
42
|
+
startTime: '2024-01-15T10:30:00Z',
|
|
43
|
+
duration: 120,
|
|
44
|
+
result: 'Completed'
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
test('should compose call log with default settings (plain text)', async () => {
|
|
48
|
+
const result = await composeCallLog(baseParams);
|
|
49
|
+
|
|
50
|
+
expect(result).toContain('- Note: Test note');
|
|
51
|
+
expect(result).toContain('- Summary: Test Call');
|
|
52
|
+
expect(result).toContain('- Duration:');
|
|
53
|
+
expect(result).toContain('- Result: Completed');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('should compose call log in HTML format', async () => {
|
|
57
|
+
const result = await composeCallLog({
|
|
58
|
+
...baseParams,
|
|
59
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
expect(result).toContain('<b>Agent notes</b>');
|
|
63
|
+
expect(result).toContain('<b>Summary</b>');
|
|
64
|
+
expect(result).toContain('<b>Duration</b>');
|
|
65
|
+
expect(result).toContain('<b>Result</b>');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should compose call log in Markdown format', async () => {
|
|
69
|
+
const result = await composeCallLog({
|
|
70
|
+
...baseParams,
|
|
71
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(result).toContain('## Agent notes');
|
|
75
|
+
expect(result).toContain('**Summary**:');
|
|
76
|
+
expect(result).toContain('**Duration**:');
|
|
77
|
+
expect(result).toContain('**Result**:');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('should respect user settings to disable fields', async () => {
|
|
81
|
+
const result = await composeCallLog({
|
|
82
|
+
...baseParams,
|
|
83
|
+
user: {
|
|
84
|
+
userSettings: {
|
|
85
|
+
addCallLogNote: { value: false },
|
|
86
|
+
addCallLogSubject: { value: false },
|
|
87
|
+
addCallLogDuration: { value: false }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(result).not.toContain('Note:');
|
|
93
|
+
expect(result).not.toContain('Summary:');
|
|
94
|
+
expect(result).not.toContain('Duration:');
|
|
95
|
+
expect(result).toContain('Result: Completed');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('should add session ID when enabled', async () => {
|
|
99
|
+
const result = await composeCallLog({
|
|
100
|
+
...baseParams,
|
|
101
|
+
user: {
|
|
102
|
+
userSettings: { addCallSessionId: { value: true } },
|
|
103
|
+
timezoneOffset: '+00:00'
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
expect(result).toContain('Session Id: session-123');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('should add recording link when provided', async () => {
|
|
111
|
+
const result = await composeCallLog({
|
|
112
|
+
...baseParams,
|
|
113
|
+
recordingLink: 'https://recording.example.com/123'
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
expect(result).toContain('Call recording link: https://recording.example.com/123');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('should add AI note when provided', async () => {
|
|
120
|
+
const result = await composeCallLog({
|
|
121
|
+
...baseParams,
|
|
122
|
+
aiNote: 'AI generated summary of the call'
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(result).toContain('AI Note');
|
|
126
|
+
expect(result).toContain('AI generated summary of the call');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should add transcript when provided', async () => {
|
|
130
|
+
const result = await composeCallLog({
|
|
131
|
+
...baseParams,
|
|
132
|
+
transcript: 'Hello, this is a test transcript.'
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(result).toContain('Transcript');
|
|
136
|
+
expect(result).toContain('Hello, this is a test transcript.');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('should add RingSense data when provided', async () => {
|
|
140
|
+
const result = await composeCallLog({
|
|
141
|
+
...baseParams,
|
|
142
|
+
ringSenseTranscript: 'RS Transcript',
|
|
143
|
+
ringSenseSummary: 'RS Summary',
|
|
144
|
+
ringSenseAIScore: '85',
|
|
145
|
+
ringSenseBulletedSummary: '- Point 1\n- Point 2',
|
|
146
|
+
ringSenseLink: 'https://ringsense.example.com/123'
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
expect(result).toContain('RingSense transcript');
|
|
150
|
+
expect(result).toContain('RingSense summary');
|
|
151
|
+
expect(result).toContain('Call score: 85');
|
|
152
|
+
expect(result).toContain('RingSense recording link');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('should add call legs when provided', async () => {
|
|
156
|
+
const result = await composeCallLog({
|
|
157
|
+
...baseParams,
|
|
158
|
+
callLog: {
|
|
159
|
+
...baseParams.callLog,
|
|
160
|
+
legs: [
|
|
161
|
+
{ direction: 'Outbound', from: { phoneNumber: '+1234567890' }, to: { phoneNumber: '+0987654321' }, duration: 60 }
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
expect(result).toContain('Call journey');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('should handle RingCentral user name setting', async () => {
|
|
170
|
+
// For Outbound calls, it picks from.name
|
|
171
|
+
const result = await composeCallLog({
|
|
172
|
+
...baseParams,
|
|
173
|
+
user: {
|
|
174
|
+
userSettings: { addRingCentralUserName: { value: true } },
|
|
175
|
+
timezoneOffset: '+00:00'
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// For Outbound, uses from.name which is John Doe
|
|
180
|
+
expect(result).toContain('RingCentral user name: John Doe');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('should handle RingCentral number and extension setting', async () => {
|
|
184
|
+
const result = await composeCallLog({
|
|
185
|
+
...baseParams,
|
|
186
|
+
user: {
|
|
187
|
+
userSettings: { addRingCentralNumber: { value: true } },
|
|
188
|
+
timezoneOffset: '+00:00'
|
|
189
|
+
},
|
|
190
|
+
callLog: {
|
|
191
|
+
...baseParams.callLog,
|
|
192
|
+
from: { phoneNumber: '+1234567890', extensionNumber: '101' }
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(result).toContain('RingCentral number and extension');
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('upsertCallAgentNote', () => {
|
|
201
|
+
test('should add note to empty body (plain text)', () => {
|
|
202
|
+
const result = upsertCallAgentNote({
|
|
203
|
+
body: '',
|
|
204
|
+
note: 'Test note',
|
|
205
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
expect(result).toBe('- Note: Test note\n');
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('should replace existing note (plain text)', () => {
|
|
212
|
+
const body = '- Note: Old note\n- Duration: 2 minutes';
|
|
213
|
+
const result = upsertCallAgentNote({
|
|
214
|
+
body,
|
|
215
|
+
note: 'New note',
|
|
216
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
expect(result).toContain('- Note: New note');
|
|
220
|
+
expect(result).not.toContain('Old note');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('should add note in HTML format', () => {
|
|
224
|
+
const result = upsertCallAgentNote({
|
|
225
|
+
body: '',
|
|
226
|
+
note: 'Test note',
|
|
227
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
expect(result).toContain('<b>Agent notes</b>');
|
|
231
|
+
expect(result).toContain('Test note');
|
|
232
|
+
expect(result).toContain('<b>Call details</b>');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('should add note in Markdown format', () => {
|
|
236
|
+
const result = upsertCallAgentNote({
|
|
237
|
+
body: '',
|
|
238
|
+
note: 'Test note',
|
|
239
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
expect(result).toContain('## Agent notes');
|
|
243
|
+
expect(result).toContain('Test note');
|
|
244
|
+
expect(result).toContain('## Call details');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('should return body unchanged if note is empty', () => {
|
|
248
|
+
const body = 'Existing content';
|
|
249
|
+
const result = upsertCallAgentNote({
|
|
250
|
+
body,
|
|
251
|
+
note: '',
|
|
252
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
expect(result).toBe(body);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe('upsertCallSessionId', () => {
|
|
260
|
+
test('should add session ID to empty body (plain text)', () => {
|
|
261
|
+
const result = upsertCallSessionId({
|
|
262
|
+
body: '',
|
|
263
|
+
id: 'session-123',
|
|
264
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(result).toBe('- Session Id: session-123\n');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test('should add session ID in HTML format', () => {
|
|
271
|
+
const result = upsertCallSessionId({
|
|
272
|
+
body: '',
|
|
273
|
+
id: 'session-123',
|
|
274
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
expect(result).toContain('<b>Session Id</b>: session-123');
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test('should add session ID in Markdown format', () => {
|
|
281
|
+
const result = upsertCallSessionId({
|
|
282
|
+
body: '',
|
|
283
|
+
id: 'session-123',
|
|
284
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
expect(result).toContain('**Session Id**: session-123');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test('should return body unchanged if id is empty', () => {
|
|
291
|
+
const body = 'Existing content';
|
|
292
|
+
const result = upsertCallSessionId({
|
|
293
|
+
body,
|
|
294
|
+
id: '',
|
|
295
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
expect(result).toBe(body);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('upsertRingCentralUserName', () => {
|
|
303
|
+
test('should add user name to empty body', () => {
|
|
304
|
+
const result = upsertRingCentralUserName({
|
|
305
|
+
body: '',
|
|
306
|
+
userName: 'John Doe',
|
|
307
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(result).toContain('RingCentral user name: John Doe');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test('should replace pending placeholder', () => {
|
|
314
|
+
const body = '- RingCentral user name: (pending...)\n';
|
|
315
|
+
const result = upsertRingCentralUserName({
|
|
316
|
+
body,
|
|
317
|
+
userName: 'John Doe',
|
|
318
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
expect(result).toContain('RingCentral user name: John Doe');
|
|
322
|
+
expect(result).not.toContain('(pending...)');
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test('should not replace existing non-pending value', () => {
|
|
326
|
+
const body = '- RingCentral user name: Jane Smith\n';
|
|
327
|
+
const result = upsertRingCentralUserName({
|
|
328
|
+
body,
|
|
329
|
+
userName: 'John Doe',
|
|
330
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
expect(result).toContain('Jane Smith');
|
|
334
|
+
expect(result).not.toContain('John Doe');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test('should add user name in HTML format', () => {
|
|
338
|
+
const result = upsertRingCentralUserName({
|
|
339
|
+
body: '',
|
|
340
|
+
userName: 'John Doe',
|
|
341
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
expect(result).toContain('<b>RingCentral user name</b>: John Doe');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test('should add user name in Markdown format', () => {
|
|
348
|
+
const result = upsertRingCentralUserName({
|
|
349
|
+
body: '',
|
|
350
|
+
userName: 'John Doe',
|
|
351
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
expect(result).toContain('**RingCentral user name**: John Doe');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test('should replace pending placeholder in Markdown format', () => {
|
|
358
|
+
const body = '**RingCentral user name**: (pending...)\n';
|
|
359
|
+
const result = upsertRingCentralUserName({
|
|
360
|
+
body,
|
|
361
|
+
userName: 'John Doe',
|
|
362
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
expect(result).toContain('**RingCentral user name**: John Doe');
|
|
366
|
+
expect(result).not.toContain('(pending...)');
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
describe('upsertRingCentralNumberAndExtension', () => {
|
|
371
|
+
test('should add number and extension to empty body (plain text)', () => {
|
|
372
|
+
const result = upsertRingCentralNumberAndExtension({
|
|
373
|
+
body: '',
|
|
374
|
+
number: '+1234567890',
|
|
375
|
+
extension: '101',
|
|
376
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
expect(result).toContain('RingCentral number and extension: +1234567890 101');
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test('should add in HTML format', () => {
|
|
383
|
+
const result = upsertRingCentralNumberAndExtension({
|
|
384
|
+
body: '',
|
|
385
|
+
number: '+1234567890',
|
|
386
|
+
extension: '101',
|
|
387
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
expect(result).toContain('<b>RingCentral number and extension</b>: +1234567890 101');
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
test('should add in Markdown format', () => {
|
|
394
|
+
const result = upsertRingCentralNumberAndExtension({
|
|
395
|
+
body: '',
|
|
396
|
+
number: '+1234567890',
|
|
397
|
+
extension: '101',
|
|
398
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
expect(result).toContain('**RingCentral number and extension**: +1234567890 101');
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test('should replace existing value in plain text', () => {
|
|
405
|
+
const body = '- RingCentral number and extension: +9999999999 999\n';
|
|
406
|
+
const result = upsertRingCentralNumberAndExtension({
|
|
407
|
+
body,
|
|
408
|
+
number: '+1234567890',
|
|
409
|
+
extension: '101',
|
|
410
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
expect(result).toContain('RingCentral number and extension: +1234567890 101');
|
|
414
|
+
expect(result).not.toContain('+9999999999');
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test('should handle number without extension', () => {
|
|
418
|
+
const result = upsertRingCentralNumberAndExtension({
|
|
419
|
+
body: '',
|
|
420
|
+
number: '+1234567890',
|
|
421
|
+
extension: '',
|
|
422
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
expect(result).toContain('RingCentral number and extension: +1234567890');
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test('should return body unchanged if number and extension are empty', () => {
|
|
429
|
+
const body = 'Existing content';
|
|
430
|
+
const result = upsertRingCentralNumberAndExtension({
|
|
431
|
+
body,
|
|
432
|
+
number: '',
|
|
433
|
+
extension: '',
|
|
434
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
expect(result).toBe(body);
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
describe('upsertCallSubject', () => {
|
|
442
|
+
test('should add subject to empty body', () => {
|
|
443
|
+
const result = upsertCallSubject({
|
|
444
|
+
body: '',
|
|
445
|
+
subject: 'Call with Client',
|
|
446
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
expect(result).toBe('- Summary: Call with Client\n');
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test('should replace existing subject', () => {
|
|
453
|
+
const body = '- Summary: Old subject\n- Duration: 5 minutes';
|
|
454
|
+
const result = upsertCallSubject({
|
|
455
|
+
body,
|
|
456
|
+
subject: 'New subject',
|
|
457
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
expect(result).toContain('- Summary: New subject');
|
|
461
|
+
expect(result).not.toContain('Old subject');
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
test('should add subject in HTML format', () => {
|
|
465
|
+
const result = upsertCallSubject({
|
|
466
|
+
body: '',
|
|
467
|
+
subject: 'Test Subject',
|
|
468
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
expect(result).toContain('<b>Summary</b>: Test Subject');
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test('should add subject in Markdown format', () => {
|
|
475
|
+
const result = upsertCallSubject({
|
|
476
|
+
body: '',
|
|
477
|
+
subject: 'Test Subject',
|
|
478
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
expect(result).toContain('**Summary**: Test Subject');
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test('should replace existing subject in Markdown format', () => {
|
|
485
|
+
const body = '**Summary**: Old subject\n**Duration**: 5 minutes';
|
|
486
|
+
const result = upsertCallSubject({
|
|
487
|
+
body,
|
|
488
|
+
subject: 'New subject',
|
|
489
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
expect(result).toContain('**Summary**: New subject');
|
|
493
|
+
expect(result).not.toContain('Old subject');
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
describe('upsertContactPhoneNumber', () => {
|
|
498
|
+
test('should add phone number for outbound call', () => {
|
|
499
|
+
const result = upsertContactPhoneNumber({
|
|
500
|
+
body: '',
|
|
501
|
+
phoneNumber: '+1234567890',
|
|
502
|
+
direction: 'Outbound',
|
|
503
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
expect(result).toContain('Contact Number: +1234567890');
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
test('should add phone number for inbound call', () => {
|
|
510
|
+
const result = upsertContactPhoneNumber({
|
|
511
|
+
body: '',
|
|
512
|
+
phoneNumber: '+1234567890',
|
|
513
|
+
direction: 'Inbound',
|
|
514
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
expect(result).toContain('Contact Number: +1234567890');
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
test('should add phone number in HTML format with direction label', () => {
|
|
521
|
+
const result = upsertContactPhoneNumber({
|
|
522
|
+
body: '',
|
|
523
|
+
phoneNumber: '+1234567890',
|
|
524
|
+
direction: 'Outbound',
|
|
525
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
expect(result).toContain('<b>Recipient phone number</b>: +1234567890');
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
test('should add phone number in Markdown format', () => {
|
|
532
|
+
const result = upsertContactPhoneNumber({
|
|
533
|
+
body: '',
|
|
534
|
+
phoneNumber: '+1234567890',
|
|
535
|
+
direction: 'Outbound',
|
|
536
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
expect(result).toContain('**Contact Number**: +1234567890');
|
|
540
|
+
});
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
describe('upsertCallDateTime', () => {
|
|
544
|
+
test('should add formatted date/time', () => {
|
|
545
|
+
const result = upsertCallDateTime({
|
|
546
|
+
body: '',
|
|
547
|
+
startTime: '2024-01-15T10:30:00Z',
|
|
548
|
+
timezoneOffset: '+00:00',
|
|
549
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
550
|
+
logDateFormat: 'YYYY-MM-DD hh:mm:ss A'
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
expect(result).toContain('Date/Time:');
|
|
554
|
+
expect(result).toContain('2024-01-15');
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
test('should apply timezone offset', () => {
|
|
558
|
+
const result = upsertCallDateTime({
|
|
559
|
+
body: '',
|
|
560
|
+
startTime: '2024-01-15T10:30:00Z',
|
|
561
|
+
timezoneOffset: '+05:00',
|
|
562
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
563
|
+
logDateFormat: 'YYYY-MM-DD HH:mm'
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
expect(result).toContain('Date/Time:');
|
|
567
|
+
expect(result).toContain('15:30'); // 10:30 + 5 hours
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
test('should add date/time in HTML format', () => {
|
|
571
|
+
const result = upsertCallDateTime({
|
|
572
|
+
body: '',
|
|
573
|
+
startTime: '2024-01-15T10:30:00Z',
|
|
574
|
+
timezoneOffset: '+00:00',
|
|
575
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
expect(result).toContain('<b>Date/time</b>:');
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
test('should add date/time in Markdown format', () => {
|
|
582
|
+
const result = upsertCallDateTime({
|
|
583
|
+
body: '',
|
|
584
|
+
startTime: '2024-01-15T10:30:00Z',
|
|
585
|
+
timezoneOffset: '+00:00',
|
|
586
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN,
|
|
587
|
+
logDateFormat: 'YYYY-MM-DD hh:mm:ss A'
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
expect(result).toContain('**Date/Time**:');
|
|
591
|
+
expect(result).toContain('2024-01-15');
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
test('should replace existing date/time in Markdown format', () => {
|
|
595
|
+
const body = '**Date/Time**: 2024-01-01 09:00:00 AM\n';
|
|
596
|
+
const result = upsertCallDateTime({
|
|
597
|
+
body,
|
|
598
|
+
startTime: '2024-01-15T10:30:00Z',
|
|
599
|
+
timezoneOffset: '+00:00',
|
|
600
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN,
|
|
601
|
+
logDateFormat: 'YYYY-MM-DD HH:mm'
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
expect(result).toContain('**Date/Time**: 2024-01-15');
|
|
605
|
+
expect(result).not.toContain('2024-01-01');
|
|
606
|
+
});
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
describe('upsertCallDuration', () => {
|
|
610
|
+
test('should add formatted duration', () => {
|
|
611
|
+
const result = upsertCallDuration({
|
|
612
|
+
body: '',
|
|
613
|
+
duration: 120,
|
|
614
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
expect(result).toContain('Duration: 2 minutes');
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
test('should handle hours, minutes, seconds', () => {
|
|
621
|
+
const result = upsertCallDuration({
|
|
622
|
+
body: '',
|
|
623
|
+
duration: 3661, // 1 hour, 1 minute, 1 second
|
|
624
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
expect(result).toContain('1 hour');
|
|
628
|
+
expect(result).toContain('1 minute');
|
|
629
|
+
expect(result).toContain('1 second');
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
test('should add duration in HTML format', () => {
|
|
633
|
+
const result = upsertCallDuration({
|
|
634
|
+
body: '',
|
|
635
|
+
duration: 60,
|
|
636
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
expect(result).toContain('<b>Duration</b>:');
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
test('should handle 0 duration', () => {
|
|
643
|
+
const result = upsertCallDuration({
|
|
644
|
+
body: '',
|
|
645
|
+
duration: 0,
|
|
646
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
expect(result).toContain('Duration: 0 seconds');
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
test('should add duration in Markdown format', () => {
|
|
653
|
+
const result = upsertCallDuration({
|
|
654
|
+
body: '',
|
|
655
|
+
duration: 120,
|
|
656
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
expect(result).toContain('**Duration**: 2 minutes');
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
test('should replace existing duration in Markdown format', () => {
|
|
663
|
+
const body = '**Duration**: 1 minute\n';
|
|
664
|
+
const result = upsertCallDuration({
|
|
665
|
+
body,
|
|
666
|
+
duration: 180,
|
|
667
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
expect(result).toContain('**Duration**: 3 minutes');
|
|
671
|
+
expect(result).not.toContain('1 minute');
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
describe('upsertCallResult', () => {
|
|
676
|
+
test('should add call result', () => {
|
|
677
|
+
const result = upsertCallResult({
|
|
678
|
+
body: '',
|
|
679
|
+
result: 'Completed',
|
|
680
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
expect(result).toContain('Result: Completed');
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
test('should replace existing result', () => {
|
|
687
|
+
const body = '- Result: Pending\n';
|
|
688
|
+
const result = upsertCallResult({
|
|
689
|
+
body,
|
|
690
|
+
result: 'Completed',
|
|
691
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
expect(result).toContain('Result: Completed');
|
|
695
|
+
expect(result).not.toContain('Pending');
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
test('should add result in HTML format', () => {
|
|
699
|
+
const result = upsertCallResult({
|
|
700
|
+
body: '',
|
|
701
|
+
result: 'Missed',
|
|
702
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
expect(result).toContain('<b>Result</b>: Missed');
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
test('should add result in Markdown format', () => {
|
|
709
|
+
const result = upsertCallResult({
|
|
710
|
+
body: '',
|
|
711
|
+
result: 'Completed',
|
|
712
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
expect(result).toContain('**Result**: Completed');
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
test('should replace existing result in Markdown format', () => {
|
|
719
|
+
const body = '**Result**: Pending\n';
|
|
720
|
+
const result = upsertCallResult({
|
|
721
|
+
body,
|
|
722
|
+
result: 'Completed',
|
|
723
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
expect(result).toContain('**Result**: Completed');
|
|
727
|
+
expect(result).not.toContain('Pending');
|
|
728
|
+
});
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
describe('upsertCallRecording', () => {
|
|
732
|
+
test('should add recording link', () => {
|
|
733
|
+
const result = upsertCallRecording({
|
|
734
|
+
body: '',
|
|
735
|
+
recordingLink: 'https://recording.example.com/123',
|
|
736
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
expect(result).toContain('Call recording link: https://recording.example.com/123');
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
test('should add recording link in HTML format with anchor', () => {
|
|
743
|
+
const result = upsertCallRecording({
|
|
744
|
+
body: '',
|
|
745
|
+
recordingLink: 'https://recording.example.com/123',
|
|
746
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
expect(result).toContain('<a target="_blank" href="https://recording.example.com/123">open</a>');
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
test('should show pending for non-http link', () => {
|
|
753
|
+
const result = upsertCallRecording({
|
|
754
|
+
body: '',
|
|
755
|
+
recordingLink: 'pending',
|
|
756
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
expect(result).toContain('(pending...)');
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
test('should add recording link in Markdown format', () => {
|
|
763
|
+
const result = upsertCallRecording({
|
|
764
|
+
body: '',
|
|
765
|
+
recordingLink: 'https://recording.example.com/123',
|
|
766
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
expect(result).toContain('**Call recording link**: https://recording.example.com/123');
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
test('should replace existing recording link in Markdown format', () => {
|
|
773
|
+
const body = '**Call recording link**: https://old-link.com\n';
|
|
774
|
+
const result = upsertCallRecording({
|
|
775
|
+
body,
|
|
776
|
+
recordingLink: 'https://new-link.com/456',
|
|
777
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
expect(result).toContain('**Call recording link**: https://new-link.com/456');
|
|
781
|
+
expect(result).not.toContain('old-link');
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
describe('upsertAiNote', () => {
|
|
786
|
+
test('should add AI note', () => {
|
|
787
|
+
const result = upsertAiNote({
|
|
788
|
+
body: '',
|
|
789
|
+
aiNote: 'AI generated summary',
|
|
790
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
expect(result).toContain('AI Note');
|
|
794
|
+
expect(result).toContain('AI generated summary');
|
|
795
|
+
expect(result).toContain('--- END');
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
test('should add AI note in HTML format', () => {
|
|
799
|
+
const result = upsertAiNote({
|
|
800
|
+
body: '',
|
|
801
|
+
aiNote: 'AI summary\nWith multiple lines',
|
|
802
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
expect(result).toContain('<b>AI Note</b>');
|
|
806
|
+
expect(result).toContain('<br>');
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
test('should replace existing AI note', () => {
|
|
810
|
+
const body = '- AI Note:\nOld note\n--- END\n';
|
|
811
|
+
const result = upsertAiNote({
|
|
812
|
+
body,
|
|
813
|
+
aiNote: 'New AI note',
|
|
814
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
expect(result).toContain('New AI note');
|
|
818
|
+
expect(result).not.toContain('Old note');
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
test('should add AI note in Markdown format', () => {
|
|
822
|
+
const result = upsertAiNote({
|
|
823
|
+
body: '',
|
|
824
|
+
aiNote: 'AI generated summary',
|
|
825
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
expect(result).toContain('### AI Note');
|
|
829
|
+
expect(result).toContain('AI generated summary');
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
test('should replace existing AI note in Markdown format', () => {
|
|
833
|
+
const body = '### AI Note\nOld AI note\n';
|
|
834
|
+
const result = upsertAiNote({
|
|
835
|
+
body,
|
|
836
|
+
aiNote: 'New AI note',
|
|
837
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
expect(result).toContain('New AI note');
|
|
841
|
+
});
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
describe('upsertTranscript', () => {
|
|
845
|
+
test('should add transcript', () => {
|
|
846
|
+
const result = upsertTranscript({
|
|
847
|
+
body: '',
|
|
848
|
+
transcript: 'Hello, this is a transcript.',
|
|
849
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
expect(result).toContain('Transcript');
|
|
853
|
+
expect(result).toContain('Hello, this is a transcript.');
|
|
854
|
+
expect(result).toContain('--- END');
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
test('should add transcript in HTML format', () => {
|
|
858
|
+
const result = upsertTranscript({
|
|
859
|
+
body: '',
|
|
860
|
+
transcript: 'Line 1\nLine 2',
|
|
861
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
expect(result).toContain('<b>Transcript</b>');
|
|
865
|
+
expect(result).toContain('<br>');
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
test('should add transcript in Markdown format', () => {
|
|
869
|
+
const result = upsertTranscript({
|
|
870
|
+
body: '',
|
|
871
|
+
transcript: 'Hello, this is a transcript.',
|
|
872
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
expect(result).toContain('### Transcript');
|
|
876
|
+
expect(result).toContain('Hello, this is a transcript.');
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
test('should replace existing transcript in Markdown format', () => {
|
|
880
|
+
const body = '### Transcript\nOld transcript\n';
|
|
881
|
+
const result = upsertTranscript({
|
|
882
|
+
body,
|
|
883
|
+
transcript: 'New transcript content',
|
|
884
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
expect(result).toContain('New transcript content');
|
|
888
|
+
});
|
|
889
|
+
});
|
|
890
|
+
|
|
891
|
+
describe('upsertLegs', () => {
|
|
892
|
+
test('should add call legs (outbound)', () => {
|
|
893
|
+
const legs = [
|
|
894
|
+
{
|
|
895
|
+
direction: 'Outbound',
|
|
896
|
+
from: { phoneNumber: '+1234567890', name: 'John' },
|
|
897
|
+
to: { phoneNumber: '+0987654321' },
|
|
898
|
+
duration: 60
|
|
899
|
+
}
|
|
900
|
+
];
|
|
901
|
+
|
|
902
|
+
const result = upsertLegs({
|
|
903
|
+
body: '',
|
|
904
|
+
legs,
|
|
905
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
expect(result).toContain('Call journey');
|
|
909
|
+
expect(result).toContain('Made call from');
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
test('should add call legs (inbound)', () => {
|
|
913
|
+
const legs = [
|
|
914
|
+
{
|
|
915
|
+
direction: 'Inbound',
|
|
916
|
+
from: { phoneNumber: '+1234567890' },
|
|
917
|
+
to: { phoneNumber: '+0987654321', name: 'Support' },
|
|
918
|
+
duration: 60
|
|
919
|
+
}
|
|
920
|
+
];
|
|
921
|
+
|
|
922
|
+
const result = upsertLegs({
|
|
923
|
+
body: '',
|
|
924
|
+
legs,
|
|
925
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
expect(result).toContain('Received call at');
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
test('should handle transferred calls', () => {
|
|
932
|
+
const legs = [
|
|
933
|
+
{
|
|
934
|
+
direction: 'Inbound',
|
|
935
|
+
from: { phoneNumber: '+1234567890' },
|
|
936
|
+
to: { phoneNumber: '+0987654321' },
|
|
937
|
+
duration: 30
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
direction: 'Outbound',
|
|
941
|
+
from: { phoneNumber: '+0987654321', extensionNumber: '101' },
|
|
942
|
+
to: { phoneNumber: '+1111111111' },
|
|
943
|
+
duration: 45
|
|
944
|
+
}
|
|
945
|
+
];
|
|
946
|
+
|
|
947
|
+
const result = upsertLegs({
|
|
948
|
+
body: '',
|
|
949
|
+
legs,
|
|
950
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
expect(result).toContain('Transferred to');
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
test('should return body unchanged for empty legs', () => {
|
|
957
|
+
const result = upsertLegs({
|
|
958
|
+
body: 'existing',
|
|
959
|
+
legs: [],
|
|
960
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
expect(result).toBe('existing');
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
test('should add call legs in HTML format', () => {
|
|
967
|
+
const legs = [
|
|
968
|
+
{
|
|
969
|
+
direction: 'Outbound',
|
|
970
|
+
from: { phoneNumber: '+1234567890', name: 'John' },
|
|
971
|
+
to: { phoneNumber: '+0987654321' },
|
|
972
|
+
duration: 60
|
|
973
|
+
}
|
|
974
|
+
];
|
|
975
|
+
|
|
976
|
+
const result = upsertLegs({
|
|
977
|
+
body: '',
|
|
978
|
+
legs,
|
|
979
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
expect(result).toContain('<b>Call journey</b>');
|
|
983
|
+
expect(result).toContain('Made call from');
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
test('should add call legs in Markdown format', () => {
|
|
987
|
+
const legs = [
|
|
988
|
+
{
|
|
989
|
+
direction: 'Outbound',
|
|
990
|
+
from: { phoneNumber: '+1234567890', name: 'John' },
|
|
991
|
+
to: { phoneNumber: '+0987654321' },
|
|
992
|
+
duration: 60
|
|
993
|
+
}
|
|
994
|
+
];
|
|
995
|
+
|
|
996
|
+
const result = upsertLegs({
|
|
997
|
+
body: '',
|
|
998
|
+
legs,
|
|
999
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
expect(result).toContain('### Call journey');
|
|
1003
|
+
expect(result).toContain('Made call from');
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
test('should replace existing legs in Markdown format', () => {
|
|
1007
|
+
const body = '### Call journey\nOld journey info\n';
|
|
1008
|
+
const legs = [
|
|
1009
|
+
{
|
|
1010
|
+
direction: 'Inbound',
|
|
1011
|
+
from: { phoneNumber: '+1234567890' },
|
|
1012
|
+
to: { phoneNumber: '+0987654321', name: 'Support' },
|
|
1013
|
+
duration: 120
|
|
1014
|
+
}
|
|
1015
|
+
];
|
|
1016
|
+
|
|
1017
|
+
const result = upsertLegs({
|
|
1018
|
+
body,
|
|
1019
|
+
legs,
|
|
1020
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
expect(result).toContain('### Call journey');
|
|
1024
|
+
expect(result).toContain('Received call at');
|
|
1025
|
+
});
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
describe('RingSense Functions', () => {
|
|
1029
|
+
describe('upsertRingSenseTranscript', () => {
|
|
1030
|
+
test('should add RingSense transcript', () => {
|
|
1031
|
+
const result = upsertRingSenseTranscript({
|
|
1032
|
+
body: '',
|
|
1033
|
+
transcript: 'RS transcript content',
|
|
1034
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
1035
|
+
});
|
|
1036
|
+
|
|
1037
|
+
expect(result).toContain('RingSense transcript');
|
|
1038
|
+
expect(result).toContain('RS transcript content');
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
test('should add in HTML format', () => {
|
|
1042
|
+
const result = upsertRingSenseTranscript({
|
|
1043
|
+
body: '',
|
|
1044
|
+
transcript: 'RS transcript',
|
|
1045
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
expect(result).toContain('<b>RingSense transcript</b>');
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
test('should add in Markdown format', () => {
|
|
1052
|
+
const result = upsertRingSenseTranscript({
|
|
1053
|
+
body: '',
|
|
1054
|
+
transcript: 'RS transcript content',
|
|
1055
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
expect(result).toContain('### RingSense transcript');
|
|
1059
|
+
expect(result).toContain('RS transcript content');
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
describe('upsertRingSenseSummary', () => {
|
|
1064
|
+
test('should add RingSense summary', () => {
|
|
1065
|
+
const result = upsertRingSenseSummary({
|
|
1066
|
+
body: '',
|
|
1067
|
+
summary: 'RS summary content',
|
|
1068
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
expect(result).toContain('RingSense summary');
|
|
1072
|
+
expect(result).toContain('RS summary content');
|
|
1073
|
+
});
|
|
1074
|
+
|
|
1075
|
+
test('should add in HTML format', () => {
|
|
1076
|
+
const result = upsertRingSenseSummary({
|
|
1077
|
+
body: '',
|
|
1078
|
+
summary: 'RS summary',
|
|
1079
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
expect(result).toContain('<b>RingSense summary</b>');
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
test('should add in Markdown format', () => {
|
|
1086
|
+
const result = upsertRingSenseSummary({
|
|
1087
|
+
body: '',
|
|
1088
|
+
summary: 'RS summary content',
|
|
1089
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
expect(result).toContain('### RingSense summary');
|
|
1093
|
+
expect(result).toContain('RS summary content');
|
|
1094
|
+
});
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
describe('upsertRingSenseAIScore', () => {
|
|
1098
|
+
test('should add RingSense AI score', () => {
|
|
1099
|
+
const result = upsertRingSenseAIScore({
|
|
1100
|
+
body: '',
|
|
1101
|
+
score: '85',
|
|
1102
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
expect(result).toContain('Call score: 85');
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
test('should add in HTML format', () => {
|
|
1109
|
+
const result = upsertRingSenseAIScore({
|
|
1110
|
+
body: '',
|
|
1111
|
+
score: '90',
|
|
1112
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
expect(result).toContain('<b>Call score</b>: 90');
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
test('should add in Markdown format', () => {
|
|
1119
|
+
const result = upsertRingSenseAIScore({
|
|
1120
|
+
body: '',
|
|
1121
|
+
score: '85',
|
|
1122
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
expect(result).toContain('**Call score**: 85');
|
|
1126
|
+
});
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
describe('upsertRingSenseBulletedSummary', () => {
|
|
1130
|
+
test('should add RingSense bulleted summary', () => {
|
|
1131
|
+
const result = upsertRingSenseBulletedSummary({
|
|
1132
|
+
body: '',
|
|
1133
|
+
summary: '- Point 1\n- Point 2',
|
|
1134
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
expect(result).toContain('RingSense bulleted summary');
|
|
1138
|
+
expect(result).toContain('- Point 1');
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
test('should add in HTML format', () => {
|
|
1142
|
+
const result = upsertRingSenseBulletedSummary({
|
|
1143
|
+
body: '',
|
|
1144
|
+
summary: '- Item 1\n- Item 2',
|
|
1145
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
expect(result).toContain('<b>RingSense bulleted summary</b>');
|
|
1149
|
+
});
|
|
1150
|
+
|
|
1151
|
+
test('should add in Markdown format', () => {
|
|
1152
|
+
const result = upsertRingSenseBulletedSummary({
|
|
1153
|
+
body: '',
|
|
1154
|
+
summary: '- Point 1\n- Point 2',
|
|
1155
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
expect(result).toContain('### RingSense bulleted summary');
|
|
1159
|
+
expect(result).toContain('- Point 1');
|
|
1160
|
+
});
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
describe('upsertRingSenseLink', () => {
|
|
1164
|
+
test('should add RingSense recording link', () => {
|
|
1165
|
+
const result = upsertRingSenseLink({
|
|
1166
|
+
body: '',
|
|
1167
|
+
link: 'https://ringsense.example.com/123',
|
|
1168
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
expect(result).toContain('RingSense recording link: https://ringsense.example.com/123');
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
test('should add in HTML format with anchor', () => {
|
|
1175
|
+
const result = upsertRingSenseLink({
|
|
1176
|
+
body: '',
|
|
1177
|
+
link: 'https://ringsense.example.com/123',
|
|
1178
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.HTML
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
expect(result).toContain('<a target="_blank" href="https://ringsense.example.com/123">open</a>');
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
test('should add in Markdown format', () => {
|
|
1185
|
+
const result = upsertRingSenseLink({
|
|
1186
|
+
body: '',
|
|
1187
|
+
link: 'https://ringsense.example.com/123',
|
|
1188
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.MARKDOWN
|
|
1189
|
+
});
|
|
1190
|
+
|
|
1191
|
+
expect(result).toContain('**RingSense recording link**: https://ringsense.example.com/123');
|
|
1192
|
+
});
|
|
1193
|
+
});
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
describe('Edge Cases', () => {
|
|
1197
|
+
test('should handle null user settings', async () => {
|
|
1198
|
+
const result = await composeCallLog({
|
|
1199
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
1200
|
+
callLog: { direction: 'Outbound', startTime: new Date() },
|
|
1201
|
+
user: { userSettings: null },
|
|
1202
|
+
note: 'Test',
|
|
1203
|
+
duration: 60
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
expect(result).toContain('Note: Test');
|
|
1207
|
+
expect(result).toContain('Duration:');
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
test('should handle undefined user settings', async () => {
|
|
1211
|
+
const result = await composeCallLog({
|
|
1212
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
1213
|
+
callLog: { direction: 'Outbound' },
|
|
1214
|
+
user: {},
|
|
1215
|
+
result: 'Completed'
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1218
|
+
expect(result).toContain('Result: Completed');
|
|
1219
|
+
});
|
|
1220
|
+
|
|
1221
|
+
test('should return empty string for empty params', async () => {
|
|
1222
|
+
const result = await composeCallLog({
|
|
1223
|
+
logFormat: LOG_DETAILS_FORMAT_TYPE.PLAIN_TEXT,
|
|
1224
|
+
user: {}
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1227
|
+
expect(result).toBe('');
|
|
1228
|
+
});
|
|
1229
|
+
});
|
|
1230
|
+
});
|
|
1231
|
+
|