@tellescope/sdk 1.253.0 → 1.254.0
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 +4 -0
- package/lib/cjs/sdk.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/_tmp_bc_verify.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/_tmp_blank_status_verify.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/_tmp_followup_verify.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/_tmp_nonmatch_verify.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js +256 -0
- package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/field_redaction.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/field_redaction.test.js +112 -99
- package/lib/cjs/tests/api_tests/field_redaction.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js +168 -0
- package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/journey_error_branching.test.js +7 -2
- package/lib/cjs/tests/api_tests/journey_error_branching.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts +22 -0
- package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/resource_access_tags.test.js +488 -0
- package/lib/cjs/tests/api_tests/resource_access_tags.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +325 -0
- package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/time_tracks.test.d.ts +8 -0
- package/lib/cjs/tests/api_tests/time_tracks.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/time_tracks.test.js +638 -1
- package/lib/cjs/tests/api_tests/time_tracks.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/user_portal_settings.test.js +104 -28
- package/lib/cjs/tests/api_tests/user_portal_settings.test.js.map +1 -1
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +878 -200
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/esm/sdk.d.ts +4 -0
- package/lib/esm/sdk.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js +120 -0
- package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js.map +1 -0
- package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js +200 -0
- package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js.map +1 -0
- package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js +194 -0
- package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js.map +1 -0
- package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js +115 -0
- package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js.map +1 -0
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.js +252 -0
- package/lib/esm/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
- package/lib/esm/tests/api_tests/field_redaction.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/field_redaction.test.js +112 -99
- package/lib/esm/tests/api_tests/field_redaction.test.js.map +1 -1
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.js +164 -0
- package/lib/esm/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
- package/lib/esm/tests/api_tests/journey_error_branching.test.js +7 -2
- package/lib/esm/tests/api_tests/journey_error_branching.test.js.map +1 -1
- package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts +22 -0
- package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/resource_access_tags.test.js +484 -0
- package/lib/esm/tests/api_tests/resource_access_tags.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +321 -0
- package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
- package/lib/esm/tests/api_tests/time_tracks.test.d.ts +8 -0
- package/lib/esm/tests/api_tests/time_tracks.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/time_tracks.test.js +635 -0
- package/lib/esm/tests/api_tests/time_tracks.test.js.map +1 -1
- package/lib/esm/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/user_portal_settings.test.js +104 -28
- package/lib/esm/tests/api_tests/user_portal_settings.test.js.map +1 -1
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +879 -201
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/tests/api_tests/beluga_manual_sync.test.ts +159 -0
- package/src/tests/api_tests/field_redaction.test.ts +13 -0
- package/src/tests/api_tests/gcal_sync_retry.test.ts +104 -0
- package/src/tests/api_tests/journey_error_branching.test.ts +5 -1
- package/src/tests/api_tests/resource_access_tags.test.ts +303 -0
- package/src/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.ts +214 -0
- package/src/tests/api_tests/time_tracks.test.ts +420 -0
- package/src/tests/api_tests/user_portal_settings.test.ts +71 -1
- package/src/tests/tests.ts +520 -11
- package/test_generated.pdf +0 -0
package/src/tests/tests.ts
CHANGED
|
@@ -83,14 +83,16 @@ import { cross_org_api_key_tests } from "./api_tests/cross_org_api_key.test";
|
|
|
83
83
|
import { custom_dashboards_tests } from "./api_tests/custom_dashboards.test";
|
|
84
84
|
import { message_assignment_trigger_tests } from "./api_tests/message_assignment_trigger.test";
|
|
85
85
|
import { outbound_chat_sent_trigger_tests } from "./api_tests/outbound_chat_sent_trigger.test";
|
|
86
|
-
import { time_tracks_tests, time_tracks_historical_tests, time_tracks_correction_tests, time_tracks_review_tests, time_tracks_lock_tests, time_tracks_edge_case_tests } from "./api_tests/time_tracks.test";
|
|
86
|
+
import { time_tracks_tests, time_tracks_historical_tests, time_tracks_correction_tests, time_tracks_review_tests, time_tracks_lock_tests, time_tracks_edge_case_tests, time_tracks_resubmit_tests, time_tracks_appointment_duration_tests } from "./api_tests/time_tracks.test";
|
|
87
87
|
import { monthly_availability_restrictions_tests } from "./api_tests/monthly_availability_restrictions.test";
|
|
88
88
|
import { calendar_event_limits_tests } from "./api_tests/calendar_event_limits.test";
|
|
89
89
|
import { custom_aggregation_tests } from "./api_tests/custom_aggregation.test";
|
|
90
90
|
import { chats_analytics_tests } from "./api_tests/chats_analytics.test";
|
|
91
91
|
import { no_access_permission_checks_tests } from "./api_tests/no_access_permission_checks.test";
|
|
92
|
+
import { resource_access_tags_tests } from "./api_tests/resource_access_tags.test";
|
|
92
93
|
import { field_redaction_tests } from "./api_tests/field_redaction.test";
|
|
93
94
|
import { data_sync_redaction_bypass_tests } from "./api_tests/security/F-0001-data-sync-redaction-bypass.test";
|
|
95
|
+
import { enduser_write_restrictions_tests } from "./api_tests/security/F-0106-F-0110-enduser-write-restrictions.test";
|
|
94
96
|
import { ai_conversations_rbac_tests } from "./api_tests/security/F-0005-ai-conversations-rbac.test";
|
|
95
97
|
import { cascade_role_rename_cross_tenant_tests } from "./api_tests/security/F-0053-cascade-role-rename-cross-tenant.test";
|
|
96
98
|
import { self_admin_role_assignment_tests } from "./api_tests/security/F-0076-self-admin-role-assignment.test";
|
|
@@ -114,6 +116,7 @@ import { organization_settings_duplicates_tests } from "./api_tests/organization
|
|
|
114
116
|
import { calendar_events_bulk_update_tests } from "./api_tests/calendar_events_bulk_update.test";
|
|
115
117
|
import { openloop_webhooks_tests } from "./api_tests/openloop_webhooks.test";
|
|
116
118
|
import { beluga_pharmacy_mappings_tests } from "./api_tests/beluga_pharmacy_mappings.test";
|
|
119
|
+
import { beluga_manual_sync_tests } from "./api_tests/beluga_manual_sync.test";
|
|
117
120
|
import { mdi_webhooks_tests } from "./api_tests/mdi_webhooks.test";
|
|
118
121
|
import { account_switcher_tests } from "./api_tests/account_switcher.test";
|
|
119
122
|
import { set_fields_order_templates_tests } from "./api_tests/set_fields_order_templates.test";
|
|
@@ -3711,6 +3714,290 @@ const order_status_equals_tests = async () => {
|
|
|
3711
3714
|
])
|
|
3712
3715
|
}
|
|
3713
3716
|
|
|
3717
|
+
// Covers the "blank status matches any order status" behavior (Order Status Equals acting as "Order Status Changed").
|
|
3718
|
+
// Kept separate from order_status_equals_tests because a blank-status trigger would break that test's exact tag-count assertions.
|
|
3719
|
+
const order_status_blank_tests = async () => {
|
|
3720
|
+
log_header("Automation Trigger Tests (Order Status Equals - blank status)")
|
|
3721
|
+
|
|
3722
|
+
// A and A2 both fire on any status for BlankSource; the only difference is omitted vs. empty-string status.
|
|
3723
|
+
const A = await sdk.api.automation_triggers.createOne({
|
|
3724
|
+
event: { type: 'Order Status Equals', info: { source: 'BlankSource' } }, // status omitted entirely
|
|
3725
|
+
action: { type: 'Add Tags', info: { tags: ['AnyOmit'] }},
|
|
3726
|
+
status: 'Active',
|
|
3727
|
+
title: "Blank status (omitted)"
|
|
3728
|
+
})
|
|
3729
|
+
const A2 = await sdk.api.automation_triggers.createOne({
|
|
3730
|
+
event: { type: 'Order Status Equals', info: { source: 'BlankSource', status: '' } }, // explicit empty string
|
|
3731
|
+
action: { type: 'Add Tags', info: { tags: ['AnyEmpty'] }},
|
|
3732
|
+
status: 'Active',
|
|
3733
|
+
title: "Blank status (empty string)"
|
|
3734
|
+
})
|
|
3735
|
+
const B = await sdk.api.automation_triggers.createOne({
|
|
3736
|
+
event: { type: 'Order Status Equals', info: { source: 'BlankSource', status: '', skus: ['MATCH-SKU'] } },
|
|
3737
|
+
action: { type: 'Add Tags', info: { tags: ['BlankWithSku'] }},
|
|
3738
|
+
status: 'Active',
|
|
3739
|
+
title: "Blank status with SKU filter"
|
|
3740
|
+
})
|
|
3741
|
+
const C = await sdk.api.automation_triggers.createOne({
|
|
3742
|
+
event: { type: 'Order Status Equals', info: { source: 'OtherSource' } }, // blank status, different source
|
|
3743
|
+
action: { type: 'Add Tags', info: { tags: ['WrongSource'] }},
|
|
3744
|
+
status: 'Active',
|
|
3745
|
+
title: "Blank status, other source"
|
|
3746
|
+
})
|
|
3747
|
+
const D = await sdk.api.automation_triggers.createOne({
|
|
3748
|
+
event: { type: 'Order Status Equals', info: { source: 'BlankSource', status: 'Shipped' } }, // status-specific (regression)
|
|
3749
|
+
action: { type: 'Add Tags', info: { tags: ['ShippedOnly'] }},
|
|
3750
|
+
status: 'Active',
|
|
3751
|
+
title: "Status-specific (regression)"
|
|
3752
|
+
})
|
|
3753
|
+
// BA/BD exercise the separate bulk-create code path (createSome of 2+); kept on their own source so the
|
|
3754
|
+
// pre-existing "bulk ignores sku/protocol filters" divergence doesn't affect these assertions.
|
|
3755
|
+
const BA = await sdk.api.automation_triggers.createOne({
|
|
3756
|
+
event: { type: 'Order Status Equals', info: { source: 'BulkSource' } }, // blank status
|
|
3757
|
+
action: { type: 'Add Tags', info: { tags: ['BulkAny'] }},
|
|
3758
|
+
status: 'Active',
|
|
3759
|
+
title: "Bulk blank status"
|
|
3760
|
+
})
|
|
3761
|
+
const BD = await sdk.api.automation_triggers.createOne({
|
|
3762
|
+
event: { type: 'Order Status Equals', info: { source: 'BulkSource', status: 'Shipped' } }, // status-specific
|
|
3763
|
+
action: { type: 'Add Tags', info: { tags: ['BulkShipped'] }},
|
|
3764
|
+
status: 'Active',
|
|
3765
|
+
title: "Bulk status-specific"
|
|
3766
|
+
})
|
|
3767
|
+
// BD2's status matches NO order in the bulk batch below; backwards-compat: it must never fire (the query's $in
|
|
3768
|
+
// branch excludes it entirely, exactly as before the blank-status change).
|
|
3769
|
+
const BD2 = await sdk.api.automation_triggers.createOne({
|
|
3770
|
+
event: { type: 'Order Status Equals', info: { source: 'BulkSource', status: 'NeverInBatch' } },
|
|
3771
|
+
action: { type: 'Add Tags', info: { tags: ['BulkNever'] }},
|
|
3772
|
+
status: 'Active',
|
|
3773
|
+
title: "Bulk status-specific (absent from batch)"
|
|
3774
|
+
})
|
|
3775
|
+
// P: blank status composed with a protocol filter (proves blank works with non-SKU filters + the no-protocol branch)
|
|
3776
|
+
const P = await sdk.api.automation_triggers.createOne({
|
|
3777
|
+
event: { type: 'Order Status Equals', info: { source: 'BlankSource', status: '', protocols: ['Protocol-A'] } },
|
|
3778
|
+
action: { type: 'Add Tags', info: { tags: ['BlankProtocol'] }},
|
|
3779
|
+
status: 'Active',
|
|
3780
|
+
title: "Blank status with protocol filter"
|
|
3781
|
+
})
|
|
3782
|
+
|
|
3783
|
+
// Case 1: validation accepts triggers with no status / empty status (A and A2 created above without error)
|
|
3784
|
+
await async_test(
|
|
3785
|
+
"Trigger with omitted status was created",
|
|
3786
|
+
() => Promise.resolve(A),
|
|
3787
|
+
{ onResult: t => !!t.id && t.event.type === 'Order Status Equals' && !t.event.info.status }
|
|
3788
|
+
)
|
|
3789
|
+
await async_test(
|
|
3790
|
+
"Trigger with empty-string status was created",
|
|
3791
|
+
() => Promise.resolve(A2),
|
|
3792
|
+
{ onResult: t => !!t.id && t.event.type === 'Order Status Equals' && t.event.info.status === '' }
|
|
3793
|
+
)
|
|
3794
|
+
|
|
3795
|
+
// Case 2: blank status fires on an arbitrary status
|
|
3796
|
+
const e2 = await sdk.api.endusers.createOne({})
|
|
3797
|
+
await sdk.api.enduser_orders.createOne({ status: 'StatusOne', source: 'BlankSource', title: 'Title', externalId: 'blank-1', enduserId: e2.id })
|
|
3798
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3799
|
+
await async_test(
|
|
3800
|
+
"Blank status fires on arbitrary status (no other tags)",
|
|
3801
|
+
() => sdk.api.endusers.getOne(e2.id),
|
|
3802
|
+
{ onResult: e => !!(
|
|
3803
|
+
e.tags?.includes('AnyOmit')
|
|
3804
|
+
&& e.tags?.includes('AnyEmpty')
|
|
3805
|
+
&& !e.tags?.includes('BlankWithSku')
|
|
3806
|
+
&& !e.tags?.includes('WrongSource')
|
|
3807
|
+
&& !e.tags?.includes('ShippedOnly')
|
|
3808
|
+
) }
|
|
3809
|
+
)
|
|
3810
|
+
|
|
3811
|
+
// Case 3: blank status fires on a totally different status value (status-value-independent)
|
|
3812
|
+
const e3 = await sdk.api.endusers.createOne({})
|
|
3813
|
+
await sdk.api.enduser_orders.createOne({ status: 'totally-arbitrary-xyz', source: 'BlankSource', title: 'Title', externalId: 'blank-2', enduserId: e3.id })
|
|
3814
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3815
|
+
await async_test(
|
|
3816
|
+
"Blank status fires on a different arbitrary status",
|
|
3817
|
+
() => sdk.api.endusers.getOne(e3.id),
|
|
3818
|
+
{ onResult: e => !!(
|
|
3819
|
+
e.tags?.includes('AnyOmit')
|
|
3820
|
+
&& e.tags?.includes('AnyEmpty')
|
|
3821
|
+
) }
|
|
3822
|
+
)
|
|
3823
|
+
|
|
3824
|
+
// Case 4: source isolation - blank trigger does not fire for a different source
|
|
3825
|
+
const e4 = await sdk.api.endusers.createOne({})
|
|
3826
|
+
await sdk.api.enduser_orders.createOne({ status: 'StatusOne', source: 'DifferentSource', title: 'Title', externalId: 'blank-3', enduserId: e4.id })
|
|
3827
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3828
|
+
await async_test(
|
|
3829
|
+
"Blank status is still scoped to its source",
|
|
3830
|
+
() => sdk.api.endusers.getOne(e4.id),
|
|
3831
|
+
{ onResult: e => !!(
|
|
3832
|
+
!e.tags?.includes('AnyOmit')
|
|
3833
|
+
&& !e.tags?.includes('AnyEmpty')
|
|
3834
|
+
&& !e.tags?.includes('WrongSource') // C only matches OtherSource
|
|
3835
|
+
) }
|
|
3836
|
+
)
|
|
3837
|
+
|
|
3838
|
+
// Case 5a: other filters still enforced with blank status (sku mismatch)
|
|
3839
|
+
const e5 = await sdk.api.endusers.createOne({})
|
|
3840
|
+
await sdk.api.enduser_orders.createOne({ status: 'whatever', source: 'BlankSource', title: 'Title', externalId: 'blank-4', enduserId: e5.id, sku: 'NOPE' })
|
|
3841
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3842
|
+
await async_test(
|
|
3843
|
+
"Blank status + SKU filter does not fire on SKU mismatch",
|
|
3844
|
+
() => sdk.api.endusers.getOne(e5.id),
|
|
3845
|
+
{ onResult: e => !!(
|
|
3846
|
+
e.tags?.includes('AnyOmit')
|
|
3847
|
+
&& e.tags?.includes('AnyEmpty')
|
|
3848
|
+
&& !e.tags?.includes('BlankWithSku')
|
|
3849
|
+
) }
|
|
3850
|
+
)
|
|
3851
|
+
|
|
3852
|
+
// Case 5b: other filters still enforced with blank status (sku match)
|
|
3853
|
+
const e6 = await sdk.api.endusers.createOne({})
|
|
3854
|
+
await sdk.api.enduser_orders.createOne({ status: 'whatever', source: 'BlankSource', title: 'Title', externalId: 'blank-5', enduserId: e6.id, sku: 'MATCH-SKU' })
|
|
3855
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3856
|
+
await async_test(
|
|
3857
|
+
"Blank status + SKU filter fires on SKU match",
|
|
3858
|
+
() => sdk.api.endusers.getOne(e6.id),
|
|
3859
|
+
{ onResult: e => !!(
|
|
3860
|
+
e.tags?.includes('AnyOmit')
|
|
3861
|
+
&& e.tags?.includes('AnyEmpty')
|
|
3862
|
+
&& e.tags?.includes('BlankWithSku')
|
|
3863
|
+
) }
|
|
3864
|
+
)
|
|
3865
|
+
|
|
3866
|
+
// Case 6: update path + regression coexistence with a status-specific trigger
|
|
3867
|
+
const e7 = await sdk.api.endusers.createOne({})
|
|
3868
|
+
const o7 = await sdk.api.enduser_orders.createOne({ status: 'Created', source: 'BlankSource', title: 'Title', externalId: 'blank-6', enduserId: e7.id })
|
|
3869
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3870
|
+
await async_test(
|
|
3871
|
+
"Blank fires on create; status-specific (Shipped) does not yet",
|
|
3872
|
+
() => sdk.api.endusers.getOne(e7.id),
|
|
3873
|
+
{ onResult: e => !!(
|
|
3874
|
+
e.tags?.includes('AnyOmit')
|
|
3875
|
+
&& e.tags?.includes('AnyEmpty')
|
|
3876
|
+
&& !e.tags?.includes('ShippedOnly')
|
|
3877
|
+
) }
|
|
3878
|
+
)
|
|
3879
|
+
// update to a NON-matching status: blank fires again, but the status-specific trigger must stay un-fired
|
|
3880
|
+
await sdk.api.enduser_orders.updateOne(o7.id, { status: 'Delivered', externalId: 'blank-6-delivered' })
|
|
3881
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3882
|
+
await async_test(
|
|
3883
|
+
"Update to non-matching status: blank fires, status-specific (Shipped) does NOT fire",
|
|
3884
|
+
() => sdk.api.endusers.getOne(e7.id),
|
|
3885
|
+
{ onResult: e => !!(
|
|
3886
|
+
e.tags?.includes('AnyOmit') // proves the update event was processed
|
|
3887
|
+
&& e.tags?.includes('AnyEmpty')
|
|
3888
|
+
&& !e.tags?.includes('ShippedOnly') // 'Delivered' must not trigger the 'Shipped' trigger
|
|
3889
|
+
) }
|
|
3890
|
+
)
|
|
3891
|
+
// now update to the matching status: status-specific trigger fires
|
|
3892
|
+
await sdk.api.enduser_orders.updateOne(o7.id, { status: 'Shipped', externalId: 'blank-6-shipped' })
|
|
3893
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3894
|
+
await async_test(
|
|
3895
|
+
"Blank fires on update too; status-specific (Shipped) now fires",
|
|
3896
|
+
() => sdk.api.endusers.getOne(e7.id),
|
|
3897
|
+
{ onResult: e => !!(
|
|
3898
|
+
e.tags?.includes('AnyOmit')
|
|
3899
|
+
&& e.tags?.includes('AnyEmpty')
|
|
3900
|
+
&& e.tags?.includes('ShippedOnly')
|
|
3901
|
+
) }
|
|
3902
|
+
)
|
|
3903
|
+
|
|
3904
|
+
// Case 7: bulk create path (createSome of 2+) must honor blank status + status-specific selectivity.
|
|
3905
|
+
// This exercises a SEPARATE matching code path (handle_orders_create bulk branch) from single creates.
|
|
3906
|
+
const eb1 = await sdk.api.endusers.createOne({})
|
|
3907
|
+
const eb2 = await sdk.api.endusers.createOne({})
|
|
3908
|
+
const eb3 = await sdk.api.endusers.createOne({})
|
|
3909
|
+
await sdk.api.enduser_orders.createSome([
|
|
3910
|
+
{ status: 'StatusA', source: 'BulkSource', title: 'Title', externalId: 'bulk-1', enduserId: eb1.id },
|
|
3911
|
+
{ status: 'Shipped', source: 'BulkSource', title: 'Title', externalId: 'bulk-2', enduserId: eb2.id },
|
|
3912
|
+
{ status: 'StatusB', source: 'BulkSource', title: 'Title', externalId: 'bulk-3', enduserId: eb3.id },
|
|
3913
|
+
])
|
|
3914
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3915
|
+
await async_test(
|
|
3916
|
+
"Bulk create: blank fires on non-Shipped order; status-specific (matching + absent) do not",
|
|
3917
|
+
() => sdk.api.endusers.getOne(eb1.id),
|
|
3918
|
+
{ onResult: e => !!(e.tags?.includes('BulkAny') && !e.tags?.includes('BulkShipped') && !e.tags?.includes('BulkNever')) }
|
|
3919
|
+
)
|
|
3920
|
+
await async_test(
|
|
3921
|
+
"Bulk create: blank + matching status-specific fire on the Shipped order; absent-status one does not",
|
|
3922
|
+
() => sdk.api.endusers.getOne(eb2.id),
|
|
3923
|
+
{ onResult: e => !!(e.tags?.includes('BulkAny') && e.tags?.includes('BulkShipped') && !e.tags?.includes('BulkNever')) }
|
|
3924
|
+
)
|
|
3925
|
+
await async_test(
|
|
3926
|
+
"Bulk create: blank fires on the other non-Shipped order; status-specific (matching + absent) do not",
|
|
3927
|
+
() => sdk.api.endusers.getOne(eb3.id),
|
|
3928
|
+
{ onResult: e => !!(e.tags?.includes('BulkAny') && !e.tags?.includes('BulkShipped') && !e.tags?.includes('BulkNever')) }
|
|
3929
|
+
)
|
|
3930
|
+
|
|
3931
|
+
// Case 8: an order update that does NOT change status must not run the handler (true "status changed" semantic).
|
|
3932
|
+
const e8 = await sdk.api.endusers.createOne({})
|
|
3933
|
+
const o8 = await sdk.api.enduser_orders.createOne({ status: 'Shipped', source: 'BlankSource', title: 'Title', externalId: 'noChange-1', enduserId: e8.id })
|
|
3934
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3935
|
+
await async_test(
|
|
3936
|
+
"Setup: status-specific (Shipped) fired on create",
|
|
3937
|
+
() => sdk.api.endusers.getOne(e8.id),
|
|
3938
|
+
{ onResult: e => !!(e.tags?.includes('AnyOmit') && e.tags?.includes('ShippedOnly')) }
|
|
3939
|
+
)
|
|
3940
|
+
// clear tags (replaceObjectFields forces the empty array to actually replace)
|
|
3941
|
+
await sdk.api.endusers.updateOne(e8.id, { tags: [] }, { replaceObjectFields: true })
|
|
3942
|
+
// sanity-check the clear actually took, so a later failure points at re-firing rather than a broken clear
|
|
3943
|
+
await async_test(
|
|
3944
|
+
"Setup: tags cleared before non-status update",
|
|
3945
|
+
() => sdk.api.endusers.getOne(e8.id),
|
|
3946
|
+
{ onResult: e => !e.tags?.length }
|
|
3947
|
+
)
|
|
3948
|
+
// update a non-status field (status stays 'Shipped'); handler should early-return and re-add nothing.
|
|
3949
|
+
// If it wrongly fired, the blank triggers A/A2 would re-add AnyOmit/AnyEmpty, so empty tags proves non-firing.
|
|
3950
|
+
await sdk.api.enduser_orders.updateOne(o8.id, { tracking: 'tracking-123', externalId: 'noChange-1b' })
|
|
3951
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3952
|
+
await async_test(
|
|
3953
|
+
"Update with unchanged status does not fire any trigger",
|
|
3954
|
+
() => sdk.api.endusers.getOne(e8.id),
|
|
3955
|
+
{ onResult: e => !e.tags?.length }
|
|
3956
|
+
)
|
|
3957
|
+
|
|
3958
|
+
// Case 9: protocol filter with blank status - order without a protocol must not fire (the order.protocol ? : false branch)
|
|
3959
|
+
const e9 = await sdk.api.endusers.createOne({})
|
|
3960
|
+
await sdk.api.enduser_orders.createOne({ status: 'whatever', source: 'BlankSource', title: 'Title', externalId: 'proto-1', enduserId: e9.id })
|
|
3961
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3962
|
+
await async_test(
|
|
3963
|
+
"Blank + protocol filter does not fire when order has no protocol",
|
|
3964
|
+
() => sdk.api.endusers.getOne(e9.id),
|
|
3965
|
+
{ onResult: e => !!(e.tags?.includes('AnyOmit') && !e.tags?.includes('BlankProtocol')) }
|
|
3966
|
+
)
|
|
3967
|
+
const e10 = await sdk.api.endusers.createOne({})
|
|
3968
|
+
await sdk.api.enduser_orders.createOne({ status: 'whatever', source: 'BlankSource', title: 'Title', externalId: 'proto-2', enduserId: e10.id, protocol: 'Protocol-A' })
|
|
3969
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
3970
|
+
await async_test(
|
|
3971
|
+
"Blank + protocol filter fires when order protocol matches",
|
|
3972
|
+
() => sdk.api.endusers.getOne(e10.id),
|
|
3973
|
+
{ onResult: e => !!(e.tags?.includes('AnyOmit') && e.tags?.includes('BlankProtocol')) }
|
|
3974
|
+
)
|
|
3975
|
+
|
|
3976
|
+
await Promise.all([
|
|
3977
|
+
sdk.api.automation_triggers.deleteOne(A.id),
|
|
3978
|
+
sdk.api.automation_triggers.deleteOne(A2.id),
|
|
3979
|
+
sdk.api.automation_triggers.deleteOne(B.id),
|
|
3980
|
+
sdk.api.automation_triggers.deleteOne(C.id),
|
|
3981
|
+
sdk.api.automation_triggers.deleteOne(D.id),
|
|
3982
|
+
sdk.api.automation_triggers.deleteOne(BA.id),
|
|
3983
|
+
sdk.api.automation_triggers.deleteOne(BD.id),
|
|
3984
|
+
sdk.api.automation_triggers.deleteOne(BD2.id),
|
|
3985
|
+
sdk.api.automation_triggers.deleteOne(P.id),
|
|
3986
|
+
sdk.api.endusers.deleteOne(e2.id),
|
|
3987
|
+
sdk.api.endusers.deleteOne(e3.id),
|
|
3988
|
+
sdk.api.endusers.deleteOne(e4.id),
|
|
3989
|
+
sdk.api.endusers.deleteOne(e5.id),
|
|
3990
|
+
sdk.api.endusers.deleteOne(e6.id),
|
|
3991
|
+
sdk.api.endusers.deleteOne(e7.id),
|
|
3992
|
+
sdk.api.endusers.deleteOne(eb1.id),
|
|
3993
|
+
sdk.api.endusers.deleteOne(eb2.id),
|
|
3994
|
+
sdk.api.endusers.deleteOne(eb3.id),
|
|
3995
|
+
sdk.api.endusers.deleteOne(e8.id),
|
|
3996
|
+
sdk.api.endusers.deleteOne(e9.id),
|
|
3997
|
+
sdk.api.endusers.deleteOne(e10.id),
|
|
3998
|
+
])
|
|
3999
|
+
}
|
|
4000
|
+
|
|
3714
4001
|
const tag_added_tests = async () => {
|
|
3715
4002
|
log_header("Automation Trigger Tests (Tag Added)")
|
|
3716
4003
|
|
|
@@ -4296,12 +4583,208 @@ const assign_care_team_tests = async () => {
|
|
|
4296
4583
|
{ onResult: e => e.assignedTo?.length === 1 && e.primaryAssignee === e.assignedTo[0] }
|
|
4297
4584
|
)
|
|
4298
4585
|
|
|
4586
|
+
// restrictByState (state credentialing) tests
|
|
4587
|
+
await sdk.api.users.updateOne(sdk.userInfo.id, { credentialedStates: [{ state: 'CA' }] }, { replaceObjectFields: true })
|
|
4588
|
+
|
|
4589
|
+
const t4 = await sdk.api.automation_triggers.createOne({
|
|
4590
|
+
title: 't4',
|
|
4591
|
+
event: { type: 'Tag Added', info: { tag: 'Trigger State' } },
|
|
4592
|
+
action: {
|
|
4593
|
+
type: "Assign Care Team",
|
|
4594
|
+
info: {
|
|
4595
|
+
tags: { qualifier: 'One Of', values: ["Assignment"] },
|
|
4596
|
+
restrictByState: true,
|
|
4597
|
+
},
|
|
4598
|
+
},
|
|
4599
|
+
status: 'Active',
|
|
4600
|
+
})
|
|
4601
|
+
const e2 = await sdk.api.endusers.createOne({ state: 'CA' })
|
|
4602
|
+
const e3 = await sdk.api.endusers.createOne({ state: 'NY' })
|
|
4603
|
+
const e4 = await sdk.api.endusers.createOne({ })
|
|
4604
|
+
|
|
4605
|
+
await Promise.all([
|
|
4606
|
+
sdk.api.endusers.updateOne(e2.id, { tags: ['Trigger State'] }),
|
|
4607
|
+
sdk.api.endusers.updateOne(e3.id, { tags: ['Trigger State'] }),
|
|
4608
|
+
sdk.api.endusers.updateOne(e4.id, { tags: ['Trigger State'] }),
|
|
4609
|
+
])
|
|
4610
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
4611
|
+
await async_test(
|
|
4612
|
+
"Care team added for enduser in credentialed state",
|
|
4613
|
+
() => sdk.api.endusers.getOne(e2.id),
|
|
4614
|
+
{ onResult: e => e.assignedTo?.length === 1 }
|
|
4615
|
+
)
|
|
4616
|
+
await async_test(
|
|
4617
|
+
"No care team added for enduser in non-credentialed state",
|
|
4618
|
+
() => sdk.api.endusers.getOne(e3.id),
|
|
4619
|
+
{ onResult: e => !e.assignedTo?.length }
|
|
4620
|
+
)
|
|
4621
|
+
await async_test(
|
|
4622
|
+
"No care team added for enduser with unknown state",
|
|
4623
|
+
() => sdk.api.endusers.getOne(e4.id),
|
|
4624
|
+
{ onResult: e => !e.assignedTo?.length }
|
|
4625
|
+
)
|
|
4626
|
+
|
|
4627
|
+
// creating multiple appointments in a single request routes through bulk_handle_actions_for_triggers
|
|
4628
|
+
// (unlike Tag Added above, which uses the per-enduser handler), covering the bulk Assign Care Team
|
|
4629
|
+
// path with mixed enduser states in one batch
|
|
4630
|
+
const t5 = await sdk.api.automation_triggers.createOne({
|
|
4631
|
+
title: 't5',
|
|
4632
|
+
event: { type: 'Appointment Created', info: { titles: ['Bulk Assign State'] } },
|
|
4633
|
+
action: {
|
|
4634
|
+
type: "Assign Care Team",
|
|
4635
|
+
info: {
|
|
4636
|
+
tags: { qualifier: 'One Of', values: ["Assignment"] },
|
|
4637
|
+
restrictByState: true,
|
|
4638
|
+
setAsPrimary: true, // not yet supported in the bulk handler — see canary assertion below
|
|
4639
|
+
},
|
|
4640
|
+
},
|
|
4641
|
+
status: 'Active',
|
|
4642
|
+
})
|
|
4643
|
+
const e5 = await sdk.api.endusers.createOne({ state: 'CA' })
|
|
4644
|
+
const e6 = await sdk.api.endusers.createOne({ state: 'NY' })
|
|
4645
|
+
const e7 = await sdk.api.endusers.createOne({ })
|
|
4646
|
+
|
|
4647
|
+
const bulkEvents = (await sdk.api.calendar_events.createSome([
|
|
4648
|
+
{ title: 'Bulk Assign State', durationInMinutes: 30, startTimeInMS: Date.now(), attendees: [{ type: 'enduser', id: e5.id }] },
|
|
4649
|
+
{ title: 'Bulk Assign State', durationInMinutes: 30, startTimeInMS: Date.now(), attendees: [{ type: 'enduser', id: e6.id }] },
|
|
4650
|
+
{ title: 'Bulk Assign State', durationInMinutes: 30, startTimeInMS: Date.now(), attendees: [{ type: 'enduser', id: e7.id }] },
|
|
4651
|
+
])).created
|
|
4652
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
4653
|
+
await async_test(
|
|
4654
|
+
"(Bulk) Care team added for enduser in credentialed state",
|
|
4655
|
+
() => sdk.api.endusers.getOne(e5.id),
|
|
4656
|
+
{ onResult: e => e.assignedTo?.length === 1 }
|
|
4657
|
+
)
|
|
4658
|
+
// canary: the bulk handler doesn't implement setAsPrimary (the per-enduser handler does), so a set
|
|
4659
|
+
// primaryAssignee here means multi-event creates no longer route through the bulk handler (or
|
|
4660
|
+
// setAsPrimary was implemented there — update this test if so)
|
|
4661
|
+
await async_test(
|
|
4662
|
+
"(Bulk) Primary not set (bulk handler routing canary)",
|
|
4663
|
+
() => sdk.api.endusers.getOne(e5.id),
|
|
4664
|
+
{ onResult: e => !e.primaryAssignee }
|
|
4665
|
+
)
|
|
4666
|
+
await async_test(
|
|
4667
|
+
"(Bulk) No care team added for enduser in non-credentialed state",
|
|
4668
|
+
() => sdk.api.endusers.getOne(e6.id),
|
|
4669
|
+
{ onResult: e => !e.assignedTo?.length }
|
|
4670
|
+
)
|
|
4671
|
+
await async_test(
|
|
4672
|
+
"(Bulk) No care team added for enduser with unknown state",
|
|
4673
|
+
() => sdk.api.endusers.getOne(e7.id),
|
|
4674
|
+
{ onResult: e => !e.assignedTo?.length }
|
|
4675
|
+
)
|
|
4676
|
+
|
|
4677
|
+
// bulk path with restrictByState off: state should not matter (default behavior unchanged)
|
|
4678
|
+
const t6 = await sdk.api.automation_triggers.createOne({
|
|
4679
|
+
title: 't6',
|
|
4680
|
+
event: { type: 'Appointment Created', info: { titles: ['Bulk Assign Any'] } },
|
|
4681
|
+
action: {
|
|
4682
|
+
type: "Assign Care Team",
|
|
4683
|
+
info: {
|
|
4684
|
+
tags: { qualifier: 'One Of', values: ["Assignment"] },
|
|
4685
|
+
},
|
|
4686
|
+
},
|
|
4687
|
+
status: 'Active',
|
|
4688
|
+
})
|
|
4689
|
+
const bulkEventsAny = (await sdk.api.calendar_events.createSome([
|
|
4690
|
+
{ title: 'Bulk Assign Any', durationInMinutes: 30, startTimeInMS: Date.now(), attendees: [{ type: 'enduser', id: e6.id }] },
|
|
4691
|
+
{ title: 'Bulk Assign Any', durationInMinutes: 30, startTimeInMS: Date.now(), attendees: [{ type: 'enduser', id: e7.id }] },
|
|
4692
|
+
])).created
|
|
4693
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
4694
|
+
await async_test(
|
|
4695
|
+
"(Bulk, no restriction) Care team added for enduser in non-credentialed state",
|
|
4696
|
+
() => sdk.api.endusers.getOne(e6.id),
|
|
4697
|
+
{ onResult: e => e.assignedTo?.length === 1 }
|
|
4698
|
+
)
|
|
4699
|
+
await async_test(
|
|
4700
|
+
"(Bulk, no restriction) Care team added for enduser with unknown state",
|
|
4701
|
+
() => sdk.api.endusers.getOne(e7.id),
|
|
4702
|
+
{ onResult: e => e.assignedTo?.length === 1 }
|
|
4703
|
+
)
|
|
4704
|
+
|
|
4705
|
+
// limitToOneUser on both handler branches: with two matching users, exactly one is assigned
|
|
4706
|
+
const u2 = await sdk.api.users.createOne({
|
|
4707
|
+
email: `assign-care-team-limit-${Date.now()}@tellescope.example`, fname: 'Throwaway', lname: 'Assignment',
|
|
4708
|
+
} as any)
|
|
4709
|
+
await sdk.api.users.updateOne(u2.id, { tags: ['Assignment'], credentialedStates: [{ state: 'CA' }] }, { replaceObjectFields: true })
|
|
4710
|
+
|
|
4711
|
+
const t7 = await sdk.api.automation_triggers.createOne({
|
|
4712
|
+
title: 't7',
|
|
4713
|
+
event: { type: 'Tag Added', info: { tag: 'Trigger One' } },
|
|
4714
|
+
action: {
|
|
4715
|
+
type: "Assign Care Team",
|
|
4716
|
+
info: {
|
|
4717
|
+
tags: { qualifier: 'One Of', values: ["Assignment"] },
|
|
4718
|
+
restrictByState: true,
|
|
4719
|
+
limitToOneUser: true,
|
|
4720
|
+
},
|
|
4721
|
+
},
|
|
4722
|
+
status: 'Active',
|
|
4723
|
+
})
|
|
4724
|
+
const e8 = await sdk.api.endusers.createOne({ state: 'CA' })
|
|
4725
|
+
await sdk.api.endusers.updateOne(e8.id, { tags: ['Trigger One'] })
|
|
4726
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
4727
|
+
await async_test(
|
|
4728
|
+
"(limitToOneUser) Exactly one of multiple matching users assigned",
|
|
4729
|
+
() => sdk.api.endusers.getOne(e8.id),
|
|
4730
|
+
{ onResult: e => e.assignedTo?.length === 1 }
|
|
4731
|
+
)
|
|
4732
|
+
|
|
4733
|
+
const t8 = await sdk.api.automation_triggers.createOne({
|
|
4734
|
+
title: 't8',
|
|
4735
|
+
event: { type: 'Appointment Created', info: { titles: ['Bulk Assign One'] } },
|
|
4736
|
+
action: {
|
|
4737
|
+
type: "Assign Care Team",
|
|
4738
|
+
info: {
|
|
4739
|
+
tags: { qualifier: 'One Of', values: ["Assignment"] },
|
|
4740
|
+
restrictByState: true,
|
|
4741
|
+
limitToOneUser: true,
|
|
4742
|
+
},
|
|
4743
|
+
},
|
|
4744
|
+
status: 'Active',
|
|
4745
|
+
})
|
|
4746
|
+
const e9 = await sdk.api.endusers.createOne({ state: 'CA' })
|
|
4747
|
+
const e10 = await sdk.api.endusers.createOne({ state: 'CA' })
|
|
4748
|
+
const bulkEventsOne = (await sdk.api.calendar_events.createSome([
|
|
4749
|
+
{ title: 'Bulk Assign One', durationInMinutes: 30, startTimeInMS: Date.now(), attendees: [{ type: 'enduser', id: e9.id }] },
|
|
4750
|
+
{ title: 'Bulk Assign One', durationInMinutes: 30, startTimeInMS: Date.now(), attendees: [{ type: 'enduser', id: e10.id }] },
|
|
4751
|
+
])).created
|
|
4752
|
+
await wait(undefined, 500) // allow triggers to happen
|
|
4753
|
+
await async_test(
|
|
4754
|
+
"(Bulk, limitToOneUser) Exactly one of multiple matching users assigned",
|
|
4755
|
+
() => sdk.api.endusers.getOne(e9.id),
|
|
4756
|
+
{ onResult: e => e.assignedTo?.length === 1 }
|
|
4757
|
+
)
|
|
4758
|
+
await async_test(
|
|
4759
|
+
"(Bulk, limitToOneUser) Exactly one of multiple matching users assigned (second enduser)",
|
|
4760
|
+
() => sdk.api.endusers.getOne(e10.id),
|
|
4761
|
+
{ onResult: e => e.assignedTo?.length === 1 }
|
|
4762
|
+
)
|
|
4763
|
+
|
|
4299
4764
|
await Promise.all([
|
|
4300
|
-
sdk.api.users.updateOne(sdk.userInfo.id, { tags: [] }, { replaceObjectFields: true }),
|
|
4765
|
+
sdk.api.users.updateOne(sdk.userInfo.id, { tags: [], credentialedStates: [] }, { replaceObjectFields: true }),
|
|
4301
4766
|
sdk.api.endusers.deleteOne(e1.id),
|
|
4767
|
+
sdk.api.endusers.deleteOne(e2.id),
|
|
4768
|
+
sdk.api.endusers.deleteOne(e3.id),
|
|
4769
|
+
sdk.api.endusers.deleteOne(e4.id),
|
|
4770
|
+
sdk.api.endusers.deleteOne(e5.id),
|
|
4771
|
+
sdk.api.endusers.deleteOne(e6.id),
|
|
4772
|
+
sdk.api.endusers.deleteOne(e7.id),
|
|
4302
4773
|
sdk.api.automation_triggers.deleteOne(t1.id),
|
|
4303
4774
|
sdk.api.automation_triggers.deleteOne(t2.id),
|
|
4304
4775
|
sdk.api.automation_triggers.deleteOne(t3.id),
|
|
4776
|
+
sdk.api.endusers.deleteOne(e8.id),
|
|
4777
|
+
sdk.api.endusers.deleteOne(e9.id),
|
|
4778
|
+
sdk.api.endusers.deleteOne(e10.id),
|
|
4779
|
+
sdk.api.users.deleteOne(u2.id),
|
|
4780
|
+
sdk.api.automation_triggers.deleteOne(t4.id),
|
|
4781
|
+
sdk.api.automation_triggers.deleteOne(t5.id),
|
|
4782
|
+
sdk.api.automation_triggers.deleteOne(t6.id),
|
|
4783
|
+
sdk.api.automation_triggers.deleteOne(t7.id),
|
|
4784
|
+
sdk.api.automation_triggers.deleteOne(t8.id),
|
|
4785
|
+
...bulkEvents.map(e => sdk.api.calendar_events.deleteOne(e.id)),
|
|
4786
|
+
...bulkEventsAny.map(e => sdk.api.calendar_events.deleteOne(e.id)),
|
|
4787
|
+
...bulkEventsOne.map(e => sdk.api.calendar_events.deleteOne(e.id)),
|
|
4305
4788
|
])
|
|
4306
4789
|
}
|
|
4307
4790
|
|
|
@@ -5104,8 +5587,10 @@ const trigger_events_api_tests = async () => {
|
|
|
5104
5587
|
const automation_trigger_tests = async () => {
|
|
5105
5588
|
log_header("Automation Trigger Tests")
|
|
5106
5589
|
|
|
5590
|
+
await assign_care_team_tests()
|
|
5107
5591
|
await push_forms_to_portal_group_completion_tests({ sdk, sdkNonAdmin })
|
|
5108
5592
|
await order_status_equals_tests()
|
|
5593
|
+
await order_status_blank_tests()
|
|
5109
5594
|
await set_fields_order_templates_tests({ sdk, sdkNonAdmin })
|
|
5110
5595
|
await medication_added_trigger_tests({ sdk, sdkNonAdmin })
|
|
5111
5596
|
await appointment_cancelled_tests()
|
|
@@ -5118,7 +5603,6 @@ const automation_trigger_tests = async () => {
|
|
|
5118
5603
|
await trigger_events_api_tests()
|
|
5119
5604
|
await fields_changed_tests()
|
|
5120
5605
|
await field_equals_trigger_tests()
|
|
5121
|
-
await assign_care_team_tests()
|
|
5122
5606
|
await contact_created_tests()
|
|
5123
5607
|
await appointment_created_tests()
|
|
5124
5608
|
await tag_added_tests()
|
|
@@ -8664,8 +9148,11 @@ export const switch_to_related_contacts_tests = async () => {
|
|
|
8664
9148
|
() => pollForResults(
|
|
8665
9149
|
() => sdk.api.endusers.getOne(parent.id),
|
|
8666
9150
|
e => !!e.tags?.includes('Success'),
|
|
8667
|
-
|
|
8668
|
-
|
|
9151
|
+
// switchToRelatedContact (cycle 1) then the afterAction addEnduserTags (cycle 2) each wait a
|
|
9152
|
+
// full worker poll cycle (>= 8s, see worker pollingDelaySeconds), so ~16s worst case. Poll for
|
|
9153
|
+
// 30s (500ms x 60) to cover two cycles plus buffer; the old 10s window timed out flakily.
|
|
9154
|
+
500,
|
|
9155
|
+
60,
|
|
8669
9156
|
),
|
|
8670
9157
|
passOnAnyResult
|
|
8671
9158
|
)
|
|
@@ -11147,7 +11634,23 @@ const register_as_enduser_tests = async () => {
|
|
|
11147
11634
|
)
|
|
11148
11635
|
await async_test(
|
|
11149
11636
|
"Enduser register (rate limited)",
|
|
11150
|
-
|
|
11637
|
+
// The register limiter records its throttle event at request start with a 1s expiry
|
|
11638
|
+
// (countPerInterval: 1, intervalInMS: 1000), so back-to-back registers are only
|
|
11639
|
+
// rate limited when they land within 1s of each other. A slow register (bcrypt on a
|
|
11640
|
+
// cold/loaded server) can exceed the window and flake — retry the pair instead of
|
|
11641
|
+
// failing on a timing miss. Any "Too many requests" from either call is the expected error.
|
|
11642
|
+
async () => {
|
|
11643
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
11644
|
+
const windowStart = Date.now()
|
|
11645
|
+
await enduserSDK.register({ email: 'test@tellescope.com', password: 'testpassWord12345!' })
|
|
11646
|
+
await enduserSDK.register({ email: 'test@tellescope.com', password: 'testpassWord12345!' })
|
|
11647
|
+
if (Date.now() - windowStart < 900) {
|
|
11648
|
+
return 'two registers within the same 1s window were not rate limited'
|
|
11649
|
+
}
|
|
11650
|
+
await wait(undefined, 1100) // let the throttle window expire before retrying the pair
|
|
11651
|
+
}
|
|
11652
|
+
return 'rate-limit timing window missed on every attempt'
|
|
11653
|
+
},
|
|
11151
11654
|
{ shouldError: true, onError: e => e.message === "Too many requests" }
|
|
11152
11655
|
)
|
|
11153
11656
|
await wait(undefined, 1000)
|
|
@@ -14181,7 +14684,7 @@ const ip_address_form_tests = async () => {
|
|
|
14181
14684
|
})
|
|
14182
14685
|
|
|
14183
14686
|
await wait(undefined, 500) // wait for IP to be set
|
|
14184
|
-
async_test(
|
|
14687
|
+
await async_test(
|
|
14185
14688
|
'IP Set on Enduser creation',
|
|
14186
14689
|
() => sdk.api.endusers.getOne(enduserId),
|
|
14187
14690
|
{ onResult: result => !!result.fields?.IP }
|
|
@@ -14200,7 +14703,8 @@ const ip_address_form_tests = async () => {
|
|
|
14200
14703
|
lname: 'test',
|
|
14201
14704
|
})
|
|
14202
14705
|
|
|
14203
|
-
|
|
14706
|
+
await wait(undefined, 500) // wait for IP to be re-set
|
|
14707
|
+
await async_test(
|
|
14204
14708
|
'IP Set on update',
|
|
14205
14709
|
() => sdk.api.endusers.getOne(enduserId),
|
|
14206
14710
|
{ onResult: result => !!result.fields?.IP && result.fields?.otherField === 'Set' && result.id === enduserId }
|
|
@@ -14333,6 +14837,12 @@ const ip_address_form_tests = async () => {
|
|
|
14333
14837
|
await replace_form_field_template_values_tests()
|
|
14334
14838
|
await mfa_tests()
|
|
14335
14839
|
await setup_tests(sdk, sdkNonAdmin)
|
|
14840
|
+
await resource_access_tags_tests({ sdk, sdkNonAdmin })
|
|
14841
|
+
await beluga_manual_sync_tests({ sdk, sdkNonAdmin })
|
|
14842
|
+
await beluga_pharmacy_mappings_tests({ sdk, sdkNonAdmin })
|
|
14843
|
+
await enduser_write_restrictions_tests({ sdk, sdkNonAdmin })
|
|
14844
|
+
await user_portal_settings_tests({ sdk, sdkNonAdmin })
|
|
14845
|
+
await automation_trigger_tests()
|
|
14336
14846
|
await invite_user_enumeration_tests({ sdk, sdkNonAdmin })
|
|
14337
14847
|
await handle_incoming_communication_cross_tenant_tests({ sdk, sdkNonAdmin })
|
|
14338
14848
|
await calendar_event_webhook_template_tests({ sdk, sdkNonAdmin })
|
|
@@ -14344,7 +14854,6 @@ const ip_address_form_tests = async () => {
|
|
|
14344
14854
|
await self_admin_role_assignment_tests({ sdk, sdkNonAdmin })
|
|
14345
14855
|
await sanitize_user_html_xss_tests()
|
|
14346
14856
|
await prototype_pollution_tests()
|
|
14347
|
-
await automation_trigger_tests()
|
|
14348
14857
|
await account_switcher_tests({ sdk, sdkNonAdmin })
|
|
14349
14858
|
await enduser_login_tests({ sdk, sdkNonAdmin })
|
|
14350
14859
|
await outbound_chat_sent_trigger_tests({ sdk })
|
|
@@ -14368,6 +14877,8 @@ const ip_address_form_tests = async () => {
|
|
|
14368
14877
|
await time_tracks_review_tests({ sdk, sdkNonAdmin })
|
|
14369
14878
|
await time_tracks_lock_tests({ sdk, sdkNonAdmin })
|
|
14370
14879
|
await time_tracks_edge_case_tests({ sdk, sdkNonAdmin })
|
|
14880
|
+
await time_tracks_resubmit_tests({ sdk, sdkNonAdmin })
|
|
14881
|
+
await time_tracks_appointment_duration_tests({ sdk, sdkNonAdmin })
|
|
14371
14882
|
await calendar_event_limits_tests({ sdk, sdkNonAdmin })
|
|
14372
14883
|
await get_some_projection_tests({ sdk, sdkNonAdmin })
|
|
14373
14884
|
await elation_user_id_tests({ sdk, sdkNonAdmin })
|
|
@@ -14384,7 +14895,6 @@ const ip_address_form_tests = async () => {
|
|
|
14384
14895
|
await load_threads_autobuild_tests({ sdk, sdkNonAdmin })
|
|
14385
14896
|
await inbox_threads_new_fields_tests()
|
|
14386
14897
|
await auto_merge_form_submission_tests({ sdk, sdkNonAdmin })
|
|
14387
|
-
await beluga_pharmacy_mappings_tests({ sdk, sdkNonAdmin })
|
|
14388
14898
|
await threadKeyTests()
|
|
14389
14899
|
await managed_content_enduser_access_tests({ sdk, sdkNonAdmin })
|
|
14390
14900
|
await managed_content_file_access_tests({ sdk, sdkNonAdmin })
|
|
@@ -14400,7 +14910,6 @@ const ip_address_form_tests = async () => {
|
|
|
14400
14910
|
await inbox_threads_loading_tests()
|
|
14401
14911
|
await load_inbox_data_tests({ sdk, sdkNonAdmin })
|
|
14402
14912
|
await enduser_observations_acknowledge_tests({ sdk, sdkNonAdmin })
|
|
14403
|
-
await user_portal_settings_tests({ sdk, sdkNonAdmin })
|
|
14404
14913
|
await create_user_notifications_trigger_tests({ sdk })
|
|
14405
14914
|
await group_mms_active_tests()
|
|
14406
14915
|
await auto_reply_tests()
|
package/test_generated.pdf
CHANGED
|
Binary file
|