@tellescope/sdk 1.253.1 → 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 (64) 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/field_redaction.test.d.ts.map +1 -1
  8. package/lib/cjs/tests/api_tests/field_redaction.test.js +112 -99
  9. package/lib/cjs/tests/api_tests/field_redaction.test.js.map +1 -1
  10. package/lib/cjs/tests/api_tests/journey_error_branching.test.js +7 -2
  11. package/lib/cjs/tests/api_tests/journey_error_branching.test.js.map +1 -1
  12. package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts +22 -0
  13. package/lib/cjs/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
  14. package/lib/cjs/tests/api_tests/resource_access_tags.test.js +488 -0
  15. package/lib/cjs/tests/api_tests/resource_access_tags.test.js.map +1 -0
  16. package/lib/cjs/tests/api_tests/time_tracks.test.d.ts +8 -0
  17. package/lib/cjs/tests/api_tests/time_tracks.test.d.ts.map +1 -1
  18. package/lib/cjs/tests/api_tests/time_tracks.test.js +638 -1
  19. package/lib/cjs/tests/api_tests/time_tracks.test.js.map +1 -1
  20. package/lib/cjs/tests/tests.d.ts.map +1 -1
  21. package/lib/cjs/tests/tests.js +586 -178
  22. package/lib/cjs/tests/tests.js.map +1 -1
  23. package/lib/esm/sdk.d.ts +4 -0
  24. package/lib/esm/sdk.d.ts.map +1 -1
  25. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts +2 -0
  26. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.d.ts.map +1 -0
  27. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js +120 -0
  28. package/lib/esm/tests/api_tests/_tmp_bc_verify.test.js.map +1 -0
  29. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts +2 -0
  30. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.d.ts.map +1 -0
  31. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js +200 -0
  32. package/lib/esm/tests/api_tests/_tmp_blank_status_verify.test.js.map +1 -0
  33. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts +2 -0
  34. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.d.ts.map +1 -0
  35. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js +194 -0
  36. package/lib/esm/tests/api_tests/_tmp_followup_verify.test.js.map +1 -0
  37. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts +2 -0
  38. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.d.ts.map +1 -0
  39. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js +115 -0
  40. package/lib/esm/tests/api_tests/_tmp_nonmatch_verify.test.js.map +1 -0
  41. package/lib/esm/tests/api_tests/field_redaction.test.d.ts.map +1 -1
  42. package/lib/esm/tests/api_tests/field_redaction.test.js +112 -99
  43. package/lib/esm/tests/api_tests/field_redaction.test.js.map +1 -1
  44. package/lib/esm/tests/api_tests/journey_error_branching.test.js +7 -2
  45. package/lib/esm/tests/api_tests/journey_error_branching.test.js.map +1 -1
  46. package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts +22 -0
  47. package/lib/esm/tests/api_tests/resource_access_tags.test.d.ts.map +1 -0
  48. package/lib/esm/tests/api_tests/resource_access_tags.test.js +484 -0
  49. package/lib/esm/tests/api_tests/resource_access_tags.test.js.map +1 -0
  50. package/lib/esm/tests/api_tests/time_tracks.test.d.ts +8 -0
  51. package/lib/esm/tests/api_tests/time_tracks.test.d.ts.map +1 -1
  52. package/lib/esm/tests/api_tests/time_tracks.test.js +635 -0
  53. package/lib/esm/tests/api_tests/time_tracks.test.js.map +1 -1
  54. package/lib/esm/tests/tests.d.ts.map +1 -1
  55. package/lib/esm/tests/tests.js +587 -179
  56. package/lib/esm/tests/tests.js.map +1 -1
  57. package/lib/tsconfig.tsbuildinfo +1 -1
  58. package/package.json +10 -10
  59. package/src/tests/api_tests/field_redaction.test.ts +13 -0
  60. package/src/tests/api_tests/journey_error_branching.test.ts +5 -1
  61. package/src/tests/api_tests/resource_access_tags.test.ts +303 -0
  62. package/src/tests/api_tests/time_tracks.test.ts +420 -0
  63. package/src/tests/tests.ts +298 -5
  64. package/test_generated.pdf +0 -0
