@tellescope/sdk 1.255.2 → 1.255.4
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/lib/cjs/tests/api_tests/generate_enduser_summary.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/generate_enduser_summary.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/generate_enduser_summary.test.js +186 -0
- package/lib/cjs/tests/api_tests/generate_enduser_summary.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/medication_added_trigger.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/medication_added_trigger.test.js +206 -136
- package/lib/cjs/tests/api_tests/medication_added_trigger.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/F-0005-ai-conversations-rbac.test.d.ts +10 -0
- package/lib/cjs/tests/api_tests/security/F-0005-ai-conversations-rbac.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/security/F-0005-ai-conversations-rbac.test.js +184 -41
- package/lib/cjs/tests/api_tests/security/F-0005-ai-conversations-rbac.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/translations.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/translations.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/translations.test.js +148 -0
- package/lib/cjs/tests/api_tests/translations.test.js.map +1 -0
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +89 -85
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/esm/tests/api_tests/generate_enduser_summary.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/generate_enduser_summary.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/generate_enduser_summary.test.js +182 -0
- package/lib/esm/tests/api_tests/generate_enduser_summary.test.js.map +1 -0
- package/lib/esm/tests/api_tests/medication_added_trigger.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/medication_added_trigger.test.js +206 -136
- package/lib/esm/tests/api_tests/medication_added_trigger.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.d.ts +10 -0
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.js +184 -41
- package/lib/esm/tests/api_tests/security/F-0005-ai-conversations-rbac.test.js.map +1 -1
- package/lib/esm/tests/api_tests/translations.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/translations.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/translations.test.js +144 -0
- package/lib/esm/tests/api_tests/translations.test.js.map +1 -0
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +89 -85
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/tests/api_tests/medication_added_trigger.test.ts +59 -1
- package/src/tests/api_tests/security/F-0005-ai-conversations-rbac.test.ts +123 -0
- package/src/tests/api_tests/translations.test.ts +83 -0
- package/src/tests/tests.ts +2 -0
- package/test_generated.pdf +0 -0
|
@@ -182,7 +182,7 @@ export const medication_added_trigger_tests = async ({ sdk, sdkNonAdmin } : { sd
|
|
|
182
182
|
title: "Medication - Beluga Protocol Test"
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
// Simulate the Beluga RX_WRITTEN webhook with two meds covering category present (typical) and "N/A"
|
|
185
|
+
// Simulate the Beluga RX_WRITTEN webhook with two meds covering category/pharmacyNotes present (typical) and "N/A"/absent
|
|
186
186
|
const webhookResponse = await fetch(`${host}/v1/webhooks/beluga`, {
|
|
187
187
|
method: 'POST',
|
|
188
188
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -198,6 +198,7 @@ export const medication_added_trigger_tests = async ({ sdk, sdkNonAdmin } : { sd
|
|
|
198
198
|
medId: 'test-ndc-123',
|
|
199
199
|
rxId: 'test-rx-456',
|
|
200
200
|
category: 'weightloss1',
|
|
201
|
+
pharmacyNotes: 'Dispense with syringes',
|
|
201
202
|
}, {
|
|
202
203
|
name: 'Metformin',
|
|
203
204
|
strength: '500mg',
|
|
@@ -245,6 +246,16 @@ export const medication_added_trigger_tests = async ({ sdk, sdkNonAdmin } : { sd
|
|
|
245
246
|
async () => belugaMedMetformin,
|
|
246
247
|
{ onResult: (m: EnduserMedication) => m?.category === 'N/A' }
|
|
247
248
|
)
|
|
249
|
+
await async_test(
|
|
250
|
+
"Beluga RX_WRITTEN - Medication has notes from webhook pharmacyNotes",
|
|
251
|
+
async () => belugaMedSemaglutide,
|
|
252
|
+
{ onResult: (m: EnduserMedication) => m?.notes === 'Dispense with syringes' }
|
|
253
|
+
)
|
|
254
|
+
await async_test(
|
|
255
|
+
"Beluga RX_WRITTEN - Medication omits notes when pharmacyNotes not provided on med",
|
|
256
|
+
async () => belugaMedMetformin,
|
|
257
|
+
{ onResult: (m: EnduserMedication) => m?.notes === undefined || m?.notes === null }
|
|
258
|
+
)
|
|
248
259
|
|
|
249
260
|
// Backwards-compatibility: a webhook with no category on any med should result in undefined category
|
|
250
261
|
const belugaFormNoCategory = await sdk.api.forms.createOne({
|
|
@@ -294,6 +305,11 @@ export const medication_added_trigger_tests = async ({ sdk, sdkNonAdmin } : { sd
|
|
|
294
305
|
async () => belugaMedNoCategory,
|
|
295
306
|
{ onResult: (m: EnduserMedication) => m?.category === undefined || m?.category === null }
|
|
296
307
|
)
|
|
308
|
+
await async_test(
|
|
309
|
+
"Beluga RX_WRITTEN - Medication omits notes when pharmacyNotes not provided",
|
|
310
|
+
async () => belugaMedNoCategory,
|
|
311
|
+
{ onResult: (m: EnduserMedication) => m?.notes === undefined || m?.notes === null }
|
|
312
|
+
)
|
|
297
313
|
|
|
298
314
|
try {
|
|
299
315
|
// Clean up Beluga test data
|
|
@@ -389,14 +405,56 @@ export const medication_added_trigger_tests = async ({ sdk, sdkNonAdmin } : { sd
|
|
|
389
405
|
{ onResult: (e: Enduser) => e.fields?.['Medication Category'] === '' }
|
|
390
406
|
)
|
|
391
407
|
|
|
408
|
+
// ---- Set Fields with {{medication.notes}} Test ----
|
|
409
|
+
log_header("Medication Added - Set Fields with {{medication.notes}}")
|
|
410
|
+
|
|
411
|
+
const setFieldsPharmacyNotesTrigger = await sdk.api.automation_triggers.createOne({
|
|
412
|
+
event: { type: 'Medication Added', info: { titles: [], protocols: [] } },
|
|
413
|
+
action: { type: 'Set Fields', info: { fields: [{ name: 'Medication Notes', type: 'Custom Value' as const, value: '{{medication.notes}}' }] }},
|
|
414
|
+
status: 'Active',
|
|
415
|
+
title: "Medication - Set Fields medication.notes"
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
const setFieldsPharmacyNotesEnduser = await sdk.api.endusers.createOne({})
|
|
419
|
+
|
|
420
|
+
const setFieldsPharmacyNotesMed = await sdk.api.enduser_medications.createOne({
|
|
421
|
+
enduserId: setFieldsPharmacyNotesEnduser.id,
|
|
422
|
+
title: 'Ozempic 1mg',
|
|
423
|
+
notes: 'Dispense with syringes',
|
|
424
|
+
})
|
|
425
|
+
await wait(undefined, 500)
|
|
426
|
+
|
|
427
|
+
await async_test(
|
|
428
|
+
"Medication Added - Set Fields copies medication.notes to enduser field",
|
|
429
|
+
() => sdk.api.endusers.getOne(setFieldsPharmacyNotesEnduser.id),
|
|
430
|
+
{ onResult: (e: Enduser) => e.fields?.['Medication Notes'] === 'Dispense with syringes' }
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
// notes absent on medication → placeholder resolves to empty string
|
|
434
|
+
const setFieldsPharmacyNotesEnduserEmpty = await sdk.api.endusers.createOne({})
|
|
435
|
+
const setFieldsPharmacyNotesMedEmpty = await sdk.api.enduser_medications.createOne({
|
|
436
|
+
enduserId: setFieldsPharmacyNotesEnduserEmpty.id,
|
|
437
|
+
title: 'Lisinopril 40mg',
|
|
438
|
+
})
|
|
439
|
+
await wait(undefined, 500)
|
|
440
|
+
|
|
441
|
+
await async_test(
|
|
442
|
+
"Medication Added - Set Fields with no notes resolves to empty string",
|
|
443
|
+
() => sdk.api.endusers.getOne(setFieldsPharmacyNotesEnduserEmpty.id),
|
|
444
|
+
{ onResult: (e: Enduser) => e.fields?.['Medication Notes'] === '' }
|
|
445
|
+
)
|
|
446
|
+
|
|
392
447
|
try {
|
|
393
448
|
await sdk.api.automation_triggers.deleteOne(setFieldsTrigger.id)
|
|
394
449
|
await sdk.api.automation_triggers.deleteOne(setFieldsTriggerFiltered.id)
|
|
395
450
|
await sdk.api.automation_triggers.deleteOne(setFieldsCategoryTrigger.id)
|
|
451
|
+
await sdk.api.automation_triggers.deleteOne(setFieldsPharmacyNotesTrigger.id)
|
|
396
452
|
await sdk.api.endusers.deleteOne(setFieldsEnduser.id)
|
|
397
453
|
await sdk.api.endusers.deleteOne(setFieldsEnduser2.id)
|
|
398
454
|
await sdk.api.endusers.deleteOne(setFieldsCategoryEnduser.id)
|
|
399
455
|
await sdk.api.endusers.deleteOne(setFieldsCategoryEnduserEmpty.id)
|
|
456
|
+
await sdk.api.endusers.deleteOne(setFieldsPharmacyNotesEnduser.id)
|
|
457
|
+
await sdk.api.endusers.deleteOne(setFieldsPharmacyNotesEnduserEmpty.id)
|
|
400
458
|
} finally {}
|
|
401
459
|
|
|
402
460
|
// ---- titleCondition (compound conditional logic on title) ----
|
|
@@ -28,6 +28,16 @@ const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.
|
|
|
28
28
|
* 2. Assigns the role to the non-admin user.
|
|
29
29
|
* 3. Calls each endpoint as the non-admin.
|
|
30
30
|
* 4. Asserts each endpoint returns a 403-equivalent error (not 200).
|
|
31
|
+
* 5. Positive case: a role granting ai_conversations create (read/update denied) must pass
|
|
32
|
+
* the send_message gate — generating a NEW conversation requires only create access.
|
|
33
|
+
* 6. But the same role must still 403 when passing a conversationId: continuing an existing
|
|
34
|
+
* conversation reads its stored history (returned in the response) and appends to it,
|
|
35
|
+
* so it requires read + update access in addition to create.
|
|
36
|
+
* 7. Default-provider-permissions role (ai_conversations = Assigned): send_message must not
|
|
37
|
+
* 500. Regression: the post-generation $push previously ran through the caller's
|
|
38
|
+
* access-scoped DB, where "Assigned" filters can't match the just-created conversation,
|
|
39
|
+
* returning null and crashing the handler (Cannot read properties of null '_id') after
|
|
40
|
+
* credits were consumed. bedrock.ts now persists via tenant-scoped org-wide queries.
|
|
31
41
|
*
|
|
32
42
|
* Pre-fix:
|
|
33
43
|
* - send_message: 200 (or some downstream error from Bedrock) — NOT 403. Test fails.
|
|
@@ -39,7 +49,11 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
39
49
|
log_header("F-0005: ai_conversations RBAC bypass regression")
|
|
40
50
|
|
|
41
51
|
const roleName = `f0005-ai-conversations-no-access-${Date.now()}`
|
|
52
|
+
const grantRoleName = `f0005-ai-conversations-create-granted-${Date.now()}`
|
|
53
|
+
const assignedRoleName = `f0005-ai-conversations-assigned-default-${Date.now()}`
|
|
42
54
|
let rbapId: string | undefined
|
|
55
|
+
let grantRbapId: string | undefined
|
|
56
|
+
let assignedRbapId: string | undefined
|
|
43
57
|
const originalRoles = sdkNonAdmin.userInfo.roles
|
|
44
58
|
|
|
45
59
|
try {
|
|
@@ -109,6 +123,109 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
109
123
|
},
|
|
110
124
|
},
|
|
111
125
|
)
|
|
126
|
+
|
|
127
|
+
// 4. Positive case: granting only ai_conversations create must pass the RBAC gate.
|
|
128
|
+
// send_message may still fail downstream (e.g. 400 "Organization has not set up credits"),
|
|
129
|
+
// but it must NOT be an access-denial error.
|
|
130
|
+
const grantRbap = await sdk.api.role_based_access_permissions.createOne({
|
|
131
|
+
role: grantRoleName,
|
|
132
|
+
permissions: {
|
|
133
|
+
...PROVIDER_PERMISSIONS,
|
|
134
|
+
ai_conversations: { create: 'All', read: null, update: null, delete: null },
|
|
135
|
+
},
|
|
136
|
+
})
|
|
137
|
+
grantRbapId = grantRbap.id
|
|
138
|
+
|
|
139
|
+
await sdk.api.users.updateOne(
|
|
140
|
+
sdkNonAdmin.userInfo.id,
|
|
141
|
+
{ roles: [grantRoleName] },
|
|
142
|
+
{ replaceObjectFields: true },
|
|
143
|
+
)
|
|
144
|
+
await wait(undefined, 1500)
|
|
145
|
+
await sdkNonAdmin.authenticate(nonAdminEmail!, nonAdminPassword!)
|
|
146
|
+
|
|
147
|
+
await async_test(
|
|
148
|
+
"F-0005: ai_conversations.send_message must NOT be access-denied when role grants create",
|
|
149
|
+
() => sdkNonAdmin.api.ai_conversations.send_message({
|
|
150
|
+
message: 'F-0005 positive-case test',
|
|
151
|
+
type: 'Test',
|
|
152
|
+
maxTokens: 1,
|
|
153
|
+
} as any)
|
|
154
|
+
.then(() => 'allowed' as const)
|
|
155
|
+
.catch((e: any) => {
|
|
156
|
+
const msg = (e?.message ?? '').toLowerCase()
|
|
157
|
+
const status = e?.status ?? e?.code
|
|
158
|
+
if (status === 403 || status === 401
|
|
159
|
+
|| msg.includes('access') || msg.includes('permission') || msg.includes('forbidden')) {
|
|
160
|
+
throw e // access denial — the gate incorrectly blocked a create-granted role
|
|
161
|
+
}
|
|
162
|
+
return 'allowed' as const // downstream (e.g. credits) error is fine — the gate passed
|
|
163
|
+
}),
|
|
164
|
+
{ onResult: r => r === 'allowed' },
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
// 5. The create-granted (read/update-denied) role must still be blocked from CONTINUING an
|
|
168
|
+
// existing conversation — send_message with conversationId returns the full stored history
|
|
169
|
+
// and appends to it. Fake id is fine: the access check must fire before any lookup.
|
|
170
|
+
await async_test(
|
|
171
|
+
"F-0005: ai_conversations.send_message with conversationId must 403 when role denies read/update",
|
|
172
|
+
() => sdkNonAdmin.api.ai_conversations.send_message({
|
|
173
|
+
message: 'F-0005 conversationId bypass test',
|
|
174
|
+
type: 'Test',
|
|
175
|
+
maxTokens: 1,
|
|
176
|
+
conversationId: new ObjectId().toHexString(),
|
|
177
|
+
} as any),
|
|
178
|
+
{
|
|
179
|
+
shouldError: true,
|
|
180
|
+
onError: (e: any) => {
|
|
181
|
+
const msg = (e?.message ?? '').toLowerCase()
|
|
182
|
+
const status = e?.status ?? e?.code
|
|
183
|
+
return status === 403 || status === 401
|
|
184
|
+
|| msg.includes('access') || msg.includes('permission') || msg.includes('forbidden')
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
// 6. Regression: a role with default provider permissions (ai_conversations = Assigned)
|
|
190
|
+
// must be able to generate a new conversation without a 500. Previously the
|
|
191
|
+
// post-generation $push ran through the access-scoped DB, matched nothing under
|
|
192
|
+
// "Assigned", and crashed the handler with "Cannot read properties of null ('_id')".
|
|
193
|
+
const assignedRbap = await sdk.api.role_based_access_permissions.createOne({
|
|
194
|
+
role: assignedRoleName,
|
|
195
|
+
permissions: { ...PROVIDER_PERMISSIONS },
|
|
196
|
+
})
|
|
197
|
+
assignedRbapId = assignedRbap.id
|
|
198
|
+
|
|
199
|
+
await sdk.api.users.updateOne(
|
|
200
|
+
sdkNonAdmin.userInfo.id,
|
|
201
|
+
{ roles: [assignedRoleName] },
|
|
202
|
+
{ replaceObjectFields: true },
|
|
203
|
+
)
|
|
204
|
+
await wait(undefined, 1500)
|
|
205
|
+
await sdkNonAdmin.authenticate(nonAdminEmail!, nonAdminPassword!)
|
|
206
|
+
|
|
207
|
+
await async_test(
|
|
208
|
+
"F-0005: ai_conversations.send_message must not 500 for Assigned-access (default provider) role",
|
|
209
|
+
() => sdkNonAdmin.api.ai_conversations.send_message({
|
|
210
|
+
message: 'F-0005 assigned-access regression test',
|
|
211
|
+
type: 'Test',
|
|
212
|
+
maxTokens: 1,
|
|
213
|
+
} as any)
|
|
214
|
+
.then(() => 'ok' as const)
|
|
215
|
+
.catch((e: any) => {
|
|
216
|
+
const msg = (e?.message ?? '').toLowerCase()
|
|
217
|
+
const status = e?.status ?? e?.code
|
|
218
|
+
if (status === 500 || msg.includes('internal error') || msg.includes('cannot read properties')) {
|
|
219
|
+
throw e // the null-update crash — regression
|
|
220
|
+
}
|
|
221
|
+
if (status === 403 || status === 401
|
|
222
|
+
|| msg.includes('access') || msg.includes('permission') || msg.includes('forbidden')) {
|
|
223
|
+
throw e // Assigned access must pass the RBAC gate
|
|
224
|
+
}
|
|
225
|
+
return 'ok' as const // downstream (e.g. credits) error is fine
|
|
226
|
+
}),
|
|
227
|
+
{ onResult: r => r === 'ok' },
|
|
228
|
+
)
|
|
112
229
|
} finally {
|
|
113
230
|
// Cleanup: restore original roles, delete the test role.
|
|
114
231
|
try {
|
|
@@ -121,6 +238,12 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
121
238
|
if (rbapId) {
|
|
122
239
|
try { await sdk.api.role_based_access_permissions.deleteOne(rbapId) } catch {}
|
|
123
240
|
}
|
|
241
|
+
if (grantRbapId) {
|
|
242
|
+
try { await sdk.api.role_based_access_permissions.deleteOne(grantRbapId) } catch {}
|
|
243
|
+
}
|
|
244
|
+
if (assignedRbapId) {
|
|
245
|
+
try { await sdk.api.role_based_access_permissions.deleteOne(assignedRbapId) } catch {}
|
|
246
|
+
}
|
|
124
247
|
// Re-authenticate the non-admin to drop the no-access role from their JWT
|
|
125
248
|
// before subsequent tests run.
|
|
126
249
|
// Role restore above re-triggers deauthenticate_user; wait > 1s so the freshly minted
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require('source-map-support').install();
|
|
2
|
+
|
|
3
|
+
import { Session } from "../../sdk"
|
|
4
|
+
import {
|
|
5
|
+
assert,
|
|
6
|
+
log_header,
|
|
7
|
+
} from "@tellescope/testing"
|
|
8
|
+
import { setup_tests } from "../setup"
|
|
9
|
+
|
|
10
|
+
const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
11
|
+
|
|
12
|
+
// Modular test for the translations framework.
|
|
13
|
+
// Validates that a model's `translations` field (nested { field: { language: text } }) is accepted by
|
|
14
|
+
// schema validation, persists, and accumulates multiple languages (uses phone_calls as the MVP model).
|
|
15
|
+
//
|
|
16
|
+
// NOTE: this test deliberately does NOT invoke the AI translation endpoint (ai_conversations.send_message).
|
|
17
|
+
// That path consumes AI credits and belongs in an eval, not a regularly-run test. The endpoint itself is
|
|
18
|
+
// already covered by the AI Summary feature, and the translation-specific logic (the system-prompt
|
|
19
|
+
// builder in @tellescope/utilities) is a pure function verified at compile time.
|
|
20
|
+
export const translations_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
21
|
+
log_header("Translations Framework Tests")
|
|
22
|
+
|
|
23
|
+
const enduser = await sdk.api.endusers.createOne({ fname: 'Translation', lname: 'Tester' })
|
|
24
|
+
let callId: string | undefined
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const call = await sdk.api.phone_calls.createOne({
|
|
28
|
+
enduserId: enduser.id,
|
|
29
|
+
inbound: true,
|
|
30
|
+
userId: sdk.userInfo.id,
|
|
31
|
+
transcription: 'Hola, por favor devuélvame la llamada cuando pueda.',
|
|
32
|
+
})
|
|
33
|
+
callId = call.id
|
|
34
|
+
|
|
35
|
+
// --- 1. translations field accepted + persisted ---
|
|
36
|
+
const translations = { transcription: { en: 'Hi, please call me back when you can.' } }
|
|
37
|
+
await sdk.api.phone_calls.updateOne(call.id, { translations }, { replaceObjectFields: true })
|
|
38
|
+
|
|
39
|
+
const updated = await sdk.api.phone_calls.getOne(call.id)
|
|
40
|
+
assert(
|
|
41
|
+
updated.translations?.transcription?.en === translations.transcription.en,
|
|
42
|
+
`translations not persisted: ${JSON.stringify(updated.translations)}`,
|
|
43
|
+
'translations field persisted correctly',
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
// add a second language and confirm accumulation (full merged object written by convention)
|
|
47
|
+
const merged = {
|
|
48
|
+
...updated.translations,
|
|
49
|
+
transcription: { ...updated.translations?.transcription, es: 'Hola de nuevo.' },
|
|
50
|
+
}
|
|
51
|
+
await sdk.api.phone_calls.updateOne(call.id, { translations: merged }, { replaceObjectFields: true })
|
|
52
|
+
const updated2 = await sdk.api.phone_calls.getOne(call.id)
|
|
53
|
+
assert(
|
|
54
|
+
!!updated2.translations?.transcription?.en && !!updated2.translations?.transcription?.es,
|
|
55
|
+
`translations did not accumulate: ${JSON.stringify(updated2.translations)}`,
|
|
56
|
+
'multiple language translations accumulate under one field',
|
|
57
|
+
)
|
|
58
|
+
} finally {
|
|
59
|
+
if (callId) await sdk.api.phone_calls.deleteOne(callId).catch(() => {})
|
|
60
|
+
await sdk.api.endusers.deleteOne(enduser.id).catch(() => {})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Allow running this test file independently
|
|
65
|
+
if (require.main === module) {
|
|
66
|
+
const sdk = new Session({ host })
|
|
67
|
+
const sdkNonAdmin = new Session({ host })
|
|
68
|
+
|
|
69
|
+
const runTests = async () => {
|
|
70
|
+
await setup_tests(sdk, sdkNonAdmin)
|
|
71
|
+
await translations_tests({ sdk, sdkNonAdmin })
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
runTests()
|
|
75
|
+
.then(() => {
|
|
76
|
+
console.log("✅ Translations test suite completed successfully")
|
|
77
|
+
process.exit(0)
|
|
78
|
+
})
|
|
79
|
+
.catch((error) => {
|
|
80
|
+
console.error("❌ Translations test suite failed:", error)
|
|
81
|
+
process.exit(1)
|
|
82
|
+
})
|
|
83
|
+
}
|
package/src/tests/tests.ts
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
|
|
37
37
|
import { Session, APIQuery, EnduserSession } from "../sdk"
|
|
38
38
|
import { enduser_observations_acknowledge_tests } from "./api_tests/enduser_observations_acknowledge.test"
|
|
39
|
+
import { translations_tests } from "./api_tests/translations.test"
|
|
39
40
|
import { user_portal_settings_tests } from "./api_tests/user_portal_settings.test"
|
|
40
41
|
import { integrations_redacted_tests } from "./api_tests/integrations_redacted.test"
|
|
41
42
|
import { get_some_projection_tests } from "./api_tests/get_some_projection.test"
|
|
@@ -15113,6 +15114,7 @@ const ip_address_form_tests = async () => {
|
|
|
15113
15114
|
await inbox_threads_loading_tests()
|
|
15114
15115
|
await load_inbox_data_tests({ sdk, sdkNonAdmin })
|
|
15115
15116
|
await enduser_observations_acknowledge_tests({ sdk, sdkNonAdmin })
|
|
15117
|
+
await translations_tests({ sdk, sdkNonAdmin })
|
|
15116
15118
|
await create_user_notifications_trigger_tests({ sdk })
|
|
15117
15119
|
await group_mms_active_tests()
|
|
15118
15120
|
await auto_reply_tests()
|
package/test_generated.pdf
CHANGED
|
Binary file
|