@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.
Files changed (98) hide show
  1. package/lib/cjs/sdk.d.ts +4 -0
  2. package/lib/cjs/sdk.d.ts.map +1 -1
  3. package/lib/cjs/tests/api_tests/_tmp_bc_verify.test.d.ts.map +1 -0
  4. package/lib/cjs/tests/api_tests/_tmp_blank_status_verify.test.d.ts.map +1 -0
  5. package/lib/cjs/tests/api_tests/_tmp_followup_verify.test.d.ts.map +1 -0
  6. package/lib/cjs/tests/api_tests/_tmp_nonmatch_verify.test.d.ts.map +1 -0
  7. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
  8. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
  9. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js +256 -0
  10. package/lib/cjs/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
  11. package/lib/cjs/tests/api_tests/field_redaction.test.d.ts.map +1 -1
  12. package/lib/cjs/tests/api_tests/field_redaction.test.js +112 -99
  13. package/lib/cjs/tests/api_tests/field_redaction.test.js.map +1 -1
  14. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
  15. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
  16. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js +168 -0
  17. package/lib/cjs/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
  18. package/lib/cjs/tests/api_tests/journey_error_branching.test.js +7 -2
  19. package/lib/cjs/tests/api_tests/journey_error_branching.test.js.map +1 -1
  20. package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts +22 -0
  21. package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
  22. package/lib/cjs/tests/api_tests/resource_access_tags.test.js +488 -0
  23. package/lib/cjs/tests/api_tests/resource_access_tags.test.js.map +1 -0
  24. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
  25. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
  26. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +325 -0
  27. package/lib/cjs/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
  28. package/lib/cjs/tests/api_tests/time_tracks.test.d.ts +8 -0
  29. package/lib/cjs/tests/api_tests/time_tracks.test.d.ts.map +1 -1
  30. package/lib/cjs/tests/api_tests/time_tracks.test.js +638 -1
  31. package/lib/cjs/tests/api_tests/time_tracks.test.js.map +1 -1
  32. package/lib/cjs/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
  33. package/lib/cjs/tests/api_tests/user_portal_settings.test.js +104 -28
  34. package/lib/cjs/tests/api_tests/user_portal_settings.test.js.map +1 -1
  35. package/lib/cjs/tests/tests.d.ts.map +1 -1
  36. package/lib/cjs/tests/tests.js +878 -200
  37. package/lib/cjs/tests/tests.js.map +1 -1
  38. package/lib/esm/sdk.d.ts +4 -0
  39. package/lib/esm/sdk.d.ts.map +1 -1
  40. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts +2 -0
  41. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts.map +1 -0
  42. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js +120 -0
  43. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js.map +1 -0
  44. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts +2 -0
  45. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts.map +1 -0
  46. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js +200 -0
  47. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js.map +1 -0
  48. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts +2 -0
  49. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts.map +1 -0
  50. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js +194 -0
  51. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js.map +1 -0
  52. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts +2 -0
  53. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts.map +1 -0
  54. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js +115 -0
  55. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js.map +1 -0
  56. package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts +6 -0
  57. package/lib/esm/tests/api_tests/beluga_manual_sync.test.d.ts.map +1 -0
  58. package/lib/esm/tests/api_tests/beluga_manual_sync.test.js +252 -0
  59. package/lib/esm/tests/api_tests/beluga_manual_sync.test.js.map +1 -0
  60. package/lib/esm/tests/api_tests/field_redaction.test.d.ts.map +1 -1
  61. package/lib/esm/tests/api_tests/field_redaction.test.js +112 -99
  62. package/lib/esm/tests/api_tests/field_redaction.test.js.map +1 -1
  63. package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts +43 -0
  64. package/lib/esm/tests/api_tests/gcal_sync_retry.test.d.ts.map +1 -0
  65. package/lib/esm/tests/api_tests/gcal_sync_retry.test.js +164 -0
  66. package/lib/esm/tests/api_tests/gcal_sync_retry.test.js.map +1 -0
  67. package/lib/esm/tests/api_tests/journey_error_branching.test.js +7 -2
  68. package/lib/esm/tests/api_tests/journey_error_branching.test.js.map +1 -1
  69. package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts +22 -0
  70. package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
  71. package/lib/esm/tests/api_tests/resource_access_tags.test.js +484 -0
  72. package/lib/esm/tests/api_tests/resource_access_tags.test.js.map +1 -0
  73. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts +23 -0
  74. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.d.ts.map +1 -0
  75. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js +321 -0
  76. package/lib/esm/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.js.map +1 -0
  77. package/lib/esm/tests/api_tests/time_tracks.test.d.ts +8 -0
  78. package/lib/esm/tests/api_tests/time_tracks.test.d.ts.map +1 -1
  79. package/lib/esm/tests/api_tests/time_tracks.test.js +635 -0
  80. package/lib/esm/tests/api_tests/time_tracks.test.js.map +1 -1
  81. package/lib/esm/tests/api_tests/user_portal_settings.test.d.ts.map +1 -1
  82. package/lib/esm/tests/api_tests/user_portal_settings.test.js +104 -28
  83. package/lib/esm/tests/api_tests/user_portal_settings.test.js.map +1 -1
  84. package/lib/esm/tests/tests.d.ts.map +1 -1
  85. package/lib/esm/tests/tests.js +879 -201
  86. package/lib/esm/tests/tests.js.map +1 -1
  87. package/lib/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +10 -10
  89. package/src/tests/api_tests/beluga_manual_sync.test.ts +159 -0
  90. package/src/tests/api_tests/field_redaction.test.ts +13 -0
  91. package/src/tests/api_tests/gcal_sync_retry.test.ts +104 -0
  92. package/src/tests/api_tests/journey_error_branching.test.ts +5 -1
  93. package/src/tests/api_tests/resource_access_tags.test.ts +303 -0
  94. package/src/tests/api_tests/security/F-0106-F-0110-enduser-write-restrictions.test.ts +214 -0
  95. package/src/tests/api_tests/time_tracks.test.ts +420 -0
  96. package/src/tests/api_tests/user_portal_settings.test.ts +71 -1
  97. package/src/tests/tests.ts +520 -11
  98. package/test_generated.pdf +0 -0
@@ -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
- 50,
8668
- 200,
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
- () => enduserSDK.register({ email: 'test@tellescope.com', password: 'testpassWord12345!' }),
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
- async_test(
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()
Binary file