@tellescope/sdk 1.3.42 → 1.3.43

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.
@@ -1550,7 +1550,7 @@ const formEventTests = async () => {
1550
1550
 
1551
1551
  const triggerStep = await sdk.api.automation_steps.createOne({
1552
1552
  journeyId: journey.id,
1553
- event: { type: 'onJourneyStart', info: { } },
1553
+ events: [{ type: 'onJourneyStart', info: { } }],
1554
1554
  // in practice, this would send a form, so that the next step(s) could handle the response
1555
1555
  // but we don't want to send emails in testing, and can still attach this Id to a form response to test a trigger
1556
1556
  action: {
@@ -1560,10 +1560,10 @@ const formEventTests = async () => {
1560
1560
  })
1561
1561
  await sdk.api.automation_steps.createOne({
1562
1562
  journeyId: journey.id,
1563
- event: {
1563
+ events: [{
1564
1564
  type: 'formResponse',
1565
1565
  info: { automationStepId: triggerStep.id }
1566
- },
1566
+ }],
1567
1567
  action: {
1568
1568
  type: 'setEnduserStatus',
1569
1569
  info: { status: 'placeholder' },
@@ -1614,7 +1614,7 @@ const ticketEventTests = async () => {
1614
1614
 
1615
1615
  const root = await sdk.api.automation_steps.createOne({
1616
1616
  journeyId: journey.id,
1617
- event: { type: 'onJourneyStart', info: { } },
1617
+ events: [{ type: 'onJourneyStart', info: { } }],
1618
1618
  action: {
1619
1619
  type: 'createTicket',
1620
1620
  info: {
@@ -1630,7 +1630,7 @@ const ticketEventTests = async () => {
1630
1630
  })
1631
1631
  const nullRoot = await sdk.api.automation_steps.createOne({
1632
1632
  journeyId: nullJourney.id,
1633
- event: { type: 'onJourneyStart', info: { } },
1633
+ events: [{ type: 'onJourneyStart', info: { } }],
1634
1634
  action: {
1635
1635
  type: 'createTicket',
1636
1636
  info: {
@@ -1648,7 +1648,7 @@ const ticketEventTests = async () => {
1648
1648
  const createStep = (journeyId: string, automationStepId: string, closedForReason?: string ) => (
1649
1649
  sdk.api.automation_steps.createOne({
1650
1650
  journeyId,
1651
- event: { type: 'ticketCompleted', info: { automationStepId, closedForReason, } },
1651
+ events: [{ type: 'ticketCompleted', info: { automationStepId, closedForReason, } }],
1652
1652
  action: { type: 'setEnduserStatus', info: { status: closedForReason ?? 'Null' }, },
1653
1653
  })
1654
1654
  )
@@ -1664,7 +1664,7 @@ const ticketEventTests = async () => {
1664
1664
 
1665
1665
  await sdk.api.endusers.updateOne(enduser.id, { journeys: { [journey.id]: 'Added' }})
1666
1666
  await sdk.api.endusers.updateOne(enduserWithTeam.id, { journeys: { [nullJourney.id]: 'Added (Null)' }})
1667
- await wait(undefined, 2000) // wait for tickets to be automatically created
1667
+ await wait(undefined, 2200) // wait for tickets to be automatically created
1668
1668
 
1669
1669
  await async_test(
1670
1670
  `Tickets automatically created`,
@@ -1733,6 +1733,70 @@ const ticketEventTests = async () => {
1733
1733
  const removeFromJourneyTests = async () => {
1734
1734
  log_header("Remove from Journey")
1735
1735
 
1736
+ const journey = await sdk.api.journeys.createOne({ title: 'test journey'})
1737
+ const enduser = await sdk.api.endusers.createOne({ email: 'test@tellescope.com' })
1738
+
1739
+ const TEST_DELAY = 1000
1740
+
1741
+ const step = await (
1742
+ sdk.api.automation_steps.createOne({
1743
+ journeyId: journey.id,
1744
+ events: [{ type: 'onJourneyStart', info: { } }],
1745
+ action: { type: 'setEnduserStatus', info: { status: 'Root' }, },
1746
+ })
1747
+ )
1748
+ await (
1749
+ sdk.api.automation_steps.createOne({
1750
+ journeyId: journey.id,
1751
+ events: [{ type: 'afterAction', info: {
1752
+ automationStepId: step.id,
1753
+ delay: TEST_DELAY / 1000,
1754
+ delayInMS: TEST_DELAY,
1755
+ unit: 'Seconds',
1756
+ } }],
1757
+ action: { type: 'setEnduserStatus', info: { status: 'Delayed Step' }, },
1758
+ })
1759
+ )
1760
+ // test empty events step doesn't get triggered or cause errors
1761
+ await (
1762
+ sdk.api.automation_steps.createOne({
1763
+ journeyId: journey.id,
1764
+ events: [],
1765
+ action: { type: 'setEnduserStatus', info: { status: 'INVARIANT_VIOLATION' }, },
1766
+ })
1767
+ )
1768
+
1769
+ // add to journey to trigger initial action
1770
+ await sdk.api.endusers.updateOne(enduser.id, { journeys: { [journey.id]: 'New' } }, { replaceObjectFields: true })
1771
+ await wait(undefined, 250)
1772
+ await async_test(
1773
+ `Root action triggered (only root)`,
1774
+ () => sdk.api.automated_actions.getSome({ filter: { enduserId: enduser.id }}),
1775
+ { onResult: es => es.length === 1 }
1776
+ )
1777
+ await wait(undefined, 500)
1778
+ await async_test(
1779
+ `Next step not trigged early`,
1780
+ () => sdk.api.endusers.getOne(enduser.id),
1781
+ { onResult: e => e.journeys?.[journey.id] !== 'Delayed Step' }
1782
+ )
1783
+
1784
+ await wait(undefined, 2 * TEST_DELAY) // wait long enough for automation to process and delay to pass
1785
+ await async_test(
1786
+ `Sequenced action triggered`,
1787
+ () => sdk.api.endusers.getOne(enduser.id),
1788
+ { onResult: e => e.journeys?.[journey.id] === 'Delayed Step' }
1789
+ )
1790
+
1791
+ await Promise.all([
1792
+ sdk.api.journeys.deleteOne(journey.id),
1793
+ sdk.api.endusers.deleteOne(enduser.id),
1794
+ ])
1795
+ }
1796
+
1797
+ const sequenceTests = async () => {
1798
+ log_header("Automation Sequencing")
1799
+
1736
1800
  const journey = await sdk.api.journeys.createOne({ title: 'test journey'})
1737
1801
  const journey2 = await sdk.api.journeys.createOne({ title: 'other journey'})
1738
1802
 
@@ -1743,14 +1807,14 @@ const removeFromJourneyTests = async () => {
1743
1807
  const step = await (
1744
1808
  sdk.api.automation_steps.createOne({
1745
1809
  journeyId: journey.id,
1746
- event: { type: 'onJourneyStart', info: { } },
1810
+ events: [{ type: 'onJourneyStart', info: { } }],
1747
1811
  action: { type: 'setEnduserStatus', info: { status: 'Root' }, },
1748
1812
  })
1749
1813
  )
1750
1814
  const step2 = await (
1751
1815
  sdk.api.automation_steps.createOne({
1752
1816
  journeyId: journey2.id,
1753
- event: { type: 'onJourneyStart', info: { } },
1817
+ events: [{ type: 'onJourneyStart', info: { } }],
1754
1818
  action: { type: 'setEnduserStatus', info: { status: 'Root' }, },
1755
1819
  })
1756
1820
  )
@@ -1759,7 +1823,6 @@ const removeFromJourneyTests = async () => {
1759
1823
  sdk.api.automated_actions.createOne({
1760
1824
  journeyId,
1761
1825
  automationStepId: step.id,
1762
- cancelConditions: [],
1763
1826
  enduserId: enduserId ?? enduser.id,
1764
1827
  processAfter: Date.now() + 1000000, // add delay to make sure it doesn't happen
1765
1828
  status: 'active',
@@ -1800,8 +1863,128 @@ const removeFromJourneyTests = async () => {
1800
1863
  ])
1801
1864
  }
1802
1865
 
1866
+ export const cancelConditionsTests = async () => {
1867
+ log_header("Cancel Condition Tests")
1868
+
1869
+ const enduser = await sdk.api.endusers.createOne({ email: 'deletemeee@tellescope.com' })
1870
+ const journey = await sdk.api.journeys.createOne({ title: 'test journey '})
1871
+ const form = await sdk.api.forms.createOne({ title: 'test form' })
1872
+ const field = await sdk.api.form_fields.createOne({
1873
+ formId: form.id, title: 'question', type: 'string',
1874
+ previousFields: [{ type: 'root', info: {} }]
1875
+ })
1876
+
1877
+ // this action won't be fired, because patient isn't added to journey as part of tests
1878
+ const triggerStep = await sdk.api.automation_steps.createOne({
1879
+ journeyId: journey.id,
1880
+ events: [{ type: 'onJourneyStart', info: { } }],
1881
+ // in practice, this would send a form, so that the next step(s) could handle the response
1882
+ // but we don't want to send emails in testing, and can still attach this Id to a form response to test a trigger
1883
+ action: {
1884
+ type: 'setEnduserStatus',
1885
+ info: { status: 'start' },
1886
+ },
1887
+ })
1888
+
1889
+ const unsub = await sdk.api.automation_steps.createOne({
1890
+ journeyId: journey.id,
1891
+ events: [{
1892
+ type: 'formUnsubmitted',
1893
+ info: {
1894
+ automationStepId: triggerStep.id,
1895
+ delayInMS: 25, // should trigger
1896
+ delay: 0, unit: 'Seconds', // don't matter
1897
+ cancelConditions: [{ type: 'formResponse', info: { automationStepId: triggerStep.id }}]
1898
+ }
1899
+ }],
1900
+ action: {
1901
+ type: 'setEnduserStatus',
1902
+ info: { status: 'triggered' },
1903
+ },
1904
+ })
1905
+
1906
+ await sdk.api.automation_steps.createOne({
1907
+ journeyId: journey.id,
1908
+ events: [{
1909
+ type: 'afterAction',
1910
+ info: {
1911
+ automationStepId: unsub.id,
1912
+ delayInMS: 1000000, // ensure it doesn't trigger
1913
+ delay: 0, unit: 'Seconds', // don't matter
1914
+ cancelConditions: [{ type: 'formResponse', info: { automationStepId: triggerStep.id }}]
1915
+ }
1916
+ }],
1917
+ action: {
1918
+ type: 'setEnduserStatus',
1919
+ info: { status: 'violation 1' },
1920
+ },
1921
+ })
1922
+
1923
+ // a second followup to the unsub event (to create example of two actions with same cancel condition)
1924
+ await sdk.api.automation_steps.createOne({
1925
+ journeyId: journey.id,
1926
+ events: [{
1927
+ type: 'afterAction',
1928
+ info: {
1929
+ automationStepId: unsub.id,
1930
+ delayInMS: 1000000, // ensure it doesn't trigger
1931
+ delay: 0, unit: 'Seconds', // don't matter
1932
+ cancelConditions: [{ type: 'formResponse', info: { automationStepId: triggerStep.id }}]
1933
+ }
1934
+ }],
1935
+ action: {
1936
+ type: 'setEnduserStatus',
1937
+ info: { status: 'violation 2' },
1938
+ },
1939
+ })
1940
+
1941
+ const { accessCode } = await sdk.api.form_responses.prepare_form_response({
1942
+ formId: form.id,
1943
+ automationStepId: triggerStep.id, // must be included for trigger to happen
1944
+ enduserId: enduser.id
1945
+ })
1946
+
1947
+ // allow formUnsubmitted to trigger
1948
+ await wait(undefined, 2000) // allow background creation with generous pause
1949
+
1950
+ await async_test(
1951
+ `formUnsubmitted event with short delay is triggered`,
1952
+ () => sdk.api.endusers.getOne(enduser.id),
1953
+ { onResult: e => e?.journeys?.[journey.id] === 'triggered' }
1954
+ )
1955
+
1956
+ // trigger cancel conditions
1957
+ await sdk.api.form_responses.submit_form_response({ accessCode, automationStepId: triggerStep.id, responses: [{
1958
+ answer: {
1959
+ type: 'string',
1960
+ value: 'answer'
1961
+ },
1962
+ fieldId: field.id,
1963
+ fieldTitle: field.title,
1964
+ }] })
1965
+
1966
+ await wait(undefined, 2000) // allow background creation with generous pause
1967
+
1968
+ await async_test(
1969
+ `Cancel conditions work for followup`,
1970
+ () => sdk.api.automated_actions.getSome(),
1971
+ { onResult: as => as.length === 3
1972
+ && as.find(a => a.automationStepId === unsub.id)?.status === 'finished'
1973
+ && as.filter(a => a.status === 'cancelled').length === 2
1974
+ }
1975
+ )
1976
+
1977
+ await Promise.all([
1978
+ sdk.api.forms.deleteOne(form.id),
1979
+ sdk.api.journeys.deleteOne(journey.id),
1980
+ sdk.api.endusers.deleteOne(enduser.id)
1981
+ ])
1982
+ }
1983
+
1803
1984
  const automation_events_tests = async () => {
1804
1985
  log_header("Automation Events")
1986
+ await cancelConditionsTests()
1987
+ await sequenceTests()
1805
1988
  await formEventTests()
1806
1989
  await ticketEventTests()
1807
1990
  await removeFromJourneyTests()
@@ -2650,6 +2833,7 @@ export const databases_tests = async () => {
2650
2833
 
2651
2834
  const NO_TEST = () => {}
2652
2835
  const tests: { [K in keyof ClientModelForName]: () => void } = {
2836
+ automation_steps: automation_events_tests,
2653
2837
  calendar_event_templates: NO_TEST,
2654
2838
  databases: databases_tests,
2655
2839
  database_records: NO_TEST,
@@ -2675,7 +2859,6 @@ const tests: { [K in keyof ClientModelForName]: () => void } = {
2675
2859
  form_responses: form_response_tests,
2676
2860
  calendar_events: calendar_events_tests,
2677
2861
  webhooks: NO_TEST, // tested separately,
2678
- automation_steps: automation_events_tests,
2679
2862
  sequence_automations: NO_TEST,
2680
2863
  automated_actions: NO_TEST,
2681
2864
  enduser_status_updates: status_update_tests,
@@ -254,7 +254,7 @@ const test_automation_webhooks = async () => {
254
254
  }
255
255
  await sdk.api.automation_steps.createOne({
256
256
  journeyId: journey.id,
257
- event: { type: "onJourneyStart", info: {} },
257
+ events: [{ type: "onJourneyStart", info: {} }],
258
258
  action: testAction,
259
259
  })
260
260
 
@@ -286,9 +286,9 @@ let CALENDAR_EVENT_WEBHOOK_COUNT = 0 //
286
286
  const calendar_event_reminders_tests = async (isSubscribed: boolean) => {
287
287
  log_header(`Calendar Event Reminders, isSubscribed=${isSubscribed}`)
288
288
 
289
- const firstRemindAt = 0
289
+ const firstRemindAt = AUTOMATION_POLLING_DELAY_MS * 4
290
290
  const secondRemindAt = AUTOMATION_POLLING_DELAY_MS * 2
291
- const thirdRemindAt = AUTOMATION_POLLING_DELAY_MS * 4
291
+ const thirdRemindAt = AUTOMATION_POLLING_DELAY_MS * 0
292
292
  const sampleCalendarEventReminders: CalendarEvent['reminders'] = [
293
293
  {
294
294
  msBeforeStartTime: firstRemindAt,
@@ -309,7 +309,7 @@ const calendar_event_reminders_tests = async (isSubscribed: boolean) => {
309
309
  ]
310
310
  const calendarEvent = await sdk.api.calendar_events.createOne({
311
311
  durationInMinutes: 10,
312
- startTimeInMS: Date.now(),
312
+ startTimeInMS: Date.now() + firstRemindAt,
313
313
  title: "Test Notifications",
314
314
  reminders: sampleCalendarEventReminders,
315
315
  })