@tellescope/sdk 1.248.0 → 1.249.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/.env +3 -0
- package/lib/cjs/sdk.d.ts +1 -0
- package/lib/cjs/sdk.d.ts.map +1 -1
- package/lib/cjs/sdk.js +1 -0
- package/lib/cjs/sdk.js.map +1 -1
- package/lib/cjs/tests/api_tests/chats_analytics.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/chats_analytics.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/chats_analytics.test.js +256 -0
- package/lib/cjs/tests/api_tests/chats_analytics.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/cross_org_api_key.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/cross_org_api_key.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/cross_org_api_key.test.js +748 -0
- package/lib/cjs/tests/api_tests/cross_org_api_key.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/enduser_session_invalidation.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/enduser_session_invalidation.test.js +426 -2
- package/lib/cjs/tests/api_tests/enduser_session_invalidation.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/eom_billing_codes.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/eom_billing_codes.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/eom_billing_codes.test.js +162 -0
- package/lib/cjs/tests/api_tests/eom_billing_codes.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/eom_procedure_codes.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/eom_procedure_codes.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/eom_procedure_codes.test.js +339 -0
- package/lib/cjs/tests/api_tests/eom_procedure_codes.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/managed_content_file_access.test.d.ts +13 -0
- package/lib/cjs/tests/api_tests/managed_content_file_access.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/managed_content_file_access.test.js +385 -0
- package/lib/cjs/tests/api_tests/managed_content_file_access.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/organization_settings_duplicates.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/organization_settings_duplicates.test.js +25 -2
- package/lib/cjs/tests/api_tests/organization_settings_duplicates.test.js.map +1 -1
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +185 -134
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/esm/sdk.d.ts +3 -2
- package/lib/esm/sdk.d.ts.map +1 -1
- package/lib/esm/sdk.js +1 -0
- package/lib/esm/sdk.js.map +1 -1
- package/lib/esm/tests/api_tests/chats_analytics.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/chats_analytics.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/chats_analytics.test.js +252 -0
- package/lib/esm/tests/api_tests/chats_analytics.test.js.map +1 -0
- package/lib/esm/tests/api_tests/cross_org_api_key.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/cross_org_api_key.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/cross_org_api_key.test.js +744 -0
- package/lib/esm/tests/api_tests/cross_org_api_key.test.js.map +1 -0
- package/lib/esm/tests/api_tests/enduser_session_invalidation.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/enduser_session_invalidation.test.js +426 -2
- package/lib/esm/tests/api_tests/enduser_session_invalidation.test.js.map +1 -1
- package/lib/esm/tests/api_tests/eom_billing_codes.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/eom_billing_codes.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/eom_billing_codes.test.js +158 -0
- package/lib/esm/tests/api_tests/eom_billing_codes.test.js.map +1 -0
- package/lib/esm/tests/api_tests/eom_procedure_codes.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/eom_procedure_codes.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/eom_procedure_codes.test.js +335 -0
- package/lib/esm/tests/api_tests/eom_procedure_codes.test.js.map +1 -0
- package/lib/esm/tests/api_tests/managed_content_file_access.test.d.ts +13 -0
- package/lib/esm/tests/api_tests/managed_content_file_access.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/managed_content_file_access.test.js +358 -0
- package/lib/esm/tests/api_tests/managed_content_file_access.test.js.map +1 -0
- package/lib/esm/tests/api_tests/organization_settings_duplicates.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/organization_settings_duplicates.test.js +25 -2
- package/lib/esm/tests/api_tests/organization_settings_duplicates.test.js.map +1 -1
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +186 -135
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/sdk.ts +4 -0
- package/src/tests/api_tests/chats_analytics.test.ts +182 -0
- package/src/tests/api_tests/cross_org_api_key.test.ts +665 -0
- package/src/tests/api_tests/enduser_session_invalidation.test.ts +223 -0
- package/src/tests/api_tests/eom_procedure_codes.test.ts +296 -0
- package/src/tests/api_tests/managed_content_file_access.test.ts +214 -0
- package/src/tests/api_tests/organization_settings_duplicates.test.ts +14 -0
- package/src/tests/tests.ts +93 -3
- package/test_generated.pdf +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
require('source-map-support').install();
|
|
2
|
+
|
|
3
|
+
import * as buffer from 'buffer'
|
|
4
|
+
import { Session, EnduserSession } from "../../sdk"
|
|
5
|
+
import {
|
|
6
|
+
async_test,
|
|
7
|
+
log_header,
|
|
8
|
+
} from "@tellescope/testing"
|
|
9
|
+
import { setup_tests } from "../setup"
|
|
10
|
+
|
|
11
|
+
const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
12
|
+
const businessId = '60398b1131a295e64f084ff6'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Tests for file_download_URL enduser access via managed content fallback.
|
|
16
|
+
*
|
|
17
|
+
* Verifies the backend fallback logic that allows endusers to access files
|
|
18
|
+
* attached to managed content records they have access to, even when the
|
|
19
|
+
* file itself does not have enduserId set or publicRead: true.
|
|
20
|
+
*/
|
|
21
|
+
export const managed_content_file_access_tests = async ({ sdk, sdkNonAdmin }: { sdk: Session, sdkNonAdmin: Session }) => {
|
|
22
|
+
log_header("Managed Content File Access Tests")
|
|
23
|
+
|
|
24
|
+
const contentRecordIds: string[] = []
|
|
25
|
+
const assignmentIds: string[] = []
|
|
26
|
+
const fileIds: string[] = []
|
|
27
|
+
let testEnduserId: string | undefined
|
|
28
|
+
let otherEnduserId: string | undefined
|
|
29
|
+
let enduserSDK: EnduserSession | undefined
|
|
30
|
+
let otherEnduserSDK: EnduserSession | undefined
|
|
31
|
+
|
|
32
|
+
const uploadFile = async (
|
|
33
|
+
name: string,
|
|
34
|
+
opts: { enduserId?: string, publicRead?: boolean } = {}
|
|
35
|
+
) => {
|
|
36
|
+
const buff = buffer.Buffer.from(`test file content for ${name}`)
|
|
37
|
+
const { presignedUpload, file } = await sdk.api.files.prepare_file_upload({
|
|
38
|
+
name,
|
|
39
|
+
type: 'text/plain',
|
|
40
|
+
size: buff.byteLength,
|
|
41
|
+
...opts,
|
|
42
|
+
})
|
|
43
|
+
await sdk.UPLOAD(presignedUpload as any, buff)
|
|
44
|
+
await sdk.api.files.confirm_file_upload({ id: file.id })
|
|
45
|
+
fileIds.push(file.id)
|
|
46
|
+
return file
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
console.log("Setting up test data...")
|
|
51
|
+
|
|
52
|
+
const testEnduser = await sdk.api.endusers.createOne({
|
|
53
|
+
email: `mcr_file_access_test_${Date.now()}@test.tellescope.com`,
|
|
54
|
+
})
|
|
55
|
+
testEnduserId = testEnduser.id
|
|
56
|
+
await sdk.api.endusers.set_password({ id: testEnduser.id, password: 'TestPassword123!' })
|
|
57
|
+
|
|
58
|
+
const otherEnduser = await sdk.api.endusers.createOne({
|
|
59
|
+
email: `mcr_file_access_other_${Date.now()}@test.tellescope.com`,
|
|
60
|
+
})
|
|
61
|
+
otherEnduserId = otherEnduser.id
|
|
62
|
+
await sdk.api.endusers.set_password({ id: otherEnduser.id, password: 'TestPassword123!' })
|
|
63
|
+
|
|
64
|
+
enduserSDK = new EnduserSession({ host, businessId })
|
|
65
|
+
await enduserSDK.authenticate(testEnduser.email!, 'TestPassword123!')
|
|
66
|
+
|
|
67
|
+
otherEnduserSDK = new EnduserSession({ host, businessId })
|
|
68
|
+
await otherEnduserSDK.authenticate(otherEnduser.email!, 'TestPassword123!')
|
|
69
|
+
|
|
70
|
+
// ===== Test 1: File attached to assignmentType: 'All' content - enduser CAN access =====
|
|
71
|
+
const fileForAll = await uploadFile('mcr-file-all.txt')
|
|
72
|
+
const contentAll = await sdk.api.managed_content_records.createOne({
|
|
73
|
+
title: 'MCR File Access - All',
|
|
74
|
+
htmlContent: '<p>All</p>',
|
|
75
|
+
textContent: 'All',
|
|
76
|
+
assignmentType: 'All',
|
|
77
|
+
attachments: [{ secureName: fileForAll.secureName, type: 'file', name: fileForAll.name }],
|
|
78
|
+
})
|
|
79
|
+
contentRecordIds.push(contentAll.id)
|
|
80
|
+
|
|
81
|
+
await async_test(
|
|
82
|
+
'staff-uploaded file in assignmentType:All content - enduser CAN access',
|
|
83
|
+
async () => {
|
|
84
|
+
const result = await enduserSDK!.api.files.file_download_URL({ secureName: fileForAll.secureName })
|
|
85
|
+
return !!result?.downloadURL
|
|
86
|
+
},
|
|
87
|
+
{ onResult: (r) => r === true }
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
// ===== Test 2: File attached to Individual content for enduser A - enduser B CANNOT access =====
|
|
91
|
+
const fileForIndividual = await uploadFile('mcr-file-individual.txt')
|
|
92
|
+
const contentIndividual = await sdk.api.managed_content_records.createOne({
|
|
93
|
+
title: 'MCR File Access - Individual',
|
|
94
|
+
htmlContent: '<p>Individual</p>',
|
|
95
|
+
textContent: 'Individual',
|
|
96
|
+
enduserId: testEnduser.id,
|
|
97
|
+
attachments: [{ secureName: fileForIndividual.secureName, type: 'file', name: fileForIndividual.name }],
|
|
98
|
+
})
|
|
99
|
+
contentRecordIds.push(contentIndividual.id)
|
|
100
|
+
|
|
101
|
+
await async_test(
|
|
102
|
+
'file attached to Individual content - assigned enduser CAN access',
|
|
103
|
+
async () => {
|
|
104
|
+
const result = await enduserSDK!.api.files.file_download_URL({ secureName: fileForIndividual.secureName })
|
|
105
|
+
return !!result?.downloadURL
|
|
106
|
+
},
|
|
107
|
+
{ onResult: (r) => r === true }
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
await async_test(
|
|
111
|
+
'file attached to Individual content - unassigned enduser CANNOT access',
|
|
112
|
+
async () => {
|
|
113
|
+
try {
|
|
114
|
+
await otherEnduserSDK!.api.files.file_download_URL({ secureName: fileForIndividual.secureName })
|
|
115
|
+
return false
|
|
116
|
+
} catch (err) {
|
|
117
|
+
return true
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
{ onResult: (r) => r === true }
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
// ===== Test 3: File not attached to any managed content - enduser CANNOT access =====
|
|
124
|
+
const fileNoContent = await uploadFile('mcr-file-no-content.txt')
|
|
125
|
+
|
|
126
|
+
await async_test(
|
|
127
|
+
'file not attached to any managed content - enduser CANNOT access',
|
|
128
|
+
async () => {
|
|
129
|
+
try {
|
|
130
|
+
await enduserSDK!.api.files.file_download_URL({ secureName: fileNoContent.secureName })
|
|
131
|
+
return false
|
|
132
|
+
} catch (err) {
|
|
133
|
+
return true
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{ onResult: (r) => r === true }
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
// ===== Test 4: File with enduserId set - existing behavior preserved =====
|
|
140
|
+
const fileWithEnduser = await uploadFile('mcr-file-with-enduser.txt', { enduserId: testEnduser.id })
|
|
141
|
+
|
|
142
|
+
await async_test(
|
|
143
|
+
'file with enduserId set - enduser CAN access (no fallback needed)',
|
|
144
|
+
async () => {
|
|
145
|
+
const result = await enduserSDK!.api.files.file_download_URL({ secureName: fileWithEnduser.secureName })
|
|
146
|
+
return !!result?.downloadURL
|
|
147
|
+
},
|
|
148
|
+
{ onResult: (r) => r === true }
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
// ===== Test 5: File with publicRead: true - existing behavior preserved =====
|
|
152
|
+
const filePublic = await uploadFile('mcr-file-public.txt', { publicRead: true })
|
|
153
|
+
|
|
154
|
+
await async_test(
|
|
155
|
+
'file with publicRead - enduser CAN access',
|
|
156
|
+
async () => {
|
|
157
|
+
const result = await enduserSDK!.api.files.file_download_URL({ secureName: filePublic.secureName })
|
|
158
|
+
return !!result?.downloadURL
|
|
159
|
+
},
|
|
160
|
+
{ onResult: (r) => r === true }
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
console.log("All Managed Content File Access tests passed!")
|
|
164
|
+
|
|
165
|
+
} finally {
|
|
166
|
+
console.log("Cleaning up test data...")
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
for (const assignmentId of assignmentIds) {
|
|
170
|
+
await sdk.api.managed_content_record_assignments.deleteOne(assignmentId).catch(() => {})
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for (const recordId of contentRecordIds) {
|
|
174
|
+
await sdk.api.managed_content_records.deleteOne(recordId).catch(() => {})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for (const fileId of fileIds) {
|
|
178
|
+
await sdk.api.files.deleteOne(fileId).catch(() => {})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (testEnduserId) {
|
|
182
|
+
await sdk.api.endusers.deleteOne(testEnduserId).catch(() => {})
|
|
183
|
+
}
|
|
184
|
+
if (otherEnduserId) {
|
|
185
|
+
await sdk.api.endusers.deleteOne(otherEnduserId).catch(() => {})
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log("Cleanup completed")
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error('Cleanup error:', error)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (require.main === module) {
|
|
196
|
+
console.log(`Using API URL: ${host}`)
|
|
197
|
+
const sdk = new Session({ host })
|
|
198
|
+
const sdkNonAdmin = new Session({ host })
|
|
199
|
+
|
|
200
|
+
const runTests = async () => {
|
|
201
|
+
await setup_tests(sdk, sdkNonAdmin)
|
|
202
|
+
await managed_content_file_access_tests({ sdk, sdkNonAdmin })
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
runTests()
|
|
206
|
+
.then(() => {
|
|
207
|
+
console.log("Managed content file access test suite completed successfully")
|
|
208
|
+
process.exit(0)
|
|
209
|
+
})
|
|
210
|
+
.catch((error) => {
|
|
211
|
+
console.error("Managed content file access test suite failed:", error)
|
|
212
|
+
process.exit(1)
|
|
213
|
+
})
|
|
214
|
+
}
|
|
@@ -176,6 +176,20 @@ export const organization_settings_duplicates_tests = async ({ sdk, sdkNonAdmin
|
|
|
176
176
|
},
|
|
177
177
|
}
|
|
178
178
|
}, { replaceObjectFields: true })
|
|
179
|
+
|
|
180
|
+
// === D. subdomain is readonly ===
|
|
181
|
+
const orgBefore = await sdk.api.organizations.getOne(orgId)
|
|
182
|
+
await async_test(
|
|
183
|
+
"subdomain field is readonly — update does not change persisted value",
|
|
184
|
+
async () => {
|
|
185
|
+
await sdk.api.organizations.updateOne(orgId, {
|
|
186
|
+
subdomain: `readonly-attempt-${Date.now()}`,
|
|
187
|
+
} as any).catch(() => undefined) // tolerate either silent-drop or unknown-field rejection
|
|
188
|
+
const orgAfter = await sdk.api.organizations.getOne(orgId)
|
|
189
|
+
return orgAfter.subdomain === orgBefore.subdomain
|
|
190
|
+
},
|
|
191
|
+
{ onResult: (unchanged: boolean) => unchanged === true }
|
|
192
|
+
)
|
|
179
193
|
}
|
|
180
194
|
|
|
181
195
|
// Allow running this test file independently
|
package/src/tests/tests.ts
CHANGED
|
@@ -50,7 +50,7 @@ import { appointment_rescheduled_trigger_tests } from "./api_tests/appointment_r
|
|
|
50
50
|
import { journey_error_branching_tests } from "./api_tests/journey_error_branching.test"
|
|
51
51
|
import { afteraction_day_of_month_delay_tests } from "./api_tests/afteraction_day_of_month_delay.test"
|
|
52
52
|
import { setup_tests } from "./setup"
|
|
53
|
-
import { evaluate_conditional_logic_for_enduser_fields, FORM_LOGIC_CALCULATED_FIELDS, get_care_team_primary, get_flattened_fields, get_next_reminder_timestamp, object_is_empty, replace_enduser_template_values, responses_satisfy_conditions, truncate_string, weighted_round_robin, YYYY_MM_DD_to_MM_DD_YYYY } from "@tellescope/utilities"
|
|
53
|
+
import { evaluate_conditional_logic_for_enduser_fields, FORM_LOGIC_CALCULATED_FIELDS, get_care_team_primary, get_flattened_fields, get_next_reminder_timestamp, object_is_empty, replace_enduser_template_values, replace_form_field_template_values, responses_satisfy_conditions, truncate_string, weighted_round_robin, YYYY_MM_DD_to_MM_DD_YYYY } from "@tellescope/utilities"
|
|
54
54
|
import { DEFAULT_OPERATIONS, PLACEHOLDER_ID, ZENDESK_INTEGRATIONS_TITLE, ZOOM_TITLE } from "@tellescope/constants"
|
|
55
55
|
import {
|
|
56
56
|
schema,
|
|
@@ -74,16 +74,20 @@ import {
|
|
|
74
74
|
|
|
75
75
|
import fs from "fs"
|
|
76
76
|
import { load_inbox_data_tests } from "./api_tests/load_inbox_data.test";
|
|
77
|
+
import { eom_procedure_codes_tests } from "./api_tests/eom_procedure_codes.test";
|
|
78
|
+
import { cross_org_api_key_tests } from "./api_tests/cross_org_api_key.test";
|
|
77
79
|
import { custom_dashboards_tests } from "./api_tests/custom_dashboards.test";
|
|
78
80
|
import { message_assignment_trigger_tests } from "./api_tests/message_assignment_trigger.test";
|
|
79
81
|
import { time_tracks_tests, time_tracks_historical_tests, time_tracks_correction_tests, time_tracks_review_tests, time_tracks_lock_tests, time_tracks_edge_case_tests } from "./api_tests/time_tracks.test";
|
|
80
82
|
import { monthly_availability_restrictions_tests } from "./api_tests/monthly_availability_restrictions.test";
|
|
81
83
|
import { calendar_event_limits_tests } from "./api_tests/calendar_event_limits.test";
|
|
82
84
|
import { custom_aggregation_tests } from "./api_tests/custom_aggregation.test";
|
|
85
|
+
import { chats_analytics_tests } from "./api_tests/chats_analytics.test";
|
|
83
86
|
import { no_access_permission_checks_tests } from "./api_tests/no_access_permission_checks.test";
|
|
84
87
|
import { field_redaction_tests } from "./api_tests/field_redaction.test";
|
|
85
88
|
import { bulk_assignment_tests } from "./api_tests/bulk_assignment.test";
|
|
86
89
|
import { managed_content_enduser_access_tests } from "./api_tests/managed_content_enduser_access.test";
|
|
90
|
+
import { managed_content_file_access_tests } from "./api_tests/managed_content_file_access.test";
|
|
87
91
|
import { auto_merge_form_submission_tests } from "./api_tests/auto_merge_form_submission.test";
|
|
88
92
|
import { database_cascade_delete_tests } from "./api_tests/database_cascade_delete.test";
|
|
89
93
|
import { ai_conversations_tests } from "./api_tests/ai_conversations.test";
|
|
@@ -12903,6 +12907,87 @@ const replace_enduser_template_values_tests = async () => {
|
|
|
12903
12907
|
await sdk.api.endusers.deleteOne(enduser.id)
|
|
12904
12908
|
}
|
|
12905
12909
|
|
|
12910
|
+
const replace_form_field_template_values_tests = async () => {
|
|
12911
|
+
log_header("Replace Form Field Template Values Tests")
|
|
12912
|
+
|
|
12913
|
+
const enduserWithMultilineField = {
|
|
12914
|
+
fname: "Multi",
|
|
12915
|
+
lname: "Line",
|
|
12916
|
+
fields: { Locations: 'NYC\nSF\nLA' },
|
|
12917
|
+
} as Partial<Enduser>
|
|
12918
|
+
|
|
12919
|
+
// With escapeNewlinesAsHTMLBreaks: true — newlines in substituted value become <br />
|
|
12920
|
+
assert(
|
|
12921
|
+
replace_form_field_template_values(
|
|
12922
|
+
'<p>Locations: {{enduser.Locations}}</p>',
|
|
12923
|
+
{ enduser: enduserWithMultilineField, escapeNewlinesAsHTMLBreaks: true }
|
|
12924
|
+
) === '<p>Locations: NYC<br />SF<br />LA</p>',
|
|
12925
|
+
'fail escapeNewlinesAsHTMLBreaks true', 'escapeNewlinesAsHTMLBreaks true'
|
|
12926
|
+
)
|
|
12927
|
+
|
|
12928
|
+
// Default (option absent) — newlines preserved as \n
|
|
12929
|
+
assert(
|
|
12930
|
+
replace_form_field_template_values(
|
|
12931
|
+
'<p>Locations: {{enduser.Locations}}</p>',
|
|
12932
|
+
{ enduser: enduserWithMultilineField }
|
|
12933
|
+
) === '<p>Locations: NYC\nSF\nLA</p>',
|
|
12934
|
+
'fail default newline preserved', 'default newline preserved'
|
|
12935
|
+
)
|
|
12936
|
+
|
|
12937
|
+
// Explicit false — same as default
|
|
12938
|
+
assert(
|
|
12939
|
+
replace_form_field_template_values(
|
|
12940
|
+
'<p>Locations: {{enduser.Locations}}</p>',
|
|
12941
|
+
{ enduser: enduserWithMultilineField, escapeNewlinesAsHTMLBreaks: false }
|
|
12942
|
+
) === '<p>Locations: NYC\nSF\nLA</p>',
|
|
12943
|
+
'fail escapeNewlinesAsHTMLBreaks false', 'escapeNewlinesAsHTMLBreaks false'
|
|
12944
|
+
)
|
|
12945
|
+
|
|
12946
|
+
// \n in original template (not in substituted value) is left alone
|
|
12947
|
+
assert(
|
|
12948
|
+
replace_form_field_template_values(
|
|
12949
|
+
'<p>Header</p>\n<p>{{enduser.fname}}</p>',
|
|
12950
|
+
{ enduser: enduserWithMultilineField, escapeNewlinesAsHTMLBreaks: true }
|
|
12951
|
+
) === '<p>Header</p>\n<p>Multi</p>',
|
|
12952
|
+
'fail template newline untouched', 'template newline untouched'
|
|
12953
|
+
)
|
|
12954
|
+
|
|
12955
|
+
// Single-line value unaffected when option is enabled
|
|
12956
|
+
assert(
|
|
12957
|
+
replace_form_field_template_values(
|
|
12958
|
+
'<p>Hello {{enduser.fname}}</p>',
|
|
12959
|
+
{ enduser: enduserWithMultilineField, escapeNewlinesAsHTMLBreaks: true }
|
|
12960
|
+
) === '<p>Hello Multi</p>',
|
|
12961
|
+
'fail single-line value', 'single-line value'
|
|
12962
|
+
)
|
|
12963
|
+
|
|
12964
|
+
// Substituted value containing literal two-char \n escape sequence is also converted
|
|
12965
|
+
const enduserWithLiteralEscapeField = {
|
|
12966
|
+
fname: "Multi",
|
|
12967
|
+
fields: { Locations: 'NYC\\nSF\\nLA' },
|
|
12968
|
+
} as Partial<Enduser>
|
|
12969
|
+
assert(
|
|
12970
|
+
replace_form_field_template_values(
|
|
12971
|
+
'<p>Locations: {{enduser.Locations}}</p>',
|
|
12972
|
+
{ enduser: enduserWithLiteralEscapeField, escapeNewlinesAsHTMLBreaks: true }
|
|
12973
|
+
) === '<p>Locations: NYC<br />SF<br />LA</p>',
|
|
12974
|
+
'fail literal \\n escape in substituted value', 'literal \\n escape in substituted value'
|
|
12975
|
+
)
|
|
12976
|
+
|
|
12977
|
+
// Substituted value with \r\n is also converted (single break per CRLF, not two)
|
|
12978
|
+
const enduserWithCRLFField = {
|
|
12979
|
+
fname: "Multi",
|
|
12980
|
+
fields: { Locations: 'NYC\r\nSF\r\nLA' },
|
|
12981
|
+
} as Partial<Enduser>
|
|
12982
|
+
assert(
|
|
12983
|
+
replace_form_field_template_values(
|
|
12984
|
+
'<p>Locations: {{enduser.Locations}}</p>',
|
|
12985
|
+
{ enduser: enduserWithCRLFField, escapeNewlinesAsHTMLBreaks: true }
|
|
12986
|
+
) === '<p>Locations: NYC<br />SF<br />LA</p>',
|
|
12987
|
+
'fail CRLF in substituted value', 'CRLF in substituted value'
|
|
12988
|
+
)
|
|
12989
|
+
}
|
|
12990
|
+
|
|
12906
12991
|
const inbox_threads_building_tests = async () => {
|
|
12907
12992
|
log_header("Inbox Thread Building Tests")
|
|
12908
12993
|
|
|
@@ -14199,8 +14284,14 @@ const ip_address_form_tests = async () => {
|
|
|
14199
14284
|
|
|
14200
14285
|
await enduser_conditional_logic_tests()
|
|
14201
14286
|
await replace_enduser_template_values_tests()
|
|
14287
|
+
await replace_form_field_template_values_tests()
|
|
14202
14288
|
await mfa_tests()
|
|
14203
14289
|
await setup_tests(sdk, sdkNonAdmin)
|
|
14290
|
+
await eom_procedure_codes_tests({ sdk, sdkNonAdmin })
|
|
14291
|
+
await cross_org_api_key_tests({ sdk, sdkNonAdmin })
|
|
14292
|
+
await organization_settings_duplicates_tests({ sdk, sdkNonAdmin })
|
|
14293
|
+
await enduser_session_invalidation_tests({ sdk, sdkNonAdmin })
|
|
14294
|
+
await chats_analytics_tests({ sdk, sdkNonAdmin })
|
|
14204
14295
|
await field_redaction_tests({ sdk, sdkNonAdmin })
|
|
14205
14296
|
await form_submitted_trigger_tests({ sdk, sdkNonAdmin })
|
|
14206
14297
|
await date_string_validation_tests({ sdk, sdkNonAdmin })
|
|
@@ -14208,7 +14299,6 @@ const ip_address_form_tests = async () => {
|
|
|
14208
14299
|
await automation_trigger_tests()
|
|
14209
14300
|
await integrations_redacted_tests({ sdk, sdkNonAdmin })
|
|
14210
14301
|
await mdb_sort_tests({ sdk, sdkNonAdmin })
|
|
14211
|
-
await organization_settings_duplicates_tests({ sdk, sdkNonAdmin })
|
|
14212
14302
|
await search_tests()
|
|
14213
14303
|
await time_tracks_tests({ sdk, sdkNonAdmin })
|
|
14214
14304
|
await time_tracks_historical_tests({ sdk, sdkNonAdmin })
|
|
@@ -14235,6 +14325,7 @@ const ip_address_form_tests = async () => {
|
|
|
14235
14325
|
await beluga_pharmacy_mappings_tests({ sdk, sdkNonAdmin })
|
|
14236
14326
|
await threadKeyTests()
|
|
14237
14327
|
await managed_content_enduser_access_tests({ sdk, sdkNonAdmin })
|
|
14328
|
+
await managed_content_file_access_tests({ sdk, sdkNonAdmin })
|
|
14238
14329
|
await afteraction_day_of_month_delay_tests({ sdk, sdkNonAdmin })
|
|
14239
14330
|
await bulk_assignment_tests({ sdk, sdkNonAdmin })
|
|
14240
14331
|
await formsort_tests()
|
|
@@ -14247,7 +14338,6 @@ const ip_address_form_tests = async () => {
|
|
|
14247
14338
|
await inbox_threads_loading_tests()
|
|
14248
14339
|
await load_inbox_data_tests({ sdk, sdkNonAdmin })
|
|
14249
14340
|
await enduser_observations_acknowledge_tests({ sdk, sdkNonAdmin })
|
|
14250
|
-
await enduser_session_invalidation_tests({ sdk, sdkNonAdmin })
|
|
14251
14341
|
await create_user_notifications_trigger_tests({ sdk })
|
|
14252
14342
|
await group_mms_active_tests()
|
|
14253
14343
|
await auto_reply_tests()
|
package/test_generated.pdf
CHANGED
|
Binary file
|