Skip to content

Commit 55969dd

Browse files
committed
Add tests and put feature under feature flag
1 parent ec0bbd7 commit 55969dd

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed

packages/core/src/tools/experimentalFeatures.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export enum ExperimentalFeature {
1919
FEATURE_OPERATION_VITAL = 'feature_operation_vital',
2020
SHORT_SESSION_INVESTIGATION = 'short_session_investigation',
2121
AVOID_FETCH_KEEPALIVE = 'avoid_fetch_keepalive',
22+
SOURCE_CODE_CONTEXT = 'source_code_context',
2223
}
2324

2425
const enabledExperimentalFeatures: Set<ExperimentalFeature> = new Set()
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import { ExperimentalFeature, HookNames } from '@datadog/browser-core'
2+
import type { RelativeTime } from '@datadog/browser-core'
3+
import type { Hooks } from '../hooks'
4+
import { createHooks } from '../hooks'
5+
import { mockExperimentalFeatures, registerCleanupTask } from '../../../../core/test'
6+
import type { BrowserWindow } from './sourceCodeContext'
7+
import { startSourceCodeContext } from './sourceCodeContext'
8+
9+
describe('sourceCodeContext', () => {
10+
let hooks: Hooks
11+
let browserWindow: BrowserWindow
12+
const TEST_STACK = `Error: Test error
13+
at testFunction (http://localhost:8080/file.js:41:27)
14+
at HTMLButtonElement.onclick (http://localhost:8080/file-2.js:107:146)`
15+
16+
const MATCHING_TEST_STACK = `Error: Another error
17+
at anotherFunction (http://localhost:8080/file.js:41:27)
18+
at HTMLButtonElement.onPointerUp (http://localhost:8080/another-file.js:107:146)`
19+
20+
beforeEach(() => {
21+
hooks = createHooks()
22+
browserWindow = window as BrowserWindow
23+
})
24+
25+
function setupBrowserWindowWithContext() {
26+
browserWindow.DD_SOURCE_CODE_CONTEXT = {
27+
[TEST_STACK]: {
28+
service: 'my-service',
29+
version: '1.0.0',
30+
},
31+
}
32+
33+
registerCleanupTask(() => {
34+
delete browserWindow.DD_SOURCE_CODE_CONTEXT
35+
})
36+
}
37+
38+
describe('assemble hook when FF disabled', () => {
39+
it('should not add source code context', () => {
40+
setupBrowserWindowWithContext()
41+
startSourceCodeContext(hooks)
42+
43+
const result = hooks.triggerHook(HookNames.Assemble, {
44+
eventType: 'error',
45+
startTime: 0 as RelativeTime,
46+
domainContext: {},
47+
rawRumEvent: {
48+
type: 'error',
49+
error: {
50+
stack: MATCHING_TEST_STACK,
51+
},
52+
} as any,
53+
})
54+
55+
expect(result).toBeUndefined()
56+
})
57+
})
58+
59+
describe('assemble hook when FF enabled', () => {
60+
beforeEach(() => {
61+
mockExperimentalFeatures([ExperimentalFeature.SOURCE_CODE_CONTEXT])
62+
})
63+
64+
it('should add source code context matching the error stack first frame URL', () => {
65+
setupBrowserWindowWithContext()
66+
startSourceCodeContext(hooks)
67+
68+
const result = hooks.triggerHook(HookNames.Assemble, {
69+
eventType: 'error',
70+
startTime: 0 as RelativeTime,
71+
domainContext: {},
72+
rawRumEvent: {
73+
type: 'error',
74+
error: {
75+
stack: MATCHING_TEST_STACK,
76+
},
77+
} as any,
78+
})
79+
80+
expect(result).toEqual({
81+
type: 'error',
82+
service: 'my-service',
83+
version: '1.0.0',
84+
})
85+
})
86+
87+
it('should add source code context matching the handling_stack first frame URL', () => {
88+
setupBrowserWindowWithContext()
89+
startSourceCodeContext(hooks)
90+
91+
const result = hooks.triggerHook(HookNames.Assemble, {
92+
eventType: 'action',
93+
startTime: 0 as RelativeTime,
94+
rawRumEvent: {
95+
type: 'action',
96+
} as any,
97+
domainContext: {
98+
handling_stack: MATCHING_TEST_STACK,
99+
},
100+
})
101+
102+
expect(result).toEqual({
103+
type: 'action',
104+
service: 'my-service',
105+
version: '1.0.0',
106+
})
107+
})
108+
109+
it('should not add source code context matching no stack', () => {
110+
setupBrowserWindowWithContext()
111+
startSourceCodeContext(hooks)
112+
113+
const result = hooks.triggerHook(HookNames.Assemble, {
114+
eventType: 'error',
115+
startTime: 0 as RelativeTime,
116+
domainContext: {},
117+
rawRumEvent: {
118+
type: 'error',
119+
error: {
120+
stack: `Error: Another error
121+
at anotherFunction (http://localhost:8080/another-file.js:41:27)`,
122+
},
123+
} as any,
124+
})
125+
126+
expect(result).toBeUndefined()
127+
})
128+
129+
it('should support late updates to DD_SOURCE_CODE_CONTEXT', () => {
130+
startSourceCodeContext(hooks)
131+
132+
// Add context AFTER initialization
133+
setupBrowserWindowWithContext()
134+
135+
const result = hooks.triggerHook(HookNames.Assemble, {
136+
eventType: 'error',
137+
startTime: 0 as RelativeTime,
138+
domainContext: {},
139+
rawRumEvent: {
140+
type: 'error',
141+
error: {
142+
stack: TEST_STACK,
143+
},
144+
} as any,
145+
})
146+
147+
expect(result).toEqual({
148+
type: 'error',
149+
service: 'my-service',
150+
version: '1.0.0',
151+
})
152+
})
153+
154+
it('should ignore updates to existing source code context after initialization', () => {
155+
setupBrowserWindowWithContext()
156+
startSourceCodeContext(hooks)
157+
158+
// Update existing entry
159+
browserWindow.DD_SOURCE_CODE_CONTEXT![TEST_STACK] = {
160+
service: 'updated-service',
161+
version: '1.1.0',
162+
}
163+
164+
const result = hooks.triggerHook(HookNames.Assemble, {
165+
eventType: 'error',
166+
startTime: 0 as RelativeTime,
167+
domainContext: {},
168+
rawRumEvent: {
169+
type: 'error',
170+
error: {
171+
stack: TEST_STACK,
172+
},
173+
} as any,
174+
})
175+
176+
expect(result).toEqual({
177+
type: 'error',
178+
service: 'my-service',
179+
version: '1.0.0',
180+
})
181+
})
182+
})
183+
})

0 commit comments

Comments
 (0)