@servicetitan/journey 2.0.0 → 3.0.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 (233) hide show
  1. package/README.md +1 -1
  2. package/dist/__test-utils__/test-runtime.d.ts.map +1 -0
  3. package/dist/__test-utils__/test-runtime.js +54 -0
  4. package/dist/__test-utils__/test-runtime.js.map +1 -0
  5. package/dist/__tests__/core/ambient.test.d.ts.map +1 -0
  6. package/dist/__tests__/core/api.test.d.ts +2 -0
  7. package/dist/__tests__/core/api.test.d.ts.map +1 -0
  8. package/dist/__tests__/core/define-journey.test.d.ts.map +1 -0
  9. package/dist/__tests__/core/requests.test.d.ts.map +1 -0
  10. package/dist/__tests__/core/runtime.test.d.ts.map +1 -0
  11. package/dist/__tests__/core/sanitize.test.d.ts +2 -0
  12. package/dist/__tests__/core/sanitize.test.d.ts.map +1 -0
  13. package/dist/__tests__/core/step.test.d.ts.map +1 -0
  14. package/dist/__tests__/core/timeouts.test.d.ts.map +1 -0
  15. package/dist/__tests__/global.test.d.ts +3 -0
  16. package/dist/__tests__/global.test.d.ts.map +1 -0
  17. package/dist/__tests__/hardening.test.d.ts +2 -0
  18. package/dist/__tests__/hardening.test.d.ts.map +1 -0
  19. package/dist/__tests__/integrations/axios.test.d.ts.map +1 -0
  20. package/dist/__tests__/integrations/context.test.d.ts.map +1 -0
  21. package/dist/__tests__/integrations/expose-app-journey.test.d.ts.map +1 -0
  22. package/dist/__tests__/integrations/fetch.test.d.ts.map +1 -0
  23. package/dist/__tests__/integrations/host-mfe.test.d.ts +2 -0
  24. package/dist/__tests__/integrations/host-mfe.test.d.ts.map +1 -0
  25. package/dist/__tests__/integrations/jquery.test.d.ts.map +1 -0
  26. package/dist/__tests__/integrations/request-key.test.d.ts.map +1 -0
  27. package/dist/__tests__/integrations/scope.test.d.ts.map +1 -0
  28. package/dist/__tests__/integrations/use-journey-step.test.d.ts +2 -0
  29. package/dist/__tests__/integrations/use-journey-step.test.d.ts.map +1 -0
  30. package/dist/__tests__/sinks/console.test.d.ts +2 -0
  31. package/dist/__tests__/sinks/console.test.d.ts.map +1 -0
  32. package/dist/__tests__/sinks/datadog.test.d.ts.map +1 -0
  33. package/dist/__tests__/sinks/sinks.test.d.ts.map +1 -0
  34. package/dist/config.d.ts +61 -13
  35. package/dist/config.d.ts.map +1 -1
  36. package/dist/config.js +98 -29
  37. package/dist/config.js.map +1 -1
  38. package/dist/core/abort-error.d.ts +4 -0
  39. package/dist/core/abort-error.d.ts.map +1 -0
  40. package/dist/core/abort-error.js +22 -0
  41. package/dist/core/abort-error.js.map +1 -0
  42. package/dist/core/api.d.ts +43 -0
  43. package/dist/core/api.d.ts.map +1 -0
  44. package/dist/core/api.js +122 -0
  45. package/dist/core/api.js.map +1 -0
  46. package/dist/{endpoint-policy.d.ts → core/endpoint-policy.d.ts} +14 -4
  47. package/dist/core/endpoint-policy.d.ts.map +1 -0
  48. package/dist/core/endpoint-policy.js +70 -0
  49. package/dist/core/endpoint-policy.js.map +1 -0
  50. package/dist/core/index.d.ts +6 -5
  51. package/dist/core/index.d.ts.map +1 -1
  52. package/dist/core/index.js +4 -3
  53. package/dist/core/index.js.map +1 -1
  54. package/dist/core/limits.d.ts +29 -0
  55. package/dist/core/limits.d.ts.map +1 -0
  56. package/dist/core/limits.js +63 -0
  57. package/dist/core/limits.js.map +1 -0
  58. package/dist/core/request-policy.d.ts +39 -0
  59. package/dist/core/request-policy.d.ts.map +1 -0
  60. package/dist/core/request-policy.js +18 -0
  61. package/dist/core/request-policy.js.map +1 -0
  62. package/dist/core/runtime.d.ts +95 -17
  63. package/dist/core/runtime.d.ts.map +1 -1
  64. package/dist/core/runtime.js +435 -124
  65. package/dist/core/runtime.js.map +1 -1
  66. package/dist/core/sanitize.d.ts +23 -0
  67. package/dist/core/sanitize.d.ts.map +1 -0
  68. package/dist/core/sanitize.js +143 -0
  69. package/dist/core/sanitize.js.map +1 -0
  70. package/dist/core/step-tag.d.ts +31 -6
  71. package/dist/core/step-tag.d.ts.map +1 -1
  72. package/dist/core/step-tag.js +62 -9
  73. package/dist/core/step-tag.js.map +1 -1
  74. package/dist/core/types.d.ts +76 -26
  75. package/dist/core/types.d.ts.map +1 -1
  76. package/dist/core/types.js +4 -1
  77. package/dist/core/types.js.map +1 -1
  78. package/dist/global.d.ts +145 -0
  79. package/dist/global.d.ts.map +1 -0
  80. package/dist/global.js +326 -0
  81. package/dist/global.js.map +1 -0
  82. package/dist/index.d.ts +9 -5
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +9 -5
  85. package/dist/index.js.map +1 -1
  86. package/dist/integrations/axios.d.ts +5 -1
  87. package/dist/integrations/axios.d.ts.map +1 -1
  88. package/dist/integrations/axios.js +146 -34
  89. package/dist/integrations/axios.js.map +1 -1
  90. package/dist/integrations/fetch.d.ts +6 -4
  91. package/dist/integrations/fetch.d.ts.map +1 -1
  92. package/dist/integrations/fetch.js +105 -26
  93. package/dist/integrations/fetch.js.map +1 -1
  94. package/dist/integrations/http-report.d.ts +27 -0
  95. package/dist/integrations/http-report.d.ts.map +1 -0
  96. package/dist/integrations/http-report.js +123 -0
  97. package/dist/integrations/http-report.js.map +1 -0
  98. package/dist/integrations/jquery/index.d.ts +10 -6
  99. package/dist/integrations/jquery/index.d.ts.map +1 -1
  100. package/dist/integrations/jquery/index.js +28 -9
  101. package/dist/integrations/jquery/index.js.map +1 -1
  102. package/dist/integrations/jquery/instrument.d.ts +14 -5
  103. package/dist/integrations/jquery/instrument.d.ts.map +1 -1
  104. package/dist/integrations/jquery/instrument.js +111 -29
  105. package/dist/integrations/jquery/instrument.js.map +1 -1
  106. package/dist/integrations/react/context.d.ts +4 -1
  107. package/dist/integrations/react/context.d.ts.map +1 -1
  108. package/dist/integrations/react/context.js +4 -1
  109. package/dist/integrations/react/context.js.map +1 -1
  110. package/dist/integrations/react/scope.d.ts +14 -3
  111. package/dist/integrations/react/scope.d.ts.map +1 -1
  112. package/dist/integrations/react/scope.js +48 -9
  113. package/dist/integrations/react/scope.js.map +1 -1
  114. package/dist/integrations/react/stable-config-keys.d.ts +6 -0
  115. package/dist/integrations/react/stable-config-keys.d.ts.map +1 -0
  116. package/dist/integrations/react/stable-config-keys.js +21 -0
  117. package/dist/integrations/react/stable-config-keys.js.map +1 -0
  118. package/dist/integrations/react/use-journey-step.d.ts +11 -0
  119. package/dist/integrations/react/use-journey-step.d.ts.map +1 -0
  120. package/dist/integrations/react/use-journey-step.js +19 -0
  121. package/dist/integrations/react/use-journey-step.js.map +1 -0
  122. package/dist/integrations/request-key.d.ts +8 -3
  123. package/dist/integrations/request-key.d.ts.map +1 -1
  124. package/dist/integrations/request-key.js +10 -9
  125. package/dist/integrations/request-key.js.map +1 -1
  126. package/dist/integrations/soft-skip.d.ts +7 -0
  127. package/dist/integrations/soft-skip.d.ts.map +1 -0
  128. package/dist/integrations/soft-skip.js +30 -0
  129. package/dist/integrations/soft-skip.js.map +1 -0
  130. package/dist/sinks/console.d.ts +11 -0
  131. package/dist/sinks/console.d.ts.map +1 -0
  132. package/dist/sinks/console.js +19 -0
  133. package/dist/sinks/console.js.map +1 -0
  134. package/dist/sinks/datadog.d.ts +12 -1
  135. package/dist/sinks/datadog.d.ts.map +1 -1
  136. package/dist/sinks/datadog.js +42 -25
  137. package/dist/sinks/datadog.js.map +1 -1
  138. package/package.json +2 -2
  139. package/src/{__mocks__ → __test-utils__}/test-runtime.ts +15 -4
  140. package/src/__tests__/config.test.ts +158 -42
  141. package/src/__tests__/{ambient.test.ts → core/ambient.test.ts} +23 -16
  142. package/src/__tests__/{registry.test.ts → core/api.test.ts} +35 -30
  143. package/src/__tests__/{define-journey.test.ts → core/define-journey.test.ts} +33 -15
  144. package/src/__tests__/{requests.test.ts → core/requests.test.ts} +61 -39
  145. package/src/__tests__/{runtime.test.ts → core/runtime.test.ts} +84 -37
  146. package/src/__tests__/core/sanitize.test.ts +69 -0
  147. package/src/__tests__/{step.test.ts → core/step.test.ts} +146 -52
  148. package/src/__tests__/{timeouts.test.ts → core/timeouts.test.ts} +83 -13
  149. package/src/__tests__/global.test.ts +154 -0
  150. package/src/__tests__/hardening.test.ts +613 -0
  151. package/src/__tests__/integrations/axios.test.ts +616 -0
  152. package/src/__tests__/{context.test.tsx → integrations/context.test.tsx} +1 -1
  153. package/src/__tests__/{expose-app-journey.test.ts → integrations/expose-app-journey.test.ts} +11 -5
  154. package/src/__tests__/{fetch.test.ts → integrations/fetch.test.ts} +159 -25
  155. package/src/__tests__/integrations/host-mfe.test.ts +548 -0
  156. package/src/__tests__/integrations/jquery.test.ts +539 -0
  157. package/src/__tests__/{request-key.test.ts → integrations/request-key.test.ts} +1 -1
  158. package/src/__tests__/integrations/scope.test.tsx +286 -0
  159. package/src/__tests__/integrations/use-journey-step.test.tsx +43 -0
  160. package/src/__tests__/sinks/console.test.ts +103 -0
  161. package/src/__tests__/{datadog.test.ts → sinks/datadog.test.ts} +109 -5
  162. package/src/__tests__/{sinks.test.ts → sinks/sinks.test.ts} +13 -12
  163. package/src/config.ts +173 -41
  164. package/src/core/abort-error.ts +24 -0
  165. package/src/core/api.ts +159 -0
  166. package/src/{endpoint-policy.ts → core/endpoint-policy.ts} +46 -4
  167. package/src/core/index.ts +16 -17
  168. package/src/core/limits.ts +73 -0
  169. package/src/core/request-policy.ts +66 -0
  170. package/src/core/runtime.ts +560 -137
  171. package/src/core/sanitize.ts +177 -0
  172. package/src/core/step-tag.ts +90 -11
  173. package/src/core/types.ts +82 -26
  174. package/src/global.ts +466 -0
  175. package/src/index.ts +31 -18
  176. package/src/integrations/axios.ts +183 -45
  177. package/src/integrations/fetch.ts +127 -41
  178. package/src/integrations/http-report.ts +184 -0
  179. package/src/integrations/jquery/index.ts +37 -18
  180. package/src/integrations/jquery/instrument.ts +126 -42
  181. package/src/integrations/react/context.ts +4 -1
  182. package/src/integrations/react/scope.tsx +61 -10
  183. package/src/integrations/react/stable-config-keys.ts +28 -0
  184. package/src/integrations/react/use-journey-step.ts +31 -0
  185. package/src/integrations/request-key.ts +18 -10
  186. package/src/integrations/soft-skip.ts +35 -0
  187. package/src/sinks/console.ts +21 -0
  188. package/src/sinks/datadog.ts +52 -33
  189. package/dist/__mocks__/test-runtime.d.ts.map +0 -1
  190. package/dist/__tests__/ambient.test.d.ts.map +0 -1
  191. package/dist/__tests__/axios.test.d.ts.map +0 -1
  192. package/dist/__tests__/context.test.d.ts.map +0 -1
  193. package/dist/__tests__/datadog.test.d.ts.map +0 -1
  194. package/dist/__tests__/define-journey.test.d.ts.map +0 -1
  195. package/dist/__tests__/expose-app-journey.test.d.ts.map +0 -1
  196. package/dist/__tests__/fetch.test.d.ts.map +0 -1
  197. package/dist/__tests__/jquery.test.d.ts.map +0 -1
  198. package/dist/__tests__/registry.test.d.ts +0 -2
  199. package/dist/__tests__/registry.test.d.ts.map +0 -1
  200. package/dist/__tests__/request-key.test.d.ts.map +0 -1
  201. package/dist/__tests__/requests.test.d.ts.map +0 -1
  202. package/dist/__tests__/runtime.test.d.ts.map +0 -1
  203. package/dist/__tests__/scope.test.d.ts.map +0 -1
  204. package/dist/__tests__/sinks.test.d.ts.map +0 -1
  205. package/dist/__tests__/step.test.d.ts.map +0 -1
  206. package/dist/__tests__/timeouts.test.d.ts.map +0 -1
  207. package/dist/core/registry.d.ts +0 -50
  208. package/dist/core/registry.d.ts.map +0 -1
  209. package/dist/core/registry.js +0 -102
  210. package/dist/core/registry.js.map +0 -1
  211. package/dist/endpoint-policy.d.ts.map +0 -1
  212. package/dist/endpoint-policy.js +0 -39
  213. package/dist/endpoint-policy.js.map +0 -1
  214. package/src/__tests__/axios.test.ts +0 -365
  215. package/src/__tests__/jquery.test.ts +0 -327
  216. package/src/__tests__/scope.test.tsx +0 -128
  217. package/src/core/registry.ts +0 -162
  218. /package/dist/{__mocks__ → __test-utils__}/test-runtime.d.ts +0 -0
  219. /package/dist/__tests__/{ambient.test.d.ts → core/ambient.test.d.ts} +0 -0
  220. /package/dist/__tests__/{define-journey.test.d.ts → core/define-journey.test.d.ts} +0 -0
  221. /package/dist/__tests__/{requests.test.d.ts → core/requests.test.d.ts} +0 -0
  222. /package/dist/__tests__/{runtime.test.d.ts → core/runtime.test.d.ts} +0 -0
  223. /package/dist/__tests__/{step.test.d.ts → core/step.test.d.ts} +0 -0
  224. /package/dist/__tests__/{timeouts.test.d.ts → core/timeouts.test.d.ts} +0 -0
  225. /package/dist/__tests__/{axios.test.d.ts → integrations/axios.test.d.ts} +0 -0
  226. /package/dist/__tests__/{context.test.d.ts → integrations/context.test.d.ts} +0 -0
  227. /package/dist/__tests__/{expose-app-journey.test.d.ts → integrations/expose-app-journey.test.d.ts} +0 -0
  228. /package/dist/__tests__/{fetch.test.d.ts → integrations/fetch.test.d.ts} +0 -0
  229. /package/dist/__tests__/{jquery.test.d.ts → integrations/jquery.test.d.ts} +0 -0
  230. /package/dist/__tests__/{request-key.test.d.ts → integrations/request-key.test.d.ts} +0 -0
  231. /package/dist/__tests__/{scope.test.d.ts → integrations/scope.test.d.ts} +0 -0
  232. /package/dist/__tests__/{datadog.test.d.ts → sinks/datadog.test.d.ts} +0 -0
  233. /package/dist/__tests__/{sinks.test.d.ts → sinks/sinks.test.d.ts} +0 -0
