@tellescope/sdk 1.67.5 → 1.67.7

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.
@@ -690,6 +690,7 @@ const run_generated_tests = async <N extends ModelName>({ queries, model, name,
690
690
  () => queries.createOne(instance),
691
691
  { onResult: r => !!(_id = r.id) && (name === 'api_keys' || !!r.creator) && validateReturnType(returns.create, r, defaultValidation) }
692
692
  )
693
+ await wait(undefined, 25)
693
694
  await async_test(
694
695
  `log-${singularName} create`,
695
696
  () => sdk.api.user_logs.getOne({ resourceId: _id, resource: name, action: 'create' }),
@@ -702,6 +703,7 @@ const run_generated_tests = async <N extends ModelName>({ queries, model, name,
702
703
  () => queries.updateOne(_id, updates, { replaceObjectFields: true }),
703
704
  { onResult: u => typeof u === 'object' && u.id === _id }
704
705
  )
706
+ await wait(undefined, 25)
705
707
  await async_test(
706
708
  `log-${singularName} update`,
707
709
  () => sdk.api.user_logs.getOne({ resourceId: _id, resource: name, action: 'update' }),
@@ -743,6 +745,7 @@ const run_generated_tests = async <N extends ModelName>({ queries, model, name,
743
745
  () => queries.deleteOne(_id),
744
746
  passOnVoid
745
747
  )
748
+ await wait(undefined, 25)
746
749
  await async_test(
747
750
  `get-${singularName} (verify delete)`,
748
751
  () => queries.getOne(_id),
@@ -1501,6 +1504,7 @@ const files_tests = async () => {
1501
1504
  const enduser = await sdk.api.endusers.createOne({ email })
1502
1505
  await sdk.api.endusers.set_password({ id: enduser.id, password }).catch(console.error)
1503
1506
  await enduserSDK.authenticate(email, password).catch(console.error)
1507
+ await sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword) // to use new role, handle logout on role change
1504
1508
 
1505
1509
  const buff = buffer.Buffer.from('test file data')
1506
1510
 
@@ -1933,12 +1937,16 @@ const ticketEventTests = async () => {
1933
1937
 
1934
1938
  await sdk.api.endusers.updateOne(enduser.id, { journeys: { [journey.id]: 'Added' }})
1935
1939
  await sdk.api.endusers.updateOne(enduserWithTeam.id, { journeys: { [nullJourney.id]: 'Added (Null)' }})
1936
- await wait(undefined, 2250) // wait for tickets to be automatically created
1937
1940
 
1938
1941
  await async_test(
1939
1942
  `Tickets automatically created`,
1940
- () => sdk.api.tickets.getSome(),
1941
- { onResult: tickets => tickets?.length === 2 }
1943
+ () => pollForResults(
1944
+ sdk.api.tickets.getSome,
1945
+ tickets => tickets?.length === 2,
1946
+ 500,
1947
+ 15,
1948
+ ),
1949
+ passOnAnyResult
1942
1950
  )
1943
1951
 
1944
1952
  await async_test(
@@ -2050,11 +2058,15 @@ const removeFromJourneyTests = async () => {
2050
2058
  { onResult: e => e.journeys?.[journey.id] !== 'Delayed Step' }
2051
2059
  )
2052
2060
 
2053
- await wait(undefined, 4 * TEST_DELAY) // wait long enough for automation to process and delay to pass
2054
2061
  await async_test(
2055
2062
  `Sequenced action triggered`,
2056
- () => sdk.api.endusers.getOne(enduser.id),
2057
- { onResult: e => e.journeys?.[journey.id] === 'Delayed Step' }
2063
+ () => pollForResults(
2064
+ () => sdk.api.endusers.getOne(enduser.id),
2065
+ e => e.journeys?.[journey.id] === 'Delayed Step',
2066
+ TEST_DELAY,
2067
+ 15,
2068
+ ),
2069
+ passOnAnyResult
2058
2070
  )
2059
2071
 
2060
2072
  await Promise.all([
@@ -2238,11 +2250,15 @@ export const formUnsubmittedCancelConditionTest = async () => {
2238
2250
  })
2239
2251
 
2240
2252
  // allow fast followup to trigger
2241
- await wait(undefined, 4000) // allow background creation with generous pause
2242
2253
  await async_test(
2243
2254
  `formUnsubmitted event with short delay is triggered`,
2244
- () => sdk.api.endusers.getOne(enduser.id),
2245
- { onResult: e => e?.journeys?.[journey.id] === 'triggered again' }
2255
+ () => pollForResults(
2256
+ () => sdk.api.endusers.getOne(enduser.id),
2257
+ e => e?.journeys?.[journey.id] === 'triggered again',
2258
+ 1000,
2259
+ 10,
2260
+ ),
2261
+ passOnAnyResult
2246
2262
  )
2247
2263
 
2248
2264
  // trigger cancel conditions
@@ -2431,8 +2447,13 @@ export const formsUnsubmittedCancelConditionTest = async () => {
2431
2447
  )
2432
2448
  await async_test(
2433
2449
  `formResponses triggered after both forms submitted`,
2434
- () => sdk.api.endusers.getOne(enduser.id),
2435
- { onResult: e => e?.journeys?.[journey.id] === 'formsSubmitted' }
2450
+ () => pollForResults(
2451
+ () => sdk.api.endusers.getOne(enduser.id),
2452
+ e => e?.journeys?.[journey.id] === 'formsSubmitted',
2453
+ 500,
2454
+ 10,
2455
+ ),
2456
+ passOnAnyResult
2436
2457
  )
2437
2458
 
2438
2459
  await Promise.all([
@@ -2509,13 +2530,15 @@ export const formsUnsubmittedTest = async () => {
2509
2530
 
2510
2531
  const form_responses = await sdk.api.form_responses.getSome()
2511
2532
 
2512
- // allow fast followup to trigger
2513
- await wait(undefined, 5000) // allow background creation with generous pause
2514
-
2515
2533
  await async_test(
2516
2534
  `formsUnsubmitted handler worked`,
2517
- () => sdk.api.endusers.getOne(enduser.id),
2518
- { onResult: e => e?.journeys?.[journey.id] === 'triggered' }
2535
+ () => pollForResults(
2536
+ () => sdk.api.endusers.getOne(enduser.id),
2537
+ e => e?.journeys?.[journey.id] === 'triggered',
2538
+ 1000,
2539
+ 10
2540
+ ),
2541
+ passOnAnyResult,
2519
2542
  )
2520
2543
 
2521
2544
  // trigger cancel conditions
@@ -2723,27 +2746,37 @@ const addToJourneyTests = async () => {
2723
2746
  { onResult: e => e.journeys?.[journey.id] === '' || e.journeys?.[journey.id] === 'Root' }
2724
2747
  )
2725
2748
 
2726
- await wait(undefined, 4000) // allow onJourneyStart step to trigger
2749
+ // ensure that second step is generated before first is cancelled
2750
+ await pollForResults(
2751
+ sdk.api.automated_actions.getSome,
2752
+ es => es.length === 2,
2753
+ 100,
2754
+ 50,
2755
+ ),
2756
+
2727
2757
  await sdk.api.endusers.add_to_journey({ enduserIds: [enduser.id], journeyId: journey.id })
2728
2758
 
2759
+ await async_test(
2760
+ `Enduser correctly added and re-added`,
2761
+ () => pollForResults(
2762
+ sdk.api.automated_actions.getSome,
2763
+ es => (es.length === 4
2764
+ && es.filter(e => e.status === 'cancelled' && e.automationStepId === follow.id).length === 1 // one afterAction is cancelled
2765
+ && es.filter(e => e.status === 'active' && e.automationStepId === follow.id).length === 1 // one afterAction is still active
2766
+ && es.filter(e => e.status === 'finished' && e.automationStepId === root.id).length === 2 // two initial onJourneyStart
2767
+ ),
2768
+ 250,
2769
+ 40
2770
+ ),
2771
+ passOnAnyResult
2772
+ )
2773
+
2729
2774
  await async_test(
2730
2775
  `Enduser throttle journey add working`,
2731
2776
  () => sdk.api.endusers.add_to_journey({ enduserIds: [enduser.id], journeyId: journey.id, throttle: true }),
2732
2777
  handleAnyError
2733
2778
  )
2734
2779
 
2735
- await wait(undefined, 4000) // allow onJourneyStart step to trigger
2736
-
2737
- await async_test(
2738
- `Enduser correctly added and re-added`,
2739
- () => sdk.api.automated_actions.getSome(),
2740
- { onResult: es => es.length === 4
2741
- && es.filter(e => e.status === 'cancelled' && e.automationStepId === follow.id).length === 1 // one afterAction is cancelled
2742
- && es.filter(e => e.status === 'active' && e.automationStepId === follow.id).length === 1 // one afterAction is still active
2743
- && es.filter(e => e.status === 'finished' && e.automationStepId === root.id).length === 2 // two initial onJourneyStart
2744
- }
2745
- )
2746
-
2747
2780
  await Promise.all([
2748
2781
  sdk.api.journeys.deleteOne(journey.id),
2749
2782
  sdk.api.endusers.deleteOne(enduser.id),
@@ -2770,12 +2803,15 @@ const directAutomatedActionTest = async () => {
2770
2803
  journeyId: PLACEHOLDER_ID,
2771
2804
  })
2772
2805
 
2773
- await wait(undefined, 3000)
2774
-
2775
2806
  await async_test(
2776
2807
  `Enduser status set by manual automated action`,
2777
- () => sdk.api.endusers.getOne(enduser.id),
2778
- { onResult: e => e.journeys?.[PLACEHOLDER_ID] === 'Working' }
2808
+ () => pollForResults(
2809
+ () => sdk.api.endusers.getOne(enduser.id),
2810
+ e => e.journeys?.[PLACEHOLDER_ID] === 'Working',
2811
+ 1000,
2812
+ 10
2813
+ ),
2814
+ passOnAnyResult
2779
2815
  )
2780
2816
 
2781
2817
  await async_test(
@@ -4277,15 +4313,19 @@ const run_autoreply_test = async (title: string, { expectingAutoreply } : { expe
4277
4313
  )
4278
4314
 
4279
4315
  await enduserSDK.api.chats.createOne({ roomId: room.id, message: 'enduser' })
4280
- await wait (undefined, 50)
4281
4316
  await async_test(
4282
4317
  'Main test',
4283
- () => sdk.api.chats.getSome({ filter: { roomId: room.id }}),
4284
- { onResult: cs => (
4285
- expectingAutoreply
4286
- ? cs.length === 3
4287
- : cs.length === 2
4288
- ) }
4318
+ () => pollForResults(
4319
+ () => sdk.api.chats.getSome({ filter: { roomId: room.id }}),
4320
+ cs => (
4321
+ expectingAutoreply
4322
+ ? cs.length === 3
4323
+ : cs.length === 2
4324
+ ),
4325
+ 25,
4326
+ 10
4327
+ ),
4328
+ passOnAnyResult
4289
4329
  )
4290
4330
 
4291
4331
  await enduserSDK.api.chats.createOne({ roomId: room.id, message: 'enduser again' })
@@ -4602,11 +4642,15 @@ const wait_for_trigger_tests = async () => {
4602
4642
  ])
4603
4643
 
4604
4644
  // test trigger cleaned up on journey delete
4605
- await wait(undefined, 150)
4606
4645
  await async_test(
4607
- "Trigger did not fire while not journey",
4608
- () => sdk.api.automation_triggers.getOne(trigger.id),
4609
- handleAnyError
4646
+ "Trigger cleaned up by journey deletion",
4647
+ () => pollForResults(
4648
+ sdk.api.automation_triggers.getSome,
4649
+ results => !results.find(r => r.id === trigger.id),
4650
+ 100,
4651
+ 10,
4652
+ ),
4653
+ passOnAnyResult
4610
4654
  )
4611
4655
 
4612
4656
  // double-check that wait for trigger step triggers were deleted
@@ -4754,38 +4798,41 @@ const remove_from_journey_on_incoming_comms_tests = async () => {
4754
4798
 
4755
4799
  const room = await sdk.api.chat_rooms.createOne({ })
4756
4800
  await sdk.api.chats.createOne({ roomId: room.id, senderId: e1.id, message: 'cancel' })
4757
- await wait(undefined, 100)
4758
4801
 
4759
- console.log(jRemove.id, removeStep2.id, e1.id)
4760
4802
  await async_test(
4761
4803
  "Appropriate Automated Actions are cancelled on incoming message",
4762
- () => sdk.api.automated_actions.getSome(),
4763
- { onResult: actions => (
4764
- !!actions.find(a =>
4804
+ () => pollForResults(
4805
+ sdk.api.automated_actions.getSome,
4806
+ actions => (
4807
+ !!actions.find(a =>
4808
+ a.journeyId === jRemove.id
4809
+ && a.automationStepId === removeStep1.id
4810
+ && a.enduserId === e1.id
4811
+ && a.status === 'cancelled'
4812
+ )
4813
+ && !!actions.find(a =>
4765
4814
  a.journeyId === jRemove.id
4766
4815
  && a.automationStepId === removeStep1.id
4816
+ && a.enduserId === e2.id
4817
+ && a.status === 'active'
4818
+ )
4819
+ && !!actions.find(a =>
4820
+ a.journeyId === jDontRemove.id
4821
+ && a.automationStepId === dontRemoveStep1.id
4767
4822
  && a.enduserId === e1.id
4768
- && a.status === 'cancelled'
4823
+ && a.status === 'active'
4769
4824
  )
4770
- && !!actions.find(a =>
4771
- a.journeyId === jRemove.id
4772
- && a.automationStepId === removeStep1.id
4773
- && a.enduserId === e2.id
4774
- && a.status === 'active'
4775
- )
4776
- && !!actions.find(a =>
4777
- a.journeyId === jDontRemove.id
4778
- && a.automationStepId === dontRemoveStep1.id
4779
- && a.enduserId === e1.id
4780
- && a.status === 'active'
4781
- )
4782
- && !!actions.find(a =>
4783
- a.journeyId === jDontRemove.id
4784
- && a.automationStepId === dontRemoveStep1.id
4785
- && a.enduserId === e2.id
4786
- && a.status === 'active'
4787
- )
4788
- )}
4825
+ && !!actions.find(a =>
4826
+ a.journeyId === jDontRemove.id
4827
+ && a.automationStepId === dontRemoveStep1.id
4828
+ && a.enduserId === e2.id
4829
+ && a.status === 'active'
4830
+ )
4831
+ ),
4832
+ 25,
4833
+ 20,
4834
+ ),
4835
+ passOnAnyResult,
4789
4836
  )
4790
4837
 
4791
4838
  await sdk.api.journeys.handle_incoming_communication({ enduserId: e2.id })
@@ -4813,6 +4860,8 @@ const remove_from_journey_on_incoming_comms_tests = async () => {
4813
4860
  }
4814
4861
 
4815
4862
  const pdf_generation = async () => {
4863
+ log_header("pdf_generation Tests")
4864
+
4816
4865
  const e = await sdk.api.endusers.createOne({ fname: 'test' })
4817
4866
 
4818
4867
  // include lots of answers to ensure PDF height doesn't produce any cut-off
@@ -4847,7 +4896,6 @@ const pdf_generation = async () => {
4847
4896
 
4848
4897
  await Promise.all([
4849
4898
  sdk.api.endusers.deleteOne(e.id),
4850
- sdk.api.form_responses.deleteOne(fr.id),
4851
4899
  ])
4852
4900
  }
4853
4901
 
@@ -5030,12 +5078,15 @@ const nextReminderInMS_tests = async () => {
5030
5078
  }
5031
5079
 
5032
5080
  const pollForResults = async <T>(f: () => Promise<T>, evaluate: (r: T) => boolean, intervalInMS=500, iterations=20) => {
5081
+ let lastResult = undefined as any
5033
5082
  for (let i = 0; i < iterations; i++) {
5034
5083
  await wait(undefined, intervalInMS)
5035
5084
  const result = await f()
5085
+ lastResult = result
5036
5086
  if (evaluate(result)) return result
5037
5087
  }
5038
5088
 
5089
+ console.log(lastResult)
5039
5090
  throw new Error("failed pollForResults")
5040
5091
  }
5041
5092
 
@@ -5439,6 +5490,66 @@ const field_equals_trigger_tests = async () => {
5439
5490
  ])
5440
5491
  }
5441
5492
 
5493
+ export const no_chained_triggers_tests = async () => {
5494
+ log_header("No Chained Triggers Tests")
5495
+ const t1 = await sdk.api.automation_triggers.createOne({
5496
+ title: 't1', status: 'Active',
5497
+ event: {
5498
+ type: 'Field Equals',
5499
+ info: {
5500
+ field: 'fname',
5501
+ value: 'Trigger'
5502
+ },
5503
+ },
5504
+ action: {
5505
+ type: 'Add Tags',
5506
+ info: { tags: ['t1'] }
5507
+ }
5508
+ })
5509
+
5510
+ const t2 = await sdk.api.automation_triggers.createOne({
5511
+ title: 't2', status: 'Active',
5512
+ event: {
5513
+ type: 'Field Equals',
5514
+ info: {
5515
+ field: 'fname',
5516
+ value: '$exists'
5517
+ },
5518
+ },
5519
+ action: {
5520
+ type: 'Add Tags',
5521
+ info: { tags: ['t2'] }
5522
+ },
5523
+ enduserCondition: { $and: [ { condition: { tags: 't1' } } ] },
5524
+ })
5525
+
5526
+ // should only trigger t1, t1 would trigger t2 if allowed, but should not
5527
+ const enduser = await sdk.api.endusers.createOne({ fname: 'Trigger' })
5528
+
5529
+ await wait(undefined, 250)
5530
+ await async_test(
5531
+ `Trigger not activated by other trigger update`,
5532
+ () => sdk.api.endusers.getOne(enduser.id),
5533
+ { onResult: e => !!(!e.tags?.includes('t2') && e.tags?.includes('t1')) },
5534
+ )
5535
+
5536
+ // should cover both triggers now, which results in adding only the second tag
5537
+ await sdk.api.endusers.updateOne(enduser.id, { fname: "Updated" })
5538
+
5539
+ await wait(undefined, 250)
5540
+ await async_test(
5541
+ `Trigger activated directly`,
5542
+ () => sdk.api.endusers.getOne(enduser.id),
5543
+ { onResult: e => !!(e.tags?.includes('t1') && e.tags.includes('t2')) },
5544
+ )
5545
+
5546
+ await Promise.all([
5547
+ sdk.api.automation_triggers.deleteOne(t1.id),
5548
+ sdk.api.automation_triggers.deleteOne(t2.id),
5549
+ sdk.api.endusers.deleteOne(enduser.id)
5550
+ ])
5551
+ }
5552
+
5442
5553
  const NO_TEST = () => {}
5443
5554
  const tests: { [K in keyof ClientModelForName]: () => void } = {
5444
5555
  phone_trees: NO_TEST,
@@ -5579,6 +5690,7 @@ const validate_schema = () => {
5579
5690
  await mfa_tests()
5580
5691
  await setup_tests()
5581
5692
  await multi_tenant_tests() // should come right after setup tests
5693
+ await no_chained_triggers_tests()
5582
5694
  await field_equals_trigger_tests()
5583
5695
  await test_ticket_automation_assignment_and_optimization()
5584
5696
  await role_based_access_tests()
Binary file