@@ -83,12 +83,13 @@ 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";
94
95
  import { enduser_write_restrictions_tests } from "./api_tests/security/F-0106-F-0110-enduser-write-restrictions.test";
@@ -3713,6 +3714,290 @@ const order_status_equals_tests = async () => {
3713
3714
  ])
3714
3715
  }
3715
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
+
3716
4001
  const tag_added_tests = async () => {
3717
4002
  log_header("Automation Trigger Tests (Tag Added)")
3718
4003
 
@@ -5305,6 +5590,7 @@ const automation_trigger_tests = async () => {
5305
5590
  await assign_care_team_tests()
5306
5591
  await push_forms_to_portal_group_completion_tests({ sdk, sdkNonAdmin })
5307
5592
  await order_status_equals_tests()
5593
+ await order_status_blank_tests()
5308
5594
  await set_fields_order_templates_tests({ sdk, sdkNonAdmin })
5309
5595
  await medication_added_trigger_tests({ sdk, sdkNonAdmin })
5310
5596
  await appointment_cancelled_tests()
@@ -8862,8 +9148,11 @@ export const switch_to_related_contacts_tests = async () => {
8862
9148
  () => pollForResults(
8863
9149
  () => sdk.api.endusers.getOne(parent.id),
8864
9150
  e => !!e.tags?.includes('Success'),
8865
- 50,
8866
- 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,
8867
9156
  ),
8868
9157
  passOnAnyResult
8869
9158
  )
@@ -14395,7 +14684,7 @@ const ip_address_form_tests = async () => {
14395
14684
  })
14396
14685
 
14397
14686
  await wait(undefined, 500) // wait for IP to be set
14398
- async_test(
14687
+ await async_test(
14399
14688
  'IP Set on Enduser creation',
14400
14689
  () => sdk.api.endusers.getOne(enduserId),
14401
14690
  { onResult: result => !!result.fields?.IP }
@@ -14414,7 +14703,8 @@ const ip_address_form_tests = async () => {
14414
14703
  lname: 'test',
14415
14704
  })
14416
14705
 
14417
- async_test(
14706
+ await wait(undefined, 500) // wait for IP to be re-set
14707
+ await async_test(
14418
14708
  'IP Set on update',
14419
14709
  () => sdk.api.endusers.getOne(enduserId),
14420
14710
  { onResult: result => !!result.fields?.IP && result.fields?.otherField === 'Set' && result.id === enduserId }
@@ -14547,6 +14837,7 @@ const ip_address_form_tests = async () => {
14547
14837
  await replace_form_field_template_values_tests()
14548
14838
  await mfa_tests()
14549
14839
  await setup_tests(sdk, sdkNonAdmin)
14840
+ await resource_access_tags_tests({ sdk, sdkNonAdmin })
14550
14841
  await beluga_manual_sync_tests({ sdk, sdkNonAdmin })
14551
14842
  await beluga_pharmacy_mappings_tests({ sdk, sdkNonAdmin })
14552
14843
  await enduser_write_restrictions_tests({ sdk, sdkNonAdmin })
@@ -14586,6 +14877,8 @@ const ip_address_form_tests = async () => {
14586
14877
  await time_tracks_review_tests({ sdk, sdkNonAdmin })
14587
14878
  await time_tracks_lock_tests({ sdk, sdkNonAdmin })
14588
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 })
14589
14882
  await calendar_event_limits_tests({ sdk, sdkNonAdmin })
14590
14883
  await get_some_projection_tests({ sdk, sdkNonAdmin })
14591
14884
  await elation_user_id_tests({ sdk, sdkNonAdmin })
Binary file