@tellescope/sdk 1.4.27 → 1.4.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.env +3 -0
  2. package/lib/cjs/enduser.d.ts +6 -2
  3. package/lib/cjs/enduser.d.ts.map +1 -1
  4. package/lib/cjs/enduser.js +4 -4
  5. package/lib/cjs/enduser.js.map +1 -1
  6. package/lib/cjs/sdk.d.ts +14 -4
  7. package/lib/cjs/sdk.d.ts.map +1 -1
  8. package/lib/cjs/sdk.js +3 -4
  9. package/lib/cjs/sdk.js.map +1 -1
  10. package/lib/cjs/session.d.ts +3 -0
  11. package/lib/cjs/session.d.ts.map +1 -1
  12. package/lib/cjs/session.js +10 -7
  13. package/lib/cjs/session.js.map +1 -1
  14. package/lib/cjs/tests/socket_tests.d.ts.map +1 -1
  15. package/lib/cjs/tests/socket_tests.js +105 -66
  16. package/lib/cjs/tests/socket_tests.js.map +1 -1
  17. package/lib/cjs/tests/tests.d.ts.map +1 -1
  18. package/lib/cjs/tests/tests.js +255 -47
  19. package/lib/cjs/tests/tests.js.map +1 -1
  20. package/lib/esm/enduser.d.ts +6 -2
  21. package/lib/esm/enduser.d.ts.map +1 -1
  22. package/lib/esm/enduser.js +4 -4
  23. package/lib/esm/enduser.js.map +1 -1
  24. package/lib/esm/sdk.d.ts +14 -4
  25. package/lib/esm/sdk.d.ts.map +1 -1
  26. package/lib/esm/sdk.js +3 -4
  27. package/lib/esm/sdk.js.map +1 -1
  28. package/lib/esm/session.d.ts +4 -0
  29. package/lib/esm/session.d.ts.map +1 -1
  30. package/lib/esm/session.js +10 -7
  31. package/lib/esm/session.js.map +1 -1
  32. package/lib/esm/tests/socket_tests.d.ts.map +1 -1
  33. package/lib/esm/tests/socket_tests.js +105 -66
  34. package/lib/esm/tests/socket_tests.js.map +1 -1
  35. package/lib/esm/tests/tests.d.ts.map +1 -1
  36. package/lib/esm/tests/tests.js +255 -47
  37. package/lib/esm/tests/tests.js.map +1 -1
  38. package/lib/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +8 -8
  40. package/src/enduser.ts +12 -9
  41. package/src/sdk.ts +12 -3
  42. package/src/session.ts +8 -5
  43. package/src/tests/socket_tests.ts +47 -11
  44. package/src/tests/tests.ts +153 -4
@@ -23,7 +23,7 @@ export const get_sha256 = (s='') => createHash('sha256').update(s).digest('hex')
23
23
 
24
24
  const VERBOSE = true
25
25
 
26
- const AWAIT_SOCKET_DURATION = 300 // 25ms was generally passing for Redis, 1000ms should be upper limit of performance
26
+ const AWAIT_SOCKET_DURATION = 500 // 25ms was generally passing for Redis, 1000ms should be upper limit of performance
27
27
 
28
28
  const host = process.env.TEST_URL || 'http://localhost:8080'
29
29
  const [email, password] = [process.env.TEST_EMAIL, process.env.TEST_PASSWORD]
@@ -31,18 +31,26 @@ const [email2, password2] = [process.env.TEST_EMAIL_2, process.env.TEST_PASSWORD
31
31
  const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.env.NON_ADMIN_PASSWORD]
32
32
  const businessId = '60398b1131a295e64f084ff6'
33
33
 
34
+ const subUserEmail = process.env.SUB_EMAIL
35
+ const otherSubUserEmail = process.env.OTHER_SUB_EMAIL
36
+ const subSubUserEmail = process.env.SUB_SUB_EMAIL
37
+
34
38
  const user1 = new Session({ host, enableSocketLogging: VERBOSE })
35
39
  const user2 = new Session({ host, enableSocketLogging: VERBOSE })
36
40
  const sdkNonAdmin = new Session({ host })
41
+ const sdkSub = new Session({ host })
42
+ const sdkOtherSub = new Session({ host })
43
+ const sdkSubSub = new Session({ host })
37
44
 
38
45
  const enduserSDK = new EnduserSession({ host, businessId, enableSocketLogging: VERBOSE })