@@ -1,18 +1,27 @@
1
1
  /** @jest-environment jsdom */
2
- import { activeJourneyStep, reportBackendRequest, type JourneyStepRef } from '../core';
3
- import { instrumentFetch, type InstrumentFetchOptions } from '../integrations/fetch';
4
- import { requestKey } from '../integrations/request-key';
5
-
6
- jest.mock('../core', () => ({
7
- ...jest.requireActual('../core'),
8
- activeJourneyStep: jest.fn(),
9
- reportBackendRequest: jest.fn(),
2
+ import { resolveStamp, JourneyStepStamp } from '../../core';
3
+ import type { StepRecord } from '../../core/types';
4
+ import { instrumentFetch, type InstrumentFetchOptions } from '../../integrations/fetch';
5
+ import { onHttpComplete } from '../../integrations/http-report';
6
+ import { requestKey } from '../../integrations/request-key';
7
+
8
+ jest.mock('../../core', () => ({
9
+ ...jest.requireActual('../../core'),
10
+ resolveStamp: jest.fn(),
10
11
  }));
11
- jest.mock('../integrations/request-key');
12
+ jest.mock('../../integrations/http-report', () => ({
13
+ ...jest.requireActual('../../integrations/http-report'),
14
+ onHttpComplete: jest.fn(),
15
+ }));
16
+ jest.mock('../../integrations/request-key');
12
17
 
13
18
  describe('[journey] instrumentFetch', () => {
14
19
  const KEY = 'resolved-endpoint-key';
15
- const step = { name: 'load' } as unknown as JourneyStepRef;
20
+ const record = {
21
+ name: 'load',
22
+ journey: { name: 'j', closed: false },
23
+ } as unknown as StepRecord;
24
+ const stamp = new JourneyStepStamp(record);
16
25
 
17
26
  let target: { fetch: jest.Mock };
18
27
  let originalFetch: jest.Mock;
@@ -33,10 +42,9 @@ describe('[journey] instrumentFetch', () => {
33
42
  init = undefined;
34
43
  options = { target };
35
44
 
36
- jest.mocked(activeJourneyStep).mockReturnValue(step);
45
+ jest.mocked(resolveStamp).mockReturnValue(stamp);
37
46
  jest.mocked(requestKey).mockReturnValue(KEY);
38
47
 
39
- // Deterministic clock: each globalThis.performance.now() advances by 100ms.
40
48
  now = 1_000;
41
49
  jest.spyOn(globalThis.performance, 'now').mockImplementation(() => (now += 100));
42
50
  });
@@ -70,9 +78,53 @@ describe('[journey] instrumentFetch', () => {
70
78
 
71
79
  await target.fetch(input, init);
72
80
  expect(originalFetch).toHaveBeenCalledTimes(1);
73
- expect(reportBackendRequest).toHaveBeenCalledTimes(1);
81
+ expect(onHttpComplete).toHaveBeenCalledTimes(1);
74
82
  });
75
83
 
84
+ test('warns and soft-skips when options are null', () => {
85
+ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
86
+ const error = jest.spyOn(console, 'error').mockImplementation(() => {});
87
+
88
+ const restore = instrumentFetch(null);
89
+
90
+ expect(() => restore()).not.toThrow();
91
+ expect(warn).toHaveBeenCalledWith(
92
+ expect.stringContaining('[journey] instrumentFetch: skipped — missing')
93
+ );
94
+ expect(error).not.toHaveBeenCalled();
95
+ expect(target.fetch).toBe(originalFetch);
96
+ });
97
+
98
+ test('warns and soft-skips when target is null', () => {
99
+ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
100
+ const error = jest.spyOn(console, 'error').mockImplementation(() => {});
101
+
102
+ const restore = instrumentFetch({ target: null });
103
+
104
+ expect(() => restore()).not.toThrow();
105
+ expect(warn).toHaveBeenCalledWith(
106
+ expect.stringContaining('[journey] instrumentFetch: skipped — missing')
107
+ );
108
+ expect(error).not.toHaveBeenCalled();
109
+ });
110
+
111
+ test.each([{}, { fetch: 1 }, { fetch: undefined }])(
112
+ 'errors and soft-skips when target has invalid shape (%p)',
113
+ bad => {
114
+ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {});
115
+ const error = jest.spyOn(console, 'error').mockImplementation(() => {});
116
+
117
+ const restore = instrumentFetch({ target: bad as never });
118
+
119
+ expect(() => restore()).not.toThrow();
120
+ expect(error).toHaveBeenCalledWith(
121
+ expect.stringContaining('[journey] instrumentFetch: skipped — invalid shape (')
122
+ );
123
+ expect(error.mock.calls[0]).toHaveLength(1);
124
+ expect(warn).not.toHaveBeenCalled();
125
+ }
126
+ );
127
+
76
128
  test('delegates to the original fetch with the same arguments', async () => {
77
129
  init = { method: 'POST' };
78
130
 
@@ -90,16 +142,51 @@ describe('[journey] instrumentFetch', () => {
90
142
  test('reports the finished request against the active step', async () => {
91
143
  await subject();
92
144
 
93
- expect(reportBackendRequest).toHaveBeenCalledWith(step, 200, 100, KEY);
145
+ expect(onHttpComplete).toHaveBeenCalledWith(
146
+ expect.objectContaining({
147
+ stamp,
148
+ status: 200,
149
+ durationMs: 100,
150
+ requestKey: KEY,
151
+ method: 'GET',
152
+ })
153
+ );
154
+ });
155
+
156
+ test('reports method from init', async () => {
157
+ init = { method: 'POST' };
158
+
159
+ await subject();
160
+
161
+ expect(onHttpComplete).toHaveBeenCalledWith(
162
+ expect.objectContaining({ method: 'POST', status: 200, requestKey: KEY })
163
+ );
164
+ });
165
+
166
+ test('reports the Request method when init has none', async () => {
167
+ input = new Request('https://api.example.com/orders', { method: 'PUT' });
168
+
169
+ await subject();
170
+
171
+ expect(onHttpComplete).toHaveBeenCalledWith(expect.objectContaining({ method: 'PUT' }));
172
+ });
173
+
174
+ test('prefers init.method over the Request method', async () => {
175
+ input = new Request('https://api.example.com/orders', { method: 'PUT' });
176
+ init = { method: 'PATCH' };
177
+
178
+ await subject();
179
+
180
+ expect(onHttpComplete).toHaveBeenCalledWith(expect.objectContaining({ method: 'PATCH' }));
94
181
  });
95
182
 
96
183
  describe('when no journey step is active', () => {
97
- beforeEach(() => jest.mocked(activeJourneyStep).mockReturnValue(null));
184
+ beforeEach(() => jest.mocked(resolveStamp).mockReturnValue(undefined));
98
185
 
99
186
  test('does not report the request', async () => {
100
187
  await subject();
101
188
 
102
- expect(reportBackendRequest).not.toHaveBeenCalled();
189
+ expect(onHttpComplete).not.toHaveBeenCalled();
103
190
  });
104
191
 
105
192
  test('still delegates to the original fetch', async () => {
@@ -112,8 +199,12 @@ describe('[journey] instrumentFetch', () => {
112
199
  describe('when the active step changes before the response settles', () => {
113
200
  beforeEach(() => {
114
201
  originalFetch.mockImplementation(() => {
115
- // The step captured at call time must win over whatever is active later.
116
- jest.mocked(activeJourneyStep).mockReturnValue({ name: 'other' } as JourneyStepRef);
202
+ jest.mocked(resolveStamp).mockReturnValue(
203
+ new JourneyStepStamp({
204
+ name: 'other',
205
+ journey: { name: 'j2', closed: false },
206
+ } as unknown as StepRecord)
207
+ );
117
208
  return Promise.resolve(response);
118
209
  });
119
210
  });
@@ -121,7 +212,9 @@ describe('[journey] instrumentFetch', () => {
121
212
  test('reports against the step captured at call time', async () => {
122
213
  await subject();
123
214
 
124
- expect(reportBackendRequest).toHaveBeenCalledWith(step, 200, 100, KEY);
215
+ expect(onHttpComplete).toHaveBeenCalledWith(
216
+ expect.objectContaining({ stamp, status: 200, requestKey: KEY })
217
+ );
125
218
  });
126
219
  });
127
220
 
@@ -137,7 +230,15 @@ describe('[journey] instrumentFetch', () => {
137
230
  test('reports the failure with an undefined status', async () => {
138
231
  await subject().catch(() => {});
139
232
 
140
- expect(reportBackendRequest).toHaveBeenCalledWith(step, undefined, 100, KEY);
233
+ expect(onHttpComplete).toHaveBeenCalledWith(
234
+ expect.objectContaining({
235
+ stamp,
236
+ status: undefined,
237
+ durationMs: 100,
238
+ requestKey: KEY,
239
+ aborted: false,
240
+ })
241
+ );
141
242
  });
142
243
  });
143
244
 
@@ -200,18 +301,51 @@ describe('[journey] instrumentFetch', () => {
200
301
  });
201
302
  });
202
303
 
203
- describe('when init carries an explicit journeyStep', () => {
204
- const explicit = { name: 'explicit' } as unknown as JourneyStepRef;
304
+ describe('when init carries an explicit stamp', () => {
305
+ const explicit = new JourneyStepStamp({
306
+ name: 'explicit',
307
+ journey: { name: 'j', closed: false },
308
+ } as unknown as StepRecord);
205
309
 
206
310
  beforeEach(() => {
207
- init = { journeyStep: explicit } as RequestInit;
208
- jest.mocked(activeJourneyStep).mockReturnValue(step);
311
+ init = { stamp: explicit } as RequestInit;
312
+ jest.mocked(resolveStamp).mockImplementation(value => (value ? explicit : stamp));
209
313
  });
210
314
 
211
315
  test('prefers the explicit step over ambient', async () => {
212
316
  await subject();
213
317
 
214
- expect(reportBackendRequest).toHaveBeenCalledWith(explicit, 200, 100, KEY);
318
+ expect(onHttpComplete).toHaveBeenCalledWith(
319
+ expect.objectContaining({ stamp: explicit, status: 200, requestKey: KEY })
320
+ );
321
+ });
322
+ });
323
+
324
+ describe('when init.ignore is true', () => {
325
+ beforeEach(() => {
326
+ init = { ignore: true } as RequestInit;
327
+ });
328
+
329
+ test('does not report the request', async () => {
330
+ await subject();
331
+
332
+ expect(onHttpComplete).not.toHaveBeenCalled();
333
+ expect(originalFetch).toHaveBeenCalledWith(input, init);
334
+ });
335
+ });
336
+
337
+ describe('when the stamp is ignore', () => {
338
+ beforeEach(() => {
339
+ jest.mocked(resolveStamp).mockReturnValue(
340
+ new JourneyStepStamp(record, { ignore: true })
341
+ );
342
+ });
343
+
344
+ test('does not report the request', async () => {
345
+ await subject();
346
+
347
+ expect(onHttpComplete).not.toHaveBeenCalled();
348
+ expect(originalFetch).toHaveBeenCalledWith(input, init);
215
349
  });
216
350
  });
217
351