@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.
- package/README.md +1 -1
- package/dist/__test-utils__/test-runtime.d.ts.map +1 -0
- package/dist/__test-utils__/test-runtime.js +54 -0
- package/dist/__test-utils__/test-runtime.js.map +1 -0
- package/dist/__tests__/core/ambient.test.d.ts.map +1 -0
- package/dist/__tests__/core/api.test.d.ts +2 -0
- package/dist/__tests__/core/api.test.d.ts.map +1 -0
- package/dist/__tests__/core/define-journey.test.d.ts.map +1 -0
- package/dist/__tests__/core/requests.test.d.ts.map +1 -0
- package/dist/__tests__/core/runtime.test.d.ts.map +1 -0
- package/dist/__tests__/core/sanitize.test.d.ts +2 -0
- package/dist/__tests__/core/sanitize.test.d.ts.map +1 -0
- package/dist/__tests__/core/step.test.d.ts.map +1 -0
- package/dist/__tests__/core/timeouts.test.d.ts.map +1 -0
- package/dist/__tests__/global.test.d.ts +3 -0
- package/dist/__tests__/global.test.d.ts.map +1 -0
- package/dist/__tests__/hardening.test.d.ts +2 -0
- package/dist/__tests__/hardening.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/axios.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/context.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/expose-app-journey.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/fetch.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/host-mfe.test.d.ts +2 -0
- package/dist/__tests__/integrations/host-mfe.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/jquery.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/request-key.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/scope.test.d.ts.map +1 -0
- package/dist/__tests__/integrations/use-journey-step.test.d.ts +2 -0
- package/dist/__tests__/integrations/use-journey-step.test.d.ts.map +1 -0
- package/dist/__tests__/sinks/console.test.d.ts +2 -0
- package/dist/__tests__/sinks/console.test.d.ts.map +1 -0
- package/dist/__tests__/sinks/datadog.test.d.ts.map +1 -0
- package/dist/__tests__/sinks/sinks.test.d.ts.map +1 -0
- package/dist/config.d.ts +61 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +98 -29
- package/dist/config.js.map +1 -1
- package/dist/core/abort-error.d.ts +4 -0
- package/dist/core/abort-error.d.ts.map +1 -0
- package/dist/core/abort-error.js +22 -0
- package/dist/core/abort-error.js.map +1 -0
- package/dist/core/api.d.ts +43 -0
- package/dist/core/api.d.ts.map +1 -0
- package/dist/core/api.js +122 -0
- package/dist/core/api.js.map +1 -0
- package/dist/{endpoint-policy.d.ts → core/endpoint-policy.d.ts} +14 -4
- package/dist/core/endpoint-policy.d.ts.map +1 -0
- package/dist/core/endpoint-policy.js +70 -0
- package/dist/core/endpoint-policy.js.map +1 -0
- package/dist/core/index.d.ts +6 -5
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/limits.d.ts +29 -0
- package/dist/core/limits.d.ts.map +1 -0
- package/dist/core/limits.js +63 -0
- package/dist/core/limits.js.map +1 -0
- package/dist/core/request-policy.d.ts +39 -0
- package/dist/core/request-policy.d.ts.map +1 -0
- package/dist/core/request-policy.js +18 -0
- package/dist/core/request-policy.js.map +1 -0
- package/dist/core/runtime.d.ts +95 -17
- package/dist/core/runtime.d.ts.map +1 -1
- package/dist/core/runtime.js +435 -124
- package/dist/core/runtime.js.map +1 -1
- package/dist/core/sanitize.d.ts +23 -0
- package/dist/core/sanitize.d.ts.map +1 -0
- package/dist/core/sanitize.js +143 -0
- package/dist/core/sanitize.js.map +1 -0
- package/dist/core/step-tag.d.ts +31 -6
- package/dist/core/step-tag.d.ts.map +1 -1
- package/dist/core/step-tag.js +62 -9
- package/dist/core/step-tag.js.map +1 -1
- package/dist/core/types.d.ts +76 -26
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +4 -1
- package/dist/core/types.js.map +1 -1
- package/dist/global.d.ts +145 -0
- package/dist/global.d.ts.map +1 -0
- package/dist/global.js +326 -0
- package/dist/global.js.map +1 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/integrations/axios.d.ts +5 -1
- package/dist/integrations/axios.d.ts.map +1 -1
- package/dist/integrations/axios.js +146 -34
- package/dist/integrations/axios.js.map +1 -1
- package/dist/integrations/fetch.d.ts +6 -4
- package/dist/integrations/fetch.d.ts.map +1 -1
- package/dist/integrations/fetch.js +105 -26
- package/dist/integrations/fetch.js.map +1 -1
- package/dist/integrations/http-report.d.ts +27 -0
- package/dist/integrations/http-report.d.ts.map +1 -0
- package/dist/integrations/http-report.js +123 -0
- package/dist/integrations/http-report.js.map +1 -0
- package/dist/integrations/jquery/index.d.ts +10 -6
- package/dist/integrations/jquery/index.d.ts.map +1 -1
- package/dist/integrations/jquery/index.js +28 -9
- package/dist/integrations/jquery/index.js.map +1 -1
- package/dist/integrations/jquery/instrument.d.ts +14 -5
- package/dist/integrations/jquery/instrument.d.ts.map +1 -1
- package/dist/integrations/jquery/instrument.js +111 -29
- package/dist/integrations/jquery/instrument.js.map +1 -1
- package/dist/integrations/react/context.d.ts +4 -1
- package/dist/integrations/react/context.d.ts.map +1 -1
- package/dist/integrations/react/context.js +4 -1
- package/dist/integrations/react/context.js.map +1 -1
- package/dist/integrations/react/scope.d.ts +14 -3
- package/dist/integrations/react/scope.d.ts.map +1 -1
- package/dist/integrations/react/scope.js +48 -9
- package/dist/integrations/react/scope.js.map +1 -1
- package/dist/integrations/react/stable-config-keys.d.ts +6 -0
- package/dist/integrations/react/stable-config-keys.d.ts.map +1 -0
- package/dist/integrations/react/stable-config-keys.js +21 -0
- package/dist/integrations/react/stable-config-keys.js.map +1 -0
- package/dist/integrations/react/use-journey-step.d.ts +11 -0
- package/dist/integrations/react/use-journey-step.d.ts.map +1 -0
- package/dist/integrations/react/use-journey-step.js +19 -0
- package/dist/integrations/react/use-journey-step.js.map +1 -0
- package/dist/integrations/request-key.d.ts +8 -3
- package/dist/integrations/request-key.d.ts.map +1 -1
- package/dist/integrations/request-key.js +10 -9
- package/dist/integrations/request-key.js.map +1 -1
- package/dist/integrations/soft-skip.d.ts +7 -0
- package/dist/integrations/soft-skip.d.ts.map +1 -0
- package/dist/integrations/soft-skip.js +30 -0
- package/dist/integrations/soft-skip.js.map +1 -0
- package/dist/sinks/console.d.ts +11 -0
- package/dist/sinks/console.d.ts.map +1 -0
- package/dist/sinks/console.js +19 -0
- package/dist/sinks/console.js.map +1 -0
- package/dist/sinks/datadog.d.ts +12 -1
- package/dist/sinks/datadog.d.ts.map +1 -1
- package/dist/sinks/datadog.js +42 -25
- package/dist/sinks/datadog.js.map +1 -1
- package/package.json +2 -2
- package/src/{__mocks__ → __test-utils__}/test-runtime.ts +15 -4
- package/src/__tests__/config.test.ts +158 -42
- package/src/__tests__/{ambient.test.ts → core/ambient.test.ts} +23 -16
- package/src/__tests__/{registry.test.ts → core/api.test.ts} +35 -30
- package/src/__tests__/{define-journey.test.ts → core/define-journey.test.ts} +33 -15
- package/src/__tests__/{requests.test.ts → core/requests.test.ts} +61 -39
- package/src/__tests__/{runtime.test.ts → core/runtime.test.ts} +84 -37
- package/src/__tests__/core/sanitize.test.ts +69 -0
- package/src/__tests__/{step.test.ts → core/step.test.ts} +146 -52
- package/src/__tests__/{timeouts.test.ts → core/timeouts.test.ts} +83 -13
- package/src/__tests__/global.test.ts +154 -0
- package/src/__tests__/hardening.test.ts +613 -0
- package/src/__tests__/integrations/axios.test.ts +616 -0
- package/src/__tests__/{context.test.tsx → integrations/context.test.tsx} +1 -1
- package/src/__tests__/{expose-app-journey.test.ts → integrations/expose-app-journey.test.ts} +11 -5
- package/src/__tests__/{fetch.test.ts → integrations/fetch.test.ts} +159 -25
- package/src/__tests__/integrations/host-mfe.test.ts +548 -0
- package/src/__tests__/integrations/jquery.test.ts +539 -0
- package/src/__tests__/{request-key.test.ts → integrations/request-key.test.ts} +1 -1
- package/src/__tests__/integrations/scope.test.tsx +286 -0
- package/src/__tests__/integrations/use-journey-step.test.tsx +43 -0
- package/src/__tests__/sinks/console.test.ts +103 -0
- package/src/__tests__/{datadog.test.ts → sinks/datadog.test.ts} +109 -5
- package/src/__tests__/{sinks.test.ts → sinks/sinks.test.ts} +13 -12
- package/src/config.ts +173 -41
- package/src/core/abort-error.ts +24 -0
- package/src/core/api.ts +159 -0
- package/src/{endpoint-policy.ts → core/endpoint-policy.ts} +46 -4
- package/src/core/index.ts +16 -17
- package/src/core/limits.ts +73 -0
- package/src/core/request-policy.ts +66 -0
- package/src/core/runtime.ts +560 -137
- package/src/core/sanitize.ts +177 -0
- package/src/core/step-tag.ts +90 -11
- package/src/core/types.ts +82 -26
- package/src/global.ts +466 -0
- package/src/index.ts +31 -18
- package/src/integrations/axios.ts +183 -45
- package/src/integrations/fetch.ts +127 -41
- package/src/integrations/http-report.ts +184 -0
- package/src/integrations/jquery/index.ts +37 -18
- package/src/integrations/jquery/instrument.ts +126 -42
- package/src/integrations/react/context.ts +4 -1
- package/src/integrations/react/scope.tsx +61 -10
- package/src/integrations/react/stable-config-keys.ts +28 -0
- package/src/integrations/react/use-journey-step.ts +31 -0
- package/src/integrations/request-key.ts +18 -10
- package/src/integrations/soft-skip.ts +35 -0
- package/src/sinks/console.ts +21 -0
- package/src/sinks/datadog.ts +52 -33
- package/dist/__mocks__/test-runtime.d.ts.map +0 -1
- package/dist/__tests__/ambient.test.d.ts.map +0 -1
- package/dist/__tests__/axios.test.d.ts.map +0 -1
- package/dist/__tests__/context.test.d.ts.map +0 -1
- package/dist/__tests__/datadog.test.d.ts.map +0 -1
- package/dist/__tests__/define-journey.test.d.ts.map +0 -1
- package/dist/__tests__/expose-app-journey.test.d.ts.map +0 -1
- package/dist/__tests__/fetch.test.d.ts.map +0 -1
- package/dist/__tests__/jquery.test.d.ts.map +0 -1
- package/dist/__tests__/registry.test.d.ts +0 -2
- package/dist/__tests__/registry.test.d.ts.map +0 -1
- package/dist/__tests__/request-key.test.d.ts.map +0 -1
- package/dist/__tests__/requests.test.d.ts.map +0 -1
- package/dist/__tests__/runtime.test.d.ts.map +0 -1
- package/dist/__tests__/scope.test.d.ts.map +0 -1
- package/dist/__tests__/sinks.test.d.ts.map +0 -1
- package/dist/__tests__/step.test.d.ts.map +0 -1
- package/dist/__tests__/timeouts.test.d.ts.map +0 -1
- package/dist/core/registry.d.ts +0 -50
- package/dist/core/registry.d.ts.map +0 -1
- package/dist/core/registry.js +0 -102
- package/dist/core/registry.js.map +0 -1
- package/dist/endpoint-policy.d.ts.map +0 -1
- package/dist/endpoint-policy.js +0 -39
- package/dist/endpoint-policy.js.map +0 -1
- package/src/__tests__/axios.test.ts +0 -365
- package/src/__tests__/jquery.test.ts +0 -327
- package/src/__tests__/scope.test.tsx +0 -128
- package/src/core/registry.ts +0 -162
- /package/dist/{__mocks__ → __test-utils__}/test-runtime.d.ts +0 -0
- /package/dist/__tests__/{ambient.test.d.ts → core/ambient.test.d.ts} +0 -0
- /package/dist/__tests__/{define-journey.test.d.ts → core/define-journey.test.d.ts} +0 -0
- /package/dist/__tests__/{requests.test.d.ts → core/requests.test.d.ts} +0 -0
- /package/dist/__tests__/{runtime.test.d.ts → core/runtime.test.d.ts} +0 -0
- /package/dist/__tests__/{step.test.d.ts → core/step.test.d.ts} +0 -0
- /package/dist/__tests__/{timeouts.test.d.ts → core/timeouts.test.d.ts} +0 -0
- /package/dist/__tests__/{axios.test.d.ts → integrations/axios.test.d.ts} +0 -0
- /package/dist/__tests__/{context.test.d.ts → integrations/context.test.d.ts} +0 -0
- /package/dist/__tests__/{expose-app-journey.test.d.ts → integrations/expose-app-journey.test.d.ts} +0 -0
- /package/dist/__tests__/{fetch.test.d.ts → integrations/fetch.test.d.ts} +0 -0
- /package/dist/__tests__/{jquery.test.d.ts → integrations/jquery.test.d.ts} +0 -0
- /package/dist/__tests__/{request-key.test.d.ts → integrations/request-key.test.d.ts} +0 -0
- /package/dist/__tests__/{scope.test.d.ts → integrations/scope.test.d.ts} +0 -0
- /package/dist/__tests__/{datadog.test.d.ts → sinks/datadog.test.d.ts} +0 -0
- /package/dist/__tests__/{sinks.test.d.ts → sinks/sinks.test.d.ts} +0 -0
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
|
-
import { baseJourneyDef, lastJourney, useJourneyTestRuntime } from '../__mocks__/test-runtime';
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from '../core';
|
|
3
|
+
baseJourneyDef,
|
|
4
|
+
lastJourney,
|
|
5
|
+
useJourneyTestRuntime,
|
|
6
|
+
} from '../../__test-utils__/test-runtime';
|
|
7
|
+
import { completeJourney, failJourney, JourneyStepStamp, journeyStep } from '../../core';
|
|
8
|
+
import { moduleRuntime } from '../../core/runtime';
|
|
11
9
|
|
|
12
10
|
const emitMock = jest.fn();
|
|
13
11
|
const baseDef = { ...baseJourneyDef, name: 'step-api' };
|
|
@@ -18,10 +16,11 @@ describe('[journey] journeyStep', () => {
|
|
|
18
16
|
|
|
19
17
|
describe('with a candidate list', () => {
|
|
20
18
|
beforeEach(() => {
|
|
21
|
-
startJourney(baseDef);
|
|
19
|
+
moduleRuntime.startJourney(baseDef);
|
|
22
20
|
});
|
|
23
21
|
|
|
24
|
-
const subject = () =>
|
|
22
|
+
const subject = () =>
|
|
23
|
+
journeyStep(['missing', baseDef.name], 'do-work', step => step.journeyName);
|
|
25
24
|
|
|
26
25
|
test('resolves the first open name', async () => {
|
|
27
26
|
await expect(subject()).resolves.toBe(baseDef.name);
|
|
@@ -30,12 +29,12 @@ describe('[journey] journeyStep', () => {
|
|
|
30
29
|
|
|
31
30
|
describe('with multiple open candidates', () => {
|
|
32
31
|
beforeEach(() => {
|
|
33
|
-
startJourney(otherDef);
|
|
34
|
-
startJourney(baseDef);
|
|
32
|
+
moduleRuntime.startJourney(otherDef);
|
|
33
|
+
moduleRuntime.startJourney(baseDef);
|
|
35
34
|
});
|
|
36
35
|
|
|
37
36
|
const subject = () =>
|
|
38
|
-
journeyStep([baseDef.name, otherDef.name], 'do-work', step => step.
|
|
37
|
+
journeyStep([baseDef.name, otherDef.name], 'do-work', step => step.journeyName);
|
|
39
38
|
|
|
40
39
|
test('prefers the first name in order', async () => {
|
|
41
40
|
await expect(subject()).resolves.toBe(baseDef.name);
|
|
@@ -45,9 +44,9 @@ describe('[journey] journeyStep', () => {
|
|
|
45
44
|
describe('with no matching open journey', () => {
|
|
46
45
|
const subject = () =>
|
|
47
46
|
journeyStep(['missing-a', 'missing-b'], 'do-work', step => {
|
|
48
|
-
step.
|
|
49
|
-
step.
|
|
50
|
-
return step.
|
|
47
|
+
step.completeJourney({ a: 1 });
|
|
48
|
+
step.failJourney('noop');
|
|
49
|
+
return step.journeyName;
|
|
51
50
|
});
|
|
52
51
|
|
|
53
52
|
test('runs untraced', async () => {
|
|
@@ -56,25 +55,34 @@ describe('[journey] journeyStep', () => {
|
|
|
56
55
|
});
|
|
57
56
|
});
|
|
58
57
|
|
|
58
|
+
describe('with a bare name and nothing open', () => {
|
|
59
|
+
test('does not auto-start', async () => {
|
|
60
|
+
await journeyStep(baseDef.name, 'do-work', step => {
|
|
61
|
+
expect(step.journeyName).toBeNull();
|
|
62
|
+
expect(step.stamp()).toBeUndefined();
|
|
63
|
+
});
|
|
64
|
+
expect(emitMock).not.toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
59
68
|
describe('with a null target', () => {
|
|
60
|
-
const subject = () =>
|
|
61
|
-
journeyStep(null, 'untraced', step => step.tag() as Record<string, unknown>);
|
|
69
|
+
const subject = () => journeyStep(null, 'untraced', step => step.stamp());
|
|
62
70
|
|
|
63
|
-
test('returns
|
|
64
|
-
await expect(subject()).resolves.
|
|
71
|
+
test('returns undefined', async () => {
|
|
72
|
+
await expect(subject()).resolves.toBeUndefined();
|
|
65
73
|
});
|
|
66
74
|
});
|
|
67
75
|
|
|
68
76
|
describe('with an open journey', () => {
|
|
69
77
|
beforeEach(() => {
|
|
70
|
-
startJourney(baseDef);
|
|
78
|
+
moduleRuntime.startJourney(baseDef);
|
|
71
79
|
});
|
|
72
80
|
|
|
73
81
|
describe('when the step completes with tags', () => {
|
|
74
82
|
const subject = () =>
|
|
75
83
|
journeyStep(baseDef.name, 'do-work', step => {
|
|
76
84
|
step.setAttribute('x', 1);
|
|
77
|
-
step.
|
|
85
|
+
step.completeJourney({ 'payment.id': 42 });
|
|
78
86
|
});
|
|
79
87
|
|
|
80
88
|
test('emits good with tags and attributes', async () => {
|
|
@@ -105,29 +113,63 @@ describe('[journey] journeyStep', () => {
|
|
|
105
113
|
});
|
|
106
114
|
});
|
|
107
115
|
|
|
108
|
-
describe('when
|
|
109
|
-
|
|
116
|
+
describe('when setAttribute uses unsafe or overflowing keys', () => {
|
|
117
|
+
test('skips prototype keys and caps the map', async () => {
|
|
118
|
+
await journeyStep(baseDef.name, 'attrs', step => {
|
|
119
|
+
step.setAttribute('__proto__', 'nope');
|
|
120
|
+
step.setAttribute('token', 'secret');
|
|
121
|
+
step.setAttribute('ok', 1);
|
|
122
|
+
for (let i = 0; i < 70; i += 1) {
|
|
123
|
+
step.setAttribute(`k${i}`, i);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
completeJourney(baseDef.name);
|
|
127
|
+
|
|
128
|
+
const attributes = lastJourney(emitMock).steps[0].attributes as Record<
|
|
129
|
+
string,
|
|
130
|
+
unknown
|
|
131
|
+
>;
|
|
132
|
+
expect(Object.prototype.hasOwnProperty.call(attributes, '__proto__')).toBe(false);
|
|
133
|
+
expect(attributes.token).toBeUndefined();
|
|
134
|
+
expect(attributes.ok).toBe(1);
|
|
135
|
+
expect(Object.keys(attributes).length).toBe(64);
|
|
136
|
+
expect(({} as { polluted?: boolean }).polluted).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('when step.stamp is called', () => {
|
|
141
|
+
let tagged: JourneyStepStamp | undefined;
|
|
110
142
|
|
|
111
143
|
beforeEach(() => {
|
|
112
|
-
tagged =
|
|
144
|
+
tagged = undefined;
|
|
113
145
|
});
|
|
114
146
|
|
|
115
147
|
const subject = () =>
|
|
116
148
|
journeyStep(baseDef.name, 'do-work', step => {
|
|
117
|
-
tagged = step.
|
|
149
|
+
tagged = step.stamp();
|
|
118
150
|
});
|
|
119
151
|
|
|
120
|
-
test('binds
|
|
152
|
+
test('binds stamp', async () => {
|
|
121
153
|
await subject();
|
|
122
154
|
|
|
123
|
-
expect(tagged).
|
|
155
|
+
expect(tagged).toBeInstanceOf(JourneyStepStamp);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('when step.stamp is called with a score function', () => {
|
|
160
|
+
test('stores score on the stamp', async () => {
|
|
161
|
+
await journeyStep(baseDef.name, 'do-work', step => {
|
|
162
|
+
const score = () => 'exclude' as const;
|
|
163
|
+
const stamp = step.stamp(score);
|
|
164
|
+
expect(stamp?.score).toBe(score);
|
|
165
|
+
});
|
|
124
166
|
});
|
|
125
167
|
});
|
|
126
168
|
|
|
127
|
-
describe('when step.
|
|
169
|
+
describe('when step.failJourney is called', () => {
|
|
128
170
|
const subject = () =>
|
|
129
171
|
journeyStep(baseDef.name, 'do-work', step => {
|
|
130
|
-
step.
|
|
172
|
+
step.failJourney('empty-catalog');
|
|
131
173
|
});
|
|
132
174
|
|
|
133
175
|
test('marks bad without throwing', async () => {
|
|
@@ -147,7 +189,7 @@ describe('[journey] journeyStep', () => {
|
|
|
147
189
|
test('marks step-error and rethrows', async () => {
|
|
148
190
|
await expect(subject()).rejects.toThrow('boom');
|
|
149
191
|
expect(lastJourney(emitMock).reason).toBe('step-error');
|
|
150
|
-
expect(lastJourney(emitMock).steps[0].attributes).
|
|
192
|
+
expect(lastJourney(emitMock).steps[0].attributes).toBeUndefined();
|
|
151
193
|
});
|
|
152
194
|
});
|
|
153
195
|
|
|
@@ -158,27 +200,22 @@ describe('[journey] journeyStep', () => {
|
|
|
158
200
|
throw 'string-boom';
|
|
159
201
|
});
|
|
160
202
|
|
|
161
|
-
test('
|
|
203
|
+
test('does not stringify the throw onto attributes', async () => {
|
|
162
204
|
await expect(subject()).rejects.toBe('string-boom');
|
|
163
|
-
expect(lastJourney(emitMock).steps[0].attributes).
|
|
164
|
-
error: 'string-boom',
|
|
165
|
-
});
|
|
205
|
+
expect(lastJourney(emitMock).steps[0].attributes).toBeUndefined();
|
|
166
206
|
});
|
|
167
207
|
});
|
|
168
208
|
|
|
169
209
|
describe('when error is pre-set on the step', () => {
|
|
170
210
|
const subject = () =>
|
|
171
211
|
journeyStep(baseDef.name, 'do-work', step => {
|
|
172
|
-
|
|
173
|
-
(step.tag() as { journeyStep: unknown }).journeyStep
|
|
174
|
-
)!;
|
|
175
|
-
ref.attributes.error = 'already';
|
|
212
|
+
step.setAttribute('phase', 'load');
|
|
176
213
|
throw new Error('boom');
|
|
177
214
|
});
|
|
178
215
|
|
|
179
|
-
test('
|
|
216
|
+
test('keeps developer attributes', async () => {
|
|
180
217
|
await expect(subject()).rejects.toThrow('boom');
|
|
181
|
-
expect(lastJourney(emitMock).steps[0].attributes).toEqual({
|
|
218
|
+
expect(lastJourney(emitMock).steps[0].attributes).toEqual({ phase: 'load' });
|
|
182
219
|
});
|
|
183
220
|
});
|
|
184
221
|
|
|
@@ -186,7 +223,7 @@ describe('[journey] journeyStep', () => {
|
|
|
186
223
|
beforeEach(() => {
|
|
187
224
|
// Parent already opened baseDef; restart with expected steps.
|
|
188
225
|
emitMock.mockClear();
|
|
189
|
-
startJourney({ ...baseDef,
|
|
226
|
+
moduleRuntime.startJourney({ ...baseDef, expected: ['load', 'save'] });
|
|
190
227
|
emitMock.mockClear();
|
|
191
228
|
});
|
|
192
229
|
|
|
@@ -197,7 +234,7 @@ describe('[journey] journeyStep', () => {
|
|
|
197
234
|
expect(emitMock).not.toHaveBeenCalled();
|
|
198
235
|
|
|
199
236
|
await journeyStep(baseDef.name, 'save', step => {
|
|
200
|
-
step.
|
|
237
|
+
step.completeJourney({ done: true });
|
|
201
238
|
});
|
|
202
239
|
|
|
203
240
|
expect(emitMock).toHaveBeenCalledTimes(1);
|
|
@@ -212,8 +249,8 @@ describe('[journey] journeyStep', () => {
|
|
|
212
249
|
describe('with a JourneyDef-like object target', () => {
|
|
213
250
|
const subject = () =>
|
|
214
251
|
journeyStep(baseDef, 'via-def', step => {
|
|
215
|
-
step.
|
|
216
|
-
return step.
|
|
252
|
+
step.completeJourney();
|
|
253
|
+
return step.journeyName;
|
|
217
254
|
});
|
|
218
255
|
|
|
219
256
|
test('resolves the def name', async () => {
|
|
@@ -238,13 +275,13 @@ describe('[journey] journeyStep', () => {
|
|
|
238
275
|
describe('journeyMountStep', () => {
|
|
239
276
|
describe('with candidates', () => {
|
|
240
277
|
beforeEach(() => {
|
|
241
|
-
startJourney(baseDef);
|
|
278
|
+
moduleRuntime.startJourney(baseDef);
|
|
242
279
|
});
|
|
243
280
|
|
|
244
281
|
const subject = () =>
|
|
245
|
-
journeyMountStep(['missing', baseDef.name], 'mount-load', step => {
|
|
246
|
-
step.
|
|
247
|
-
return step.
|
|
282
|
+
moduleRuntime.journeyMountStep(['missing', baseDef.name], 'mount-load', step => {
|
|
283
|
+
step.completeJourney();
|
|
284
|
+
return step.journeyName;
|
|
248
285
|
});
|
|
249
286
|
|
|
250
287
|
test('resolves the open candidate', async () => {
|
|
@@ -260,10 +297,10 @@ describe('[journey] journeyStep', () => {
|
|
|
260
297
|
});
|
|
261
298
|
|
|
262
299
|
test('defers until after a sync startJourney', async () => {
|
|
263
|
-
const mount = journeyMountStep(baseDef.name, 'boot', () => {
|
|
300
|
+
const mount = moduleRuntime.journeyMountStep(baseDef.name, 'boot', () => {
|
|
264
301
|
order.push('mount-step');
|
|
265
302
|
});
|
|
266
|
-
startJourney(baseDef);
|
|
303
|
+
moduleRuntime.startJourney(baseDef);
|
|
267
304
|
order.push('started');
|
|
268
305
|
await mount;
|
|
269
306
|
completeJourney(baseDef.name);
|
|
@@ -276,7 +313,7 @@ describe('[journey] journeyStep', () => {
|
|
|
276
313
|
describe('when fail-fast happens mid-step', () => {
|
|
277
314
|
beforeEach(() => {
|
|
278
315
|
jest.spyOn(globalThis.performance, 'now').mockReturnValue(1_000);
|
|
279
|
-
startJourney(baseDef);
|
|
316
|
+
moduleRuntime.startJourney(baseDef);
|
|
280
317
|
});
|
|
281
318
|
|
|
282
319
|
afterEach(() => {
|
|
@@ -302,4 +339,61 @@ describe('[journey] journeyStep', () => {
|
|
|
302
339
|
await stepPromise;
|
|
303
340
|
});
|
|
304
341
|
});
|
|
342
|
+
|
|
343
|
+
describe('when the same name is restarted while a step is in flight', () => {
|
|
344
|
+
test('completeJourney on the old step does not close the new instance', async () => {
|
|
345
|
+
moduleRuntime.startJourney(baseDef);
|
|
346
|
+
let resolveWork!: () => void;
|
|
347
|
+
const hang = new Promise<void>(resolve => {
|
|
348
|
+
resolveWork = resolve;
|
|
349
|
+
});
|
|
350
|
+
const stepPromise = journeyStep(baseDef.name, 'slow', async step => {
|
|
351
|
+
await hang;
|
|
352
|
+
step.completeJourney();
|
|
353
|
+
});
|
|
354
|
+
await Promise.resolve();
|
|
355
|
+
moduleRuntime.startJourney(baseDef);
|
|
356
|
+
expect(lastJourney(emitMock).outcome).toBe('excluded');
|
|
357
|
+
emitMock.mockClear();
|
|
358
|
+
|
|
359
|
+
resolveWork();
|
|
360
|
+
await stepPromise;
|
|
361
|
+
expect(emitMock).not.toHaveBeenCalled();
|
|
362
|
+
|
|
363
|
+
completeJourney(baseDef.name);
|
|
364
|
+
expect(lastJourney(emitMock).outcome).toBe('good');
|
|
365
|
+
expect(lastJourney(emitMock).steps).toHaveLength(0);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe('when maxSteps is exceeded', () => {
|
|
370
|
+
test('stops recording steps and sets steps_truncated', async () => {
|
|
371
|
+
moduleRuntime.startJourney({ ...baseDef, maxSteps: 2 });
|
|
372
|
+
await journeyStep(baseDef.name, 'a', () => {});
|
|
373
|
+
await journeyStep(baseDef.name, 'b', () => {});
|
|
374
|
+
await journeyStep(baseDef.name, 'c', () => {});
|
|
375
|
+
completeJourney(baseDef.name);
|
|
376
|
+
|
|
377
|
+
expect(lastJourney(emitMock).steps.map((s: { name: string }) => s.name)).toEqual([
|
|
378
|
+
'a',
|
|
379
|
+
'b',
|
|
380
|
+
]);
|
|
381
|
+
expect(lastJourney(emitMock).tags?.steps_truncated).toBe(true);
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
describe('when the started config is frozen', () => {
|
|
386
|
+
test('rejects mutation of the snapshot', () => {
|
|
387
|
+
const config = { ...baseDef, name: 'frozen-def' };
|
|
388
|
+
moduleRuntime.startJourney(config);
|
|
389
|
+
const snapshot = moduleRuntime.getOpenJourney('frozen-def')!.config;
|
|
390
|
+
expect(Object.isFrozen(snapshot)).toBe(true);
|
|
391
|
+
expect(snapshot).not.toBe(config);
|
|
392
|
+
expect(() => {
|
|
393
|
+
(snapshot as { name: string }).name = 'hacked';
|
|
394
|
+
}).toThrow();
|
|
395
|
+
expect(snapshot.name).toBe('frozen-def');
|
|
396
|
+
completeJourney('frozen-def');
|
|
397
|
+
});
|
|
398
|
+
});
|
|
305
399
|
});
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/** @jest-environment jsdom */
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
baseJourneyDef,
|
|
4
|
+
lastJourney,
|
|
5
|
+
useJourneyTestRuntime,
|
|
6
|
+
} from '../../__test-utils__/test-runtime';
|
|
7
|
+
import type { JourneyStepStamp } from '../../core';
|
|
8
|
+
import { completeJourney, journeyStep } from '../../core';
|
|
9
|
+
import { moduleRuntime } from '../../core/runtime';
|
|
4
10
|
|
|
5
11
|
const emitMock = jest.fn();
|
|
6
12
|
const baseDef = { ...baseJourneyDef, name: 'timeout-api' };
|
|
@@ -18,7 +24,7 @@ describe('[journey] timeouts', () => {
|
|
|
18
24
|
|
|
19
25
|
describe('with a journey timeoutMs', () => {
|
|
20
26
|
beforeEach(() => {
|
|
21
|
-
startJourney({ ...baseDef, timeoutMs: 50 });
|
|
27
|
+
moduleRuntime.startJourney({ ...baseDef, timeoutMs: 50 });
|
|
22
28
|
});
|
|
23
29
|
|
|
24
30
|
const subject = () => jest.advanceTimersByTimeAsync(50);
|
|
@@ -33,7 +39,7 @@ describe('[journey] timeouts', () => {
|
|
|
33
39
|
|
|
34
40
|
describe('with timeoutMs 0', () => {
|
|
35
41
|
beforeEach(() => {
|
|
36
|
-
startJourney({ ...baseDef, timeoutMs: 0 });
|
|
42
|
+
moduleRuntime.startJourney({ ...baseDef, timeoutMs: 0 });
|
|
37
43
|
});
|
|
38
44
|
|
|
39
45
|
const subject = () => jest.advanceTimersByTimeAsync(60_000);
|
|
@@ -47,12 +53,30 @@ describe('[journey] timeouts', () => {
|
|
|
47
53
|
});
|
|
48
54
|
});
|
|
49
55
|
|
|
56
|
+
describe('without timeoutMs', () => {
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
moduleRuntime.startJourney({
|
|
59
|
+
name: 'timeout-idle',
|
|
60
|
+
team: baseDef.team,
|
|
61
|
+
group: baseDef.group,
|
|
62
|
+
service: baseDef.service,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('closes excluded with journey-idle-timeout after default idle window', async () => {
|
|
67
|
+
await jest.advanceTimersByTimeAsync(15 * 60 * 1_000);
|
|
68
|
+
|
|
69
|
+
expect(lastJourney(emitMock).outcome).toBe('excluded');
|
|
70
|
+
expect(lastJourney(emitMock).reason).toBe('journey-idle-timeout');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
50
74
|
describe('with a step timeoutMs', () => {
|
|
51
75
|
let resolveWork!: () => void;
|
|
52
76
|
let stepPromise: Promise<unknown>;
|
|
53
77
|
|
|
54
78
|
beforeEach(() => {
|
|
55
|
-
startJourney({ ...baseDef, stepTimeoutMs: 40 });
|
|
79
|
+
moduleRuntime.startJourney({ ...baseDef, stepTimeoutMs: 40 });
|
|
56
80
|
const hang = new Promise<void>(resolve => {
|
|
57
81
|
resolveWork = resolve;
|
|
58
82
|
});
|
|
@@ -81,7 +105,7 @@ describe('[journey] timeouts', () => {
|
|
|
81
105
|
let stepPromise: Promise<unknown>;
|
|
82
106
|
|
|
83
107
|
beforeEach(() => {
|
|
84
|
-
startJourney({ ...baseDef, stepTimeoutMs: 5_000 });
|
|
108
|
+
moduleRuntime.startJourney({ ...baseDef, stepTimeoutMs: 5_000 });
|
|
85
109
|
const hang = new Promise<void>(resolve => {
|
|
86
110
|
resolveWork = resolve;
|
|
87
111
|
});
|
|
@@ -114,7 +138,7 @@ describe('[journey] timeouts', () => {
|
|
|
114
138
|
let stepPromise: Promise<unknown>;
|
|
115
139
|
|
|
116
140
|
beforeEach(() => {
|
|
117
|
-
startJourney({ ...baseDef, stepTimeoutMs: 40 });
|
|
141
|
+
moduleRuntime.startJourney({ ...baseDef, stepTimeoutMs: 40 });
|
|
118
142
|
const hang = new Promise<void>(resolve => {
|
|
119
143
|
resolveWork = resolve;
|
|
120
144
|
});
|
|
@@ -144,14 +168,12 @@ describe('[journey] timeouts', () => {
|
|
|
144
168
|
let stepPromise: Promise<unknown>;
|
|
145
169
|
|
|
146
170
|
beforeEach(() => {
|
|
147
|
-
startJourney({ ...baseDef, stepTimeoutMs: 40 });
|
|
171
|
+
moduleRuntime.startJourney({ ...baseDef, stepTimeoutMs: 40 });
|
|
148
172
|
const hang = new Promise<void>(resolve => {
|
|
149
173
|
resolveWork = resolve;
|
|
150
174
|
});
|
|
151
175
|
stepPromise = journeyStep(baseDef.name, 'slow', async step => {
|
|
152
|
-
const ref =
|
|
153
|
-
(step.tag() as { journeyStep: unknown }).journeyStep
|
|
154
|
-
)!;
|
|
176
|
+
const ref = (step.stamp() as JourneyStepStamp).step;
|
|
155
177
|
ref.reason = 'pre-existing';
|
|
156
178
|
ref.attributes.timeout_ms = 999;
|
|
157
179
|
await hang;
|
|
@@ -176,7 +198,7 @@ describe('[journey] timeouts', () => {
|
|
|
176
198
|
describe('when clearTimeout is bypassed after complete', () => {
|
|
177
199
|
beforeEach(() => {
|
|
178
200
|
jest.spyOn(globalThis, 'clearTimeout').mockImplementation(() => {});
|
|
179
|
-
startJourney({ ...baseDef, timeoutMs: 50 });
|
|
201
|
+
moduleRuntime.startJourney({ ...baseDef, timeoutMs: 50 });
|
|
180
202
|
completeJourney(baseDef.name);
|
|
181
203
|
emitMock.mockClear();
|
|
182
204
|
});
|
|
@@ -194,12 +216,40 @@ describe('[journey] timeouts', () => {
|
|
|
194
216
|
});
|
|
195
217
|
});
|
|
196
218
|
|
|
219
|
+
describe('when a journey timeout closes a hung step', () => {
|
|
220
|
+
let releaseWork!: () => void;
|
|
221
|
+
let stepPromise: Promise<unknown>;
|
|
222
|
+
|
|
223
|
+
beforeEach(() => {
|
|
224
|
+
moduleRuntime.startJourney({ ...baseDef, timeoutMs: 50 });
|
|
225
|
+
const hang = new Promise<void>(resolve => {
|
|
226
|
+
releaseWork = resolve;
|
|
227
|
+
});
|
|
228
|
+
stepPromise = journeyStep(baseDef.name, 'slow', async () => {
|
|
229
|
+
await hang;
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
afterEach(async () => {
|
|
234
|
+
releaseWork();
|
|
235
|
+
await stepPromise;
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test('releases inFlight state before the step settles', async () => {
|
|
239
|
+
await jest.advanceTimersByTimeAsync(50);
|
|
240
|
+
|
|
241
|
+
expect(moduleRuntime.activeJourneyStep()).toBeNull();
|
|
242
|
+
expect(lastJourney(emitMock).outcome).toBe('bad');
|
|
243
|
+
expect(lastJourney(emitMock).reason).toBe('journey-timeout');
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
197
247
|
describe('with stepTimeoutMs 0', () => {
|
|
198
248
|
let resolveWork!: () => void;
|
|
199
249
|
let stepPromise: Promise<unknown>;
|
|
200
250
|
|
|
201
251
|
beforeEach(() => {
|
|
202
|
-
startJourney({ ...baseDef, stepTimeoutMs: 0 });
|
|
252
|
+
moduleRuntime.startJourney({ ...baseDef, stepTimeoutMs: 0 });
|
|
203
253
|
const hang = new Promise<void>(resolve => {
|
|
204
254
|
resolveWork = resolve;
|
|
205
255
|
});
|
|
@@ -223,4 +273,24 @@ describe('[journey] timeouts', () => {
|
|
|
223
273
|
expect(lastJourney(emitMock).outcome).toBe('good');
|
|
224
274
|
});
|
|
225
275
|
});
|
|
276
|
+
|
|
277
|
+
describe('with non-finite timeoutMs', () => {
|
|
278
|
+
test('Infinity disables the countdown', async () => {
|
|
279
|
+
moduleRuntime.startJourney({ ...baseDef, timeoutMs: Infinity });
|
|
280
|
+
await jest.advanceTimersByTimeAsync(60_000);
|
|
281
|
+
|
|
282
|
+
expect(emitMock).not.toHaveBeenCalled();
|
|
283
|
+
completeJourney(baseDef.name);
|
|
284
|
+
expect(lastJourney(emitMock).outcome).toBe('good');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test('NaN disables the countdown', async () => {
|
|
288
|
+
moduleRuntime.startJourney({ ...baseDef, timeoutMs: Number.NaN });
|
|
289
|
+
await jest.advanceTimersByTimeAsync(60_000);
|
|
290
|
+
|
|
291
|
+
expect(emitMock).not.toHaveBeenCalled();
|
|
292
|
+
completeJourney(baseDef.name);
|
|
293
|
+
expect(lastJourney(emitMock).outcome).toBe('good');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
226
296
|
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
import '../config';
|
|
3
|
+
import { defineJourney, resetJourney } from '../core';
|
|
4
|
+
import { moduleRuntime } from '../core/runtime';
|
|
5
|
+
import {
|
|
6
|
+
JOURNEY_DEBUG_STORAGE_KEY,
|
|
7
|
+
JOURNEY_ENABLED_STORAGE_KEY,
|
|
8
|
+
ST_JOURNEY_GLOBAL_KEY,
|
|
9
|
+
ST_JOURNEY_SCHEMA_VERSION,
|
|
10
|
+
disableJourney,
|
|
11
|
+
enableJourney,
|
|
12
|
+
isJourneyEnabled,
|
|
13
|
+
setJourneyDefaultEnabled,
|
|
14
|
+
type StJourneyGlobal,
|
|
15
|
+
} from '../global';
|
|
16
|
+
import { setJourneyRum } from '../sinks/datadog';
|
|
17
|
+
|
|
18
|
+
function getStJourney(): StJourneyGlobal {
|
|
19
|
+
return (globalThis as Record<string, unknown>)[ST_JOURNEY_GLOBAL_KEY] as StJourneyGlobal;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe('[journey] __stJourney global', () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
localStorage.clear();
|
|
25
|
+
sessionStorage.clear();
|
|
26
|
+
setJourneyDefaultEnabled(false);
|
|
27
|
+
delete getStJourney().rum;
|
|
28
|
+
delete (globalThis as Record<string, unknown>).DD_RUM;
|
|
29
|
+
resetJourney({ sinks: [] });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
localStorage.clear();
|
|
34
|
+
sessionStorage.clear();
|
|
35
|
+
setJourneyDefaultEnabled(false);
|
|
36
|
+
delete getStJourney().rum;
|
|
37
|
+
delete (globalThis as Record<string, unknown>).DD_RUM;
|
|
38
|
+
resetJourney({ sinks: [] });
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('installs __stJourney on package load', () => {
|
|
42
|
+
expect(getStJourney()).toEqual(
|
|
43
|
+
expect.objectContaining({
|
|
44
|
+
schemaVersion: ST_JOURNEY_SCHEMA_VERSION,
|
|
45
|
+
enable: expect.any(Function),
|
|
46
|
+
disable: expect.any(Function),
|
|
47
|
+
isEnabled: expect.any(Function),
|
|
48
|
+
enableDebugging: expect.any(Function),
|
|
49
|
+
disableDebugging: expect.any(Function),
|
|
50
|
+
isDebugEnabled: expect.any(Function),
|
|
51
|
+
getDebugState: expect.any(Function),
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('enable / disable toggle force-enable localStorage', () => {
|
|
57
|
+
expect(isJourneyEnabled()).toBe(false);
|
|
58
|
+
|
|
59
|
+
enableJourney();
|
|
60
|
+
expect(localStorage.getItem(JOURNEY_ENABLED_STORAGE_KEY)).toBe('true');
|
|
61
|
+
expect(isJourneyEnabled()).toBe(true);
|
|
62
|
+
expect(getStJourney().isEnabled()).toBe(true);
|
|
63
|
+
|
|
64
|
+
disableJourney();
|
|
65
|
+
expect(localStorage.getItem(JOURNEY_ENABLED_STORAGE_KEY)).toBeNull();
|
|
66
|
+
expect(isJourneyEnabled()).toBe(false);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('isJourneyEnabled is true when host default is on', () => {
|
|
70
|
+
expect(isJourneyEnabled()).toBe(false);
|
|
71
|
+
|
|
72
|
+
setJourneyDefaultEnabled(true);
|
|
73
|
+
expect(isJourneyEnabled()).toBe(true);
|
|
74
|
+
expect(getStJourney().isEnabled()).toBe(true);
|
|
75
|
+
|
|
76
|
+
setJourneyDefaultEnabled(false);
|
|
77
|
+
expect(isJourneyEnabled()).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('isJourneyEnabled is true when either host default or force flag is on', () => {
|
|
81
|
+
setJourneyDefaultEnabled(true);
|
|
82
|
+
enableJourney();
|
|
83
|
+
expect(isJourneyEnabled()).toBe(true);
|
|
84
|
+
|
|
85
|
+
setJourneyDefaultEnabled(false);
|
|
86
|
+
expect(isJourneyEnabled()).toBe(true);
|
|
87
|
+
|
|
88
|
+
disableJourney();
|
|
89
|
+
expect(isJourneyEnabled()).toBe(false);
|
|
90
|
+
|
|
91
|
+
setJourneyDefaultEnabled(true);
|
|
92
|
+
expect(isJourneyEnabled()).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('host default is shared on __stJourney for cross-bundle reads', () => {
|
|
96
|
+
setJourneyDefaultEnabled(true);
|
|
97
|
+
expect(getStJourney().defaultEnabled).toBe(true);
|
|
98
|
+
expect(isJourneyEnabled()).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('enableDebugging / disableDebugging toggle console-debug sessionStorage', () => {
|
|
102
|
+
const st = getStJourney();
|
|
103
|
+
|
|
104
|
+
st.enableDebugging();
|
|
105
|
+
expect(sessionStorage.getItem(JOURNEY_DEBUG_STORAGE_KEY)).toBe('true');
|
|
106
|
+
expect(st.isDebugEnabled()).toBe(true);
|
|
107
|
+
|
|
108
|
+
st.disableDebugging();
|
|
109
|
+
expect(sessionStorage.getItem(JOURNEY_DEBUG_STORAGE_KEY)).toBeNull();
|
|
110
|
+
expect(st.isDebugEnabled()).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('getDebugState omits runtimes until debugging is enabled', () => {
|
|
114
|
+
enableJourney();
|
|
115
|
+
const journey = defineJourney({
|
|
116
|
+
name: 'Book Job',
|
|
117
|
+
team: 'jbce',
|
|
118
|
+
group: 'call-booking',
|
|
119
|
+
service: 'call-screen',
|
|
120
|
+
});
|
|
121
|
+
journey.start();
|
|
122
|
+
|
|
123
|
+
expect(getStJourney().getDebugState()).toEqual(
|
|
124
|
+
expect.objectContaining({
|
|
125
|
+
enabled: true,
|
|
126
|
+
debug: false,
|
|
127
|
+
runtimes: [],
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
getStJourney().enableDebugging();
|
|
132
|
+
const on = getStJourney().getDebugState();
|
|
133
|
+
expect(on.debug).toBe(true);
|
|
134
|
+
expect(on.runtimes.some(r => r.id === moduleRuntime.id)).toBe(true);
|
|
135
|
+
expect(on.runtimes.some(r => r.openJourneys.some(j => j.name === 'Book Job'))).toBe(true);
|
|
136
|
+
|
|
137
|
+
getStJourney().disableDebugging();
|
|
138
|
+
expect(getStJourney().getDebugState().runtimes).toEqual([]);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('getDebugState.hasRum reflects DD_RUM or the fallback bridge', () => {
|
|
142
|
+
getStJourney().enableDebugging();
|
|
143
|
+
|
|
144
|
+
expect(getStJourney().getDebugState().hasRum).toBe(false);
|
|
145
|
+
|
|
146
|
+
(globalThis as Record<string, unknown>).DD_RUM = { addAction: jest.fn() };
|
|
147
|
+
expect(getStJourney().getDebugState().hasRum).toBe(true);
|
|
148
|
+
|
|
149
|
+
delete (globalThis as Record<string, unknown>).DD_RUM;
|
|
150
|
+
jest.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
151
|
+
setJourneyRum({ addAction: jest.fn() });
|
|
152
|
+
expect(getStJourney().getDebugState().hasRum).toBe(true);
|
|
153
|
+
});
|
|
154
|
+
});
|