@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.
- 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/tests.d.ts +1 -0
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +274 -206
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/esm/sdk.d.ts +1 -0
- 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/tests.d.ts +1 -0
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +272 -205
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/sdk.ts +4 -0
- package/src/tests/tests.ts +182 -70
- package/test_generated.pdf +0 -0
package/src/tests/tests.ts
CHANGED
|
@@ -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
|
-
() =>
|
|
1941
|
-
|
|
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
|
-
() =>
|
|
2057
|
-
|
|
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
|
-
() =>
|
|
2245
|
-
|
|
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
|
-
() =>
|
|
2435
|
-
|
|
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
|
-
() =>
|
|
2518
|
-
|
|
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
|
-
|
|
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
|
-
() =>
|
|
2778
|
-
|
|
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
|
-
() =>
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
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
|
|
4608
|
-
() =>
|
|
4609
|
-
|
|
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
|
-
() =>
|
|
4763
|
-
|
|
4764
|
-
|
|
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 === '
|
|
4823
|
+
&& a.status === 'active'
|
|
4769
4824
|
)
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
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()
|
package/test_generated.pdf
CHANGED
|
Binary file
|