@tellescope/sdk 1.67.0 → 1.67.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.
@@ -10,6 +10,9 @@ import {
10
10
  UserDisplayInfo,
11
11
  } from "@tellescope/types-client"
12
12
  import {
13
+ CreateTicketActionInfo,
14
+ CreateTicketAssignmentStrategies,
15
+ CreateTicketAssignmentStrategy,
13
16
  FormResponseValue,
14
17
  ModelName,
15
18
  } from "@tellescope/types-models"
@@ -5026,8 +5029,303 @@ const nextReminderInMS_tests = async () => {
5026
5029
  ])
5027
5030
  }
5028
5031
 
5032
+ const pollForResults = async <T>(f: () => Promise<T[]>, intervalInMS=500, iterations=20) => {
5033
+ for (let i = 0; i < iterations; i++) {
5034
+ await wait(undefined, intervalInMS)
5035
+ const result = await f()
5036
+ if (result.length) return result
5037
+ }
5038
+
5039
+ throw new Error("failed pollForResults")
5040
+ }
5041
+
5029
5042
  const test_ticket_automation_assignment_and_optimization = async () => {
5030
- console.log((await sdk.api.users.getSome({ })).length)
5043
+ log_header("Ticket Automation / Assignment Tests")
5044
+
5045
+ const users = await sdk.api.users.getSome()
5046
+ if (users.length < 3) throw new Error("Must have at least 3 users to detect invalid assignment")
5047
+
5048
+ await sdk.api.users.updateOne(sdk.userInfo.id, { tags: ['tag1', 'tag2'] })
5049
+ await sdk.api.users.updateOne(sdkNonAdmin.userInfo.id, { tags: ['tag1', 'tag3'] })
5050
+
5051
+ const journey = await sdk.api.journeys.createOne({ title: "Testing" })
5052
+
5053
+ let foregroundTestCounter = 0
5054
+ const testForegroundTicket = async ({
5055
+ assignedTo,
5056
+ info,
5057
+ validOwners,
5058
+ enduser,
5059
+ closedForReason,
5060
+ testDelayedChild,
5061
+ } : {
5062
+ assignedTo: string[]
5063
+ info: Pick<CreateTicketActionInfo, 'assignmentStrategy' | 'defaultAssignee'>,
5064
+ validOwners: string[],
5065
+ closedForReason?: string,
5066
+ enduser?: Enduser,
5067
+ testDelayedChild?: boolean,
5068
+ }) => {
5069
+ const e = enduser || await sdk.api.endusers.createOne({ assignedTo, journeys: { [journey.id]: '' } })
5070
+
5071
+ const step = await sdk.api.automation_steps.createOne({
5072
+ action: { type: 'createTicket', info: { ...info, title: 'background ticket' } },
5073
+ events: [{
5074
+ type: 'ticketCompleted',
5075
+ info: closedForReason ? { automationStepId: PLACEHOLDER_ID, closedForReason } : { automationStepId: PLACEHOLDER_ID }
5076
+ }],
5077
+ journeyId: journey.id,
5078
+ })
5079
+ const statusStep = await sdk.api.automation_steps.createOne({
5080
+ action: { type: 'setEnduserStatus', info: { status: 'Test Status' } },
5081
+ events: [{
5082
+ type: 'ticketCompleted',
5083
+ info: closedForReason ? { automationStepId: PLACEHOLDER_ID, closedForReason } : { automationStepId: PLACEHOLDER_ID }
5084
+ }],
5085
+ journeyId: journey.id,
5086
+ })
5087
+ const child = await sdk.api.automation_steps.createOne({
5088
+ action: { type: 'setEnduserStatus', info: { status: 'Test Status' } },
5089
+ events: [{
5090
+ type: 'afterAction',
5091
+ info: {
5092
+ automationStepId: step.id,
5093
+ delay: 0, delayInMS: 0, unit: 'Days',
5094
+ }
5095
+ }],
5096
+ journeyId: journey.id,
5097
+ })
5098
+
5099
+ const ticket = await sdk.api.tickets.createOne({
5100
+ title: 'foreground ticket',
5101
+ enduserId: e.id,
5102
+ automationStepId: PLACEHOLDER_ID,
5103
+ journeyId: journey.id,
5104
+ owner: validOwners[0],
5105
+ closedForReason,
5106
+ })
5107
+
5108
+ await async_test(
5109
+ `Foreground ticket assignment ${++foregroundTestCounter}`,
5110
+ () => sdk.api.tickets.close_ticket({ ticketId: ticket.id, closedForReason }),
5111
+ { onResult: ({ generated }) => !!generated?.owner && validOwners.includes(generated.owner) }
5112
+ )
5113
+ await async_test(
5114
+ `Foreground ticket nop, no duplicates`,
5115
+ () => sdk.api.automated_actions.getSome({ filter: { automationStepId: step.id } }),
5116
+ { onResult: steps => steps.length === 1 && !!steps[0].isNOP }
5117
+ )
5118
+ await async_test(
5119
+ `Background action queued, no duplicates`,
5120
+ () => sdk.api.automated_actions.getSome({ filter: { automationStepId: statusStep.id } }),
5121
+ {
5122
+ onResult: steps => steps.length === 1 && !steps[0].isNOP
5123
+ }
5124
+ )
5125
+
5126
+ // verify that ticket generated by close_ticket goes on to generate its own delayed actions
5127
+ if (testDelayedChild) {
5128
+ await async_test(
5129
+ `Delayed child ticket`,
5130
+ () => pollForResults(() => sdk.api.automated_actions.getSome({ filter: { automationStepId: child.id } })),
5131
+ { onResult: steps => steps.length === 1 && !steps[0].isNOP }
5132
+ )
5133
+ }
5134
+
5135
+ await Promise.all([
5136
+ sdk.api.endusers.deleteOne(e.id),
5137
+ sdk.api.automation_steps.deleteOne(step.id),
5138
+ sdk.api.automation_steps.deleteOne(statusStep.id),
5139
+ sdk.api.automation_steps.deleteOne(child.id),
5140
+ ])
5141
+ }
5142
+
5143
+ await testForegroundTicket({
5144
+ assignedTo: [],
5145
+ info: {
5146
+ assignmentStrategy: { type: 'default', info: {} } ,
5147
+ defaultAssignee: sdk.userInfo.id
5148
+ },
5149
+ validOwners: [sdk.userInfo.id],
5150
+ testDelayedChild: true,
5151
+ })
5152
+ await testForegroundTicket({
5153
+ assignedTo: [],
5154
+ info: {
5155
+ assignmentStrategy: { type: 'default', info: {} } ,
5156
+ defaultAssignee: sdk.userInfo.id
5157
+ },
5158
+ validOwners: [sdk.userInfo.id],
5159
+ closedForReason: "closedForReason test",
5160
+ testDelayedChild: true,
5161
+ })
5162
+ await testForegroundTicket({
5163
+ assignedTo: [],
5164
+ info: {
5165
+ assignmentStrategy: { type: 'default', info: {} } ,
5166
+ defaultAssignee: sdkNonAdmin.userInfo.id
5167
+ },
5168
+ validOwners: [sdkNonAdmin.userInfo.id],
5169
+ })
5170
+ await testForegroundTicket({
5171
+ assignedTo: [],
5172
+ info: {
5173
+ assignmentStrategy: { type: 'previous-owner', info: {} } ,
5174
+ defaultAssignee: sdk.userInfo.id
5175
+ },
5176
+ validOwners: [sdkNonAdmin.userInfo.id],
5177
+ })
5178
+ await testForegroundTicket({
5179
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5180
+ info: {
5181
+ assignmentStrategy: { type: 'care-team-primary', info: {} } ,
5182
+ defaultAssignee: sdk.userInfo.id
5183
+ },
5184
+ validOwners: [sdkNonAdmin.userInfo.id],
5185
+ })
5186
+ await testForegroundTicket({
5187
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5188
+ info: {
5189
+ assignmentStrategy: { type: 'care-team-random', info: {} } ,
5190
+ defaultAssignee: sdk.userInfo.id
5191
+ },
5192
+ validOwners: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5193
+ })
5194
+ await testForegroundTicket({
5195
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5196
+ info: {
5197
+ assignmentStrategy: { type: 'by-tags', info: { qualifier: 'One Of', values: ['tag1']} } ,
5198
+ defaultAssignee: sdkNonAdmin.userInfo.id,
5199
+ },
5200
+ validOwners: [sdk.userInfo.id, sdkNonAdmin.userInfo.id, ],
5201
+ })
5202
+ await testForegroundTicket({
5203
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5204
+ info: {
5205
+ assignmentStrategy: { type: 'by-tags', info: { qualifier: 'One Of', values: ['tag2']} } ,
5206
+ defaultAssignee: sdkNonAdmin.userInfo.id
5207
+ },
5208
+ validOwners: [sdk.userInfo.id],
5209
+ })
5210
+ await testForegroundTicket({
5211
+ assignedTo: [],
5212
+ info: {
5213
+ assignmentStrategy: { type: 'by-tags', info: { qualifier: 'One Of', values: ['tag3']} } ,
5214
+ defaultAssignee: sdk.userInfo.id
5215
+ },
5216
+ validOwners: [sdkNonAdmin.userInfo.id],
5217
+ })
5218
+
5219
+
5220
+ let backgroundTestCounter = 0
5221
+ const testBackgroundTicket = async ({
5222
+ assignedTo,
5223
+ info,
5224
+ validOwners,
5225
+ enduser,
5226
+ } : {
5227
+ assignedTo: string[]
5228
+ info: Pick<CreateTicketActionInfo, 'assignmentStrategy' | 'defaultAssignee'>,
5229
+ validOwners: string[],
5230
+ enduser?: Enduser,
5231
+ }) => {
5232
+ const e = enduser || await sdk.api.endusers.createOne({ assignedTo })
5233
+ await sdk.api.automated_actions.createOne({
5234
+ action: { type: 'createTicket', info: { ...info, title: 'background ticket' } },
5235
+ automationStepId: PLACEHOLDER_ID,
5236
+ enduserId: e.id,
5237
+ event: { type: 'afterAction', info: { automationStepId: PLACEHOLDER_ID, delay: 0, delayInMS: 0, unit: 'Days' } },
5238
+ journeyId: journey.id,
5239
+ status: 'active',
5240
+ processAfter: Date.now(),
5241
+ })
5242
+
5243
+ await async_test(
5244
+ `Background ticket assignment ${++backgroundTestCounter}`,
5245
+ () => pollForResults(() => sdk.api.tickets.getSome({ filter: { enduserId: e.id, title: 'background ticket' } })),
5246
+ { onResult: ts => ts.length === 1 && !!ts[0].owner && validOwners.includes(ts[0].owner) }
5247
+ )
5248
+
5249
+ await sdk.api.endusers.deleteOne(e.id)
5250
+ }
5251
+
5252
+ await testBackgroundTicket({
5253
+ assignedTo: [],
5254
+ info: {
5255
+ assignmentStrategy: { type: 'default', info: {} } ,
5256
+ defaultAssignee: sdk.userInfo.id
5257
+ },
5258
+ validOwners: [sdk.userInfo.id],
5259
+ })
5260
+ await testBackgroundTicket({
5261
+ assignedTo: [],
5262
+ info: {
5263
+ assignmentStrategy: { type: 'default', info: {} } ,
5264
+ defaultAssignee: sdkNonAdmin.userInfo.id
5265
+ },
5266
+ validOwners: [sdkNonAdmin.userInfo.id],
5267
+ })
5268
+
5269
+ // ticket needs existing enduser, previous owner for test to work
5270
+ const enduser = await sdk.api.endusers.createOne({ fname: 'previous-owner-test'})
5271
+ await sdk.api.tickets.createOne({
5272
+ // title should be different than 'background test' so it doesn't create false positive test
5273
+ title: 'previous-owner-test', enduserId: enduser.id, journeyId: journey.id, owner: sdkNonAdmin.userInfo.id
5274
+ })
5275
+ await testBackgroundTicket({
5276
+ assignedTo: [],
5277
+ enduser,
5278
+ info: {
5279
+ assignmentStrategy: { type: 'previous-owner', info: {} } ,
5280
+ defaultAssignee: sdk.userInfo.id
5281
+ },
5282
+ validOwners: [sdkNonAdmin.userInfo.id],
5283
+ })
5284
+
5285
+ await testBackgroundTicket({
5286
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5287
+ info: {
5288
+ assignmentStrategy: { type: 'care-team-primary', info: {} } ,
5289
+ defaultAssignee: sdk.userInfo.id
5290
+ },
5291
+ validOwners: [sdkNonAdmin.userInfo.id],
5292
+ })
5293
+ await testBackgroundTicket({
5294
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5295
+ info: {
5296
+ assignmentStrategy: { type: 'care-team-random', info: {} } ,
5297
+ defaultAssignee: sdk.userInfo.id
5298
+ },
5299
+ validOwners: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5300
+ })
5301
+ await testBackgroundTicket({
5302
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5303
+ info: {
5304
+ assignmentStrategy: { type: 'by-tags', info: { qualifier: 'One Of', values: ['tag1']} } ,
5305
+ defaultAssignee: sdkNonAdmin.userInfo.id,
5306
+ },
5307
+ validOwners: [sdk.userInfo.id, sdkNonAdmin.userInfo.id, ],
5308
+ })
5309
+ await testBackgroundTicket({
5310
+ assignedTo: [sdkNonAdmin.userInfo.id, sdk.userInfo.id],
5311
+ info: {
5312
+ assignmentStrategy: { type: 'by-tags', info: { qualifier: 'One Of', values: ['tag2']} } ,
5313
+ defaultAssignee: sdkNonAdmin.userInfo.id
5314
+ },
5315
+ validOwners: [sdk.userInfo.id],
5316
+ })
5317
+ await testBackgroundTicket({
5318
+ assignedTo: [],
5319
+ info: {
5320
+ assignmentStrategy: { type: 'by-tags', info: { qualifier: 'One Of', values: ['tag3']} } ,
5321
+ defaultAssignee: sdk.userInfo.id
5322
+ },
5323
+ validOwners: [sdkNonAdmin.userInfo.id],
5324
+ })
5325
+
5326
+ return Promise.all([
5327
+ await sdk.api.journeys.deleteOne(journey.id)
5328
+ ])
5031
5329
  }
5032
5330
 
5033
5331
  const NO_TEST = () => {}
@@ -223,7 +223,7 @@ const endusers_tests = async (isSubscribed: boolean) => {
223
223
 
224
224
  const update = { assignedTo: [sdk.userInfo.id] }
225
225
  await sdk.api.endusers.updateOne(enduser.id, update)
226
-
226
+ await sdk.api.endusers.updateOne(enduser.id, { fields: { 'dontIncludeInWebhook': true } }, { dontSendWebhook: true })
227
227
  await check_next_webhook(
228
228
  a => {
229
229
  delete a.updates?.[0]?.recordBeforeUpdate.humanReadableId
Binary file