39
- if (!(email && password && email2 && password2 && nonAdminEmail && nonAdminPassword)) {
46
+ if (!(email && subUserEmail && otherSubUserEmail && subSubUserEmail && password && email2 && password2 && nonAdminEmail && nonAdminPassword)) {
40
47
  console.error("Set TEST_EMAIL and TEST_PASSWORD")
41
48
  process.exit(1)
42
49
  }
43
50
 
44
51
  // consistent passing at 150ms AWAIT SOCKET DURATION
45
52
  const basic_tests = async () => {
53
+ log_header("Basic Tests")
46
54
  const socket_events: Indexable[] = []
47
55
 
48
56
  user2.handle_events({
@@ -54,6 +62,7 @@ const basic_tests = async () => {
54
62
 
55
63
  const e = await user1.api.endusers.createOne({ email: "sockets@tellescope.com" })
56
64
  await wait(undefined, AWAIT_SOCKET_DURATION)
65
+
57
66
  assert(objects_equivalent(e, socket_events?.[0]?.[0]), 'inconsistent socket create', 'socket create')
58
67
 
59
68
  await user1.api.endusers.updateOne(e.id, { fname: 'Gary' })
@@ -69,6 +78,29 @@ const basic_tests = async () => {
69
78
  assert(objects_equivalent(es, socket_events?.[3]), 'inconsistent socket create many', 'socket create many')
70
79
  }
71
80
 
81
+ const sub_organization_tests = async () => {
82
+ log_header("Sub Organization Tests")
83
+ const root_events: Indexable[] = []
84
+ const sub_events: Indexable[] = []
85
+ const other_sub_events: Indexable[] = []
86
+ const sub_sub_events: Indexable[] = []
87
+
88
+ user1.handle_events({ 'created-endusers': es => root_events.push(es) })
89
+ sdkSub.handle_events({ 'created-endusers': es => sub_events.push(es) })
90
+ sdkOtherSub.handle_events({ 'created-endusers': es => other_sub_events.push(es) })
91
+ sdkSubSub.handle_events({ 'created-endusers': es => sub_sub_events.push(es) })
92
+
93
+ const e = await sdkSub.api.endusers.createOne({ email: "sockets_other@tellescope.com" })
94
+ await wait(undefined, AWAIT_SOCKET_DURATION)
95
+
96
+ assert(objects_equivalent(e, root_events?.[0]?.[0]), 'access error', 'root gets sub')
97
+ assert(objects_equivalent(e, sub_events?.[0]?.[0]), 'access error', 'sub gets sub')
98
+ assert(other_sub_events.length === 0, 'got access incorrectly', 'other sub no access')
99
+ assert(sub_sub_events.length === 0, 'got access incorrectly', 'sub sub no access')
100
+
101
+ await user1.api.endusers.deleteOne(e.id)
102
+ }
103
+
72
104
  const access_tests = async () => {
73
105
  const user1Events: Indexable[] = []
74
106
  const nonAdminEvents: Indexable[] = []
@@ -140,7 +172,7 @@ const access_tests = async () => {
140
172
 
141
173
  await user1.api.endusers.set_password({ id: unassignedEnduser.id, password: 'enduserPassword!' })
142
174
  await enduserSDK.authenticate(unassignedEnduser.email as string, 'enduserPassword!')
143
- await enduserSDK.connectSocket()
175
+ await wait(undefined, AWAIT_SOCKET_DURATION)
144
176
 
145
177
  enduserSDK.handle_events({
146
178
  'created-chat_rooms': rs => enduserEvents.push(...rs),
@@ -227,7 +259,6 @@ const access_tests = async () => {
227
259
 
228
260
  await user1.api.endusers.set_password({ id: assignedEnduser.id, password: 'enduserPassword!' })
229
261
  await enduserSDK.authenticate(assignedEnduser.email as string, 'enduserPassword!')
230
- await enduserSDK.authenticate_socket()
231
262
 
232
263
  enduserSDK.handle_events({
233
264
  'created-chats': rs => enduserEvents.push(...rs),
@@ -271,7 +302,7 @@ const enduser_tests = async () => {
271
302
  await user1.api.endusers.set_password({ id: enduser.id, password: 'enduserPassword!' })
272
303
 
273
304
  await enduserSDK.authenticate(enduser.email as string, 'enduserPassword!')
274
- await enduserSDK.connectSocket()
305
+ await wait(undefined, AWAIT_SOCKET_DURATION)
275
306
 
276
307
  const userEvents = [] as ChatMessage[]
277
308
  const enduserEvents = [] as ChatMessage[]
@@ -336,6 +367,7 @@ const deauthentication_tests = async (byTimeout=false) => {
336
367
  const enduser = await user1.api.endusers.createOne({ email: "socketenduser@tellescope.com" })
337
368
  await user1.api.endusers.set_password({ id: enduser.id, password: 'enduserPassword!' })
338
369
  await enduserSDK.authenticate(enduser.email as string, 'enduserPassword!', { durationInSeconds: byTimeout ? TEST_SESSION_DURATION : undefined })
370
+ await wait(undefined, AWAIT_SOCKET_DURATION)
339
371
 
340
372
  const room = await user1.api.chat_rooms.createOne({
341
373
  type: 'external',
@@ -409,7 +441,7 @@ const calendar_events = async () => {
409
441
  const enduser = await user1.api.endusers.createOne({ email: "socketenduser@tellescope.com" })
410
442
  await user1.api.endusers.set_password({ id: enduser.id, password: 'enduserPassword!' })
411
443
  await enduserSDK.authenticate(enduser.email as string, 'enduserPassword!')
412
- await enduserSDK.connectSocket()
444
+ await wait(undefined, AWAIT_SOCKET_DURATION)
413
445
 
414
446
  const userEvents = [] as ChatMessage[]
415
447
  const enduserEvents = [] as ChatMessage[]
@@ -437,14 +469,18 @@ const calendar_events = async () => {
437
469
  try {
438
470
  await user1.authenticate(email, password)
439
471
  await user1.reset_db()
440
- await user2.authenticate(email2, password2) // generate authToken + socket connection for API keyj
441
- await sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword)
442
472
 
443
- await user1.connectSocket()
444
- await user2.connectSocket()
445
- await sdkNonAdmin.connectSocket()
473
+ await Promise.all([
474
+ user2.authenticate(email2, password2), // generate authToken + socket connection for API keyj
475
+ sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword),
476
+ sdkSub.authenticate(subUserEmail, password),
477
+ sdkOtherSub.authenticate(otherSubUserEmail, password),
478
+ sdkSubSub.authenticate(subSubUserEmail, password),
479
+ ])
480
+ await wait(undefined, AWAIT_SOCKET_DURATION) // wait for socket connections
446
481
 
447
482
  await basic_tests()
483
+ await sub_organization_tests()
448
484
  await access_tests()
449
485
  await calendar_events()
450
486
  await enduser_tests()
@@ -53,6 +53,10 @@ const [email, password] = [process.env.TEST_EMAIL, process.env.TEST_PASSWORD]
53
53
  const [email2, password2] = [process.env.TEST_EMAIL_2, process.env.TEST_PASSWORD_2]
54
54
  const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.env.NON_ADMIN_PASSWORD]
55
55
 
56
+ const subUserEmail = process.env.SUB_EMAIL
57
+ const otherSubUserEmail = process.env.OTHER_SUB_EMAIL
58
+ const subSubUserEmail = process.env.SUB_SUB_EMAIL
59
+
56
60
  const userId = '60398b0231a295e64f084fd9'
57
61
  const businessId = '60398b1131a295e64f084ff6'
58
62
 
@@ -76,13 +80,17 @@ const businessId = '60398b1131a295e64f084ff6'
76
80
  // }
77
81
 
78
82
  const sdk = new Session({ host })
83
+ const sdkSub = new Session({ host })
84
+ const sdkOtherSub = new Session({ host })
85
+ const sdkSubSub = new Session({ host })
79
86
  const sdkOther = new Session({ host, apiKey: "ba745e25162bb95a795c5fa1af70df188d93c4d3aac9c48b34a5c8c9dd7b80f7" })
80
87
  const sdkNonAdmin = new Session({ host })
81
88
  const enduserSDK = new EnduserSession({ host, businessId })
89
+ const subEnduserSDK = new EnduserSession({ host, businessId,"organizationIds" : ["636d3c230067fc6b4c92c59c"] })
82
90
  const enduserSDKDifferentBusinessId = new EnduserSession({ host, businessId: '80398b1131a295e64f084ff6' })
83
91
  // const sdkOtherEmail = "sebass@tellescope.com"
84
92
 
85
- if (!(email && password && email2 && password2 && nonAdminEmail && nonAdminPassword)) {
93
+ if (!(email && subUserEmail && otherSubUserEmail && subSubUserEmail && password && email2 && password2 && nonAdminEmail && nonAdminPassword)) {
86
94
  console.error("Set TEST_EMAIL and TEST_PASSWORD")
87
95
  process.exit()
88
96
  }
@@ -118,6 +126,9 @@ const setup_tests = async () => {
118
126
  'authToken refresh'
119
127
  )
120
128
 
129
+ // reset nonAdmin role to a default non-admin
130
+ await sdk.api.users.updateOne(sdkNonAdmin.userInfo.id, { roles: ['Non-Admin'] }, { replaceObjectFields: true }),
131
+
121
132
  await async_test('reset_db', () => sdk.reset_db(), passOnVoid)
122
133
  }
123
134
 
@@ -168,6 +179,103 @@ const multi_tenant_tests = async () => {
168
179
  await sdkOther.api.endusers.deleteOne(e2.id)
169
180
  }
170
181
 
182
+ const sub_organization_tests = async() => {
183
+ log_header("Sub Organizations")
184
+
185
+ const rootEnduser = await sdk.api.endusers.createOne({ email: 'root@tellescope.com' })
186
+ const subEnduser = await sdkSub.api.endusers.createOne({ email: 'sub@tellescope.com' })
187
+ const subSubEnduser = await sdkSubSub.api.endusers.createOne({ email: 'subsub@tellescope.com' })
188
+
189
+ await async_test(`root get root`, () => sdk.api.endusers.getOne(rootEnduser.id), passOnAnyResult)
190
+ await async_test(`sub get root error`, () => sdkSub.api.endusers.getOne(rootEnduser.id), handleAnyError)
191
+ await async_test(`other sub get root error`, () => sdkOtherSub.api.endusers.getOne(rootEnduser.id), handleAnyError)
192
+ await async_test(`subsub get root error`, () => sdkSubSub.api.endusers.getOne(rootEnduser.id), handleAnyError)
193
+
194
+ await async_test(`root get sub`, () => sdk.api.endusers.getOne(subEnduser.id), passOnAnyResult)
195
+ await async_test(`sub get sub`, () => sdkSub.api.endusers.getOne(subEnduser.id), passOnAnyResult)
196
+ await async_test(`other sub get sub error`, () => sdkOtherSub.api.endusers.getOne(subEnduser.id), handleAnyError)
197
+ await async_test(`subsub get sub error`, () => sdkSubSub.api.endusers.getOne(subEnduser.id), handleAnyError)
198
+
199
+ await async_test(`root get subsub`, () => sdk.api.endusers.getOne(subSubEnduser.id), passOnAnyResult)
200
+ await async_test(`sub get subsub`, () => sdkSub.api.endusers.getOne(subSubEnduser.id), passOnAnyResult)
201
+ await async_test(`other sub get sub sub error`, () => sdkOtherSub.api.endusers.getOne(subSubEnduser.id), handleAnyError)
202
+ await async_test(`subsub get subsub`, () => sdkSubSub.api.endusers.getOne(subSubEnduser.id), passOnAnyResult)
203
+
204
+ await sdk.api.endusers.set_password({ id: rootEnduser.id, password })
205
+ await enduserSDK.authenticate(rootEnduser.email!, password)
206
+ await async_test(
207
+ `root enduser create`,
208
+ () => enduserSDK.api.engagement_events.createOne({ significance: 1, type: 'test', enduserId: rootEnduser.id }),
209
+ { onResult: t => t.businessId === rootEnduser.businessId && !t.organizationIds?.length },
210
+ )
211
+
212
+ await async_test(`enduser cannot update organizationIds`, () => enduserSDK.api.endusers.updateOne(enduserSDK.userInfo.id, { organizationIds: [] }), handleAnyError)
213
+ await async_test(`users cannot update organizationIds`, () => sdk.api.users.updateOne(sdk.userInfo.id, { organizationIds: [] }), handleAnyError)
214
+
215
+
216
+ await sdk.api.endusers.set_password({ id: subEnduser.id, password })
217
+ await enduserSDK.authenticate(subEnduser.email!, password)
218
+ await async_test(
219
+ `sub enduser create`,
220
+ () => enduserSDK.api.engagement_events.createOne({ significance: 1, type: 'test', enduserId: subEnduser.id }),
221
+ { onResult: t => t.businessId === rootEnduser.businessId && t.organizationIds?.length === 1 },
222
+ )
223
+
224
+ await sdk.api.endusers.set_password({ id: subSubEnduser.id, password })
225
+ await enduserSDK.authenticate(subSubEnduser.email!, password)
226
+ await async_test(
227
+ `subSub enduser create`,
228
+ () => enduserSDK.api.engagement_events.createOne({ significance: 1, type: 'test', enduserId: subSubEnduser.id }),
229
+ { onResult: t => t.businessId === rootEnduser.businessId && t.organizationIds?.length === 2},
230
+ )
231
+
232
+ await sdk.api.endusers.updateOne(rootEnduser.id, { organizationIds: subEnduser.organizationIds })
233
+ await async_test(`root get sub adjusted`, () => sdk.api.endusers.getOne(rootEnduser.id), passOnAnyResult)
234
+ await async_test(`sub get sub adjusted`, () => sdkSub.api.endusers.getOne(rootEnduser.id), passOnAnyResult)
235
+ await async_test(`other sub get sub adjusted error`, () => sdkOtherSub.api.endusers.getOne(rootEnduser.id), handleAnyError)
236
+ await async_test(`subsub get sub adjusted error`, () => sdkSubSub.api.endusers.getOne(rootEnduser.id), handleAnyError)
237
+
238
+ await async_test(
239
+ `push behavior for organization ids (push by default)`,
240
+ () => sdk.api.endusers.updateOne(rootEnduser.id, { organizationIds: subEnduser.organizationIds }),
241
+ // { onResult: e => e.organizationIds?.length === 2 * (subEnduser.organizationIds?.length ?? 0) },
242
+ handleAnyError // this is not going to pass, because pushing must result in organizationIds that match an existing organization
243
+ )
244
+ await async_test(
245
+ `push behavior for organization ids (replace working)`,
246
+ () => sdk.api.endusers.updateOne(rootEnduser.id, { organizationIds: subEnduser.organizationIds }, { replaceObjectFields: true }),
247
+ { onResult: e => e.organizationIds?.length === subEnduser.organizationIds?.length },
248
+ )
249
+
250
+ await Promise.all([
251
+ sdk.api.endusers.deleteOne(rootEnduser.id),
252
+ sdk.api.endusers.deleteOne(subEnduser.id),
253
+ sdk.api.endusers.deleteOne(subSubEnduser.id),
254
+ ])
255
+ }
256
+
257
+ const sub_organization_enduser_tests = async() => {
258
+ log_header("Sub Organizations (Enduser-Facing Tests)")
259
+
260
+ await enduserSDK.register({ email: 'root@tellescope.com', password })
261
+ await subEnduserSDK.register({ email: 'sub@tellescope.com', password })
262
+ await enduserSDK.authenticate('root@tellescope.com', password)
263
+ await subEnduserSDK.authenticate('sub@tellescope.com', password)
264
+
265
+ assert(!enduserSDK.userInfo.organizationIds?.length, 'bad root organizationIds', 'root auth org ids')
266
+ assert(subEnduserSDK.userInfo.organizationIds?.length === 1, 'bad sub organizationIds', 'sub auth org ids')
267
+
268
+ await async_test(`root get root`, () => sdk.api.endusers.getOne(enduserSDK.userInfo.id), passOnAnyResult)
269
+ await async_test(`sub get root error`, () => sdkSub.api.endusers.getOne(enduserSDK.userInfo.id), handleAnyError)
270
+ await async_test(`root get sub`, () => sdk.api.endusers.getOne(subEnduserSDK.userInfo.id), passOnAnyResult)
271
+ await async_test(`sub get sub`, () => sdkSub.api.endusers.getOne(subEnduserSDK.userInfo.id), passOnAnyResult)
272
+
273
+ await Promise.all([
274
+ sdk.api.endusers.deleteOne(enduserSDK.userInfo.id),
275
+ sdk.api.endusers.deleteOne(subEnduserSDK.userInfo.id),
276
+ ])
277
+ }
278
+
171
279
  const threadKeyTests = async () => {
172
280
  log_header("threadKey")
173
281
  const enduser = await sdk.api.endusers.createOne({ email: 'threadkeytests@tellescope.com' })
@@ -313,7 +421,7 @@ const generate_user_auth_tests = async () => {
313
421
 
314
422
  const { authToken, enduser } = await sdk.api.users.generate_auth_token({ id: e.id })
315
423
  if (!enduser) throw new Error("Didn't get enduser when generate_auth_token called")
316
- assert(!!authToken && !!enduser, 'invalid returned values', 'Generate authToken and get enduser')
424
+ assert(!!authToken && !!enduser, 'invalid returned values', 'Generate authTokea and get enduser')
317
425
  let { isAuthenticated } = await sdk.api.endusers.is_authenticated({ id: enduser.id, authToken })
318
426
  assert(isAuthenticated, 'invalid authToken generated for enduser', 'Generate authToken for enduser is valid')
319
427
  assert(
@@ -1799,13 +1907,13 @@ const removeFromJourneyTests = async () => {
1799
1907
 
1800
1908
  // add to journey to trigger initial action
1801
1909
  await sdk.api.endusers.updateOne(enduser.id, { journeys: { [journey.id]: 'New' } }, { replaceObjectFields: true })
1802
- await wait(undefined, 500)
1910
+ await wait(undefined, 250)
1803
1911
  await async_test(
1804
1912
  `Root action triggered (only root)`,
1805
1913
  () => sdk.api.automated_actions.getSome({ filter: { enduserId: enduser.id }}),
1806
1914
  { onResult: es => es.length === 1 }
1807
1915
  )
1808
- await wait(undefined, 500)
1916
+ await wait(undefined, 250)
1809
1917
  await async_test(
1810
1918
  `Next step not trigged early`,
1811
1919
  () => sdk.api.endusers.getOne(enduser.id),
@@ -3127,6 +3235,42 @@ export const role_based_access_permissions_tests = async () => {
3127
3235
  await sdk.api.users.updateOne(sdkNonAdmin.userInfo.id, { roles: [noEnduserAccessRole] }, { replaceObjectFields: true }),
3128
3236
  await sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword) // to use new role, handle logout on role change
3129
3237
 
3238
+ await async_test(
3239
+ 'non-root admin can read',
3240
+ () => sdkSub.api.role_based_access_permissions.getOne(rbap.id),
3241
+ passOnAnyResult,
3242
+ )
3243
+ await async_test(
3244
+ 'non-root admin can read many',
3245
+ () => sdkSub.api.role_based_access_permissions.getSome(),
3246
+ { onResult: rs => rs.length > 0 },
3247
+ )
3248
+ await async_test(
3249
+ 'non-root admin blocked create',
3250
+ () => sdkSub.api.role_based_access_permissions.createOne({
3251
+ role: noEnduserAccessRole,
3252
+ permissions: {
3253
+ endusers: {
3254
+ create: null,
3255
+ read: null,
3256
+ delete: null,
3257
+ update: null,
3258
+ }
3259
+ }
3260
+ }),
3261
+ handleAnyError
3262
+ )
3263
+ await async_test(
3264
+ 'non-root admin blocked update',
3265
+ () => sdkSub.api.role_based_access_permissions.updateOne(rbap.id, { role: 'updated'}),
3266
+ handleAnyError
3267
+ )
3268
+ await async_test(
3269
+ 'non-root admin blocked delete',
3270
+ () => sdkSub.api.role_based_access_permissions.deleteOne(rbap.id),
3271
+ handleAnyError
3272
+ )
3273
+
3130
3274
  await async_test(
3131
3275
  'enduser read access restriction working',
3132
3276
  () => sdkNonAdmin.api.endusers.getSome(),
@@ -3194,10 +3338,15 @@ const tests: { [K in keyof ClientModelForName]: () => void } = {
3194
3338
  try {
3195
3339
  await Promise.all([
3196
3340
  sdk.authenticate(email, password),
3341
+ sdkSub.authenticate(subUserEmail, password),
3342
+ sdkOtherSub.authenticate(otherSubUserEmail, password),
3343
+ sdkSubSub.authenticate(subSubUserEmail, password),
3197
3344
  sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword),
3198
3345
  ])
3199
3346
  await setup_tests()
3200
3347
  await multi_tenant_tests() // should come right after setup tests
3348
+ await sub_organization_enduser_tests()
3349
+ await sub_organization_tests()
3201
3350
  await self_serve_appointment_booking_tests()
3202
3351
  await filter_by_date_tests()
3203
3352
  await generate_user_auth_tests()