Skip to content

Commit 2e8dc1d

Browse files
committed
fix tests
1 parent c2cb472 commit 2e8dc1d

File tree

5 files changed

+184
-274
lines changed

5 files changed

+184
-274
lines changed

dev-packages/browser-integration-tests/suites/profiling/legacyMode/test.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ sentryTest(
1515
sentryTest.skip();
1616
}
1717

18-
if (shouldSkipTracingTest()) {
19-
// Profiling only works when tracing is enabled
20-
sentryTest.skip();
21-
}
22-
2318
const url = await getLocalTestUrl({ testDir: __dirname });
2419

2520
const req = await waitForTransactionRequestOnUrl(page, url);

dev-packages/browser-integration-tests/suites/profiling/traceLifecycleMode_multiple-chunks/subject.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,5 @@ await Sentry.startSpanManual({ name: 'root-largeSum-2', parentSpan: null, forceT
4444
span.end();
4545
});
4646

47-
// Ensure envelope flush
4847
const client = Sentry.getClient();
4948
await client?.flush(5000);

dev-packages/browser-integration-tests/suites/profiling/traceLifecycleMode_multiple-chunks/test.ts

Lines changed: 169 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -8,142 +8,174 @@ import {
88
shouldSkipTracingTest,
99
} from '../../../utils/helpers';
1010

11-
sentryTest('does not send profile envelope when document-policy is not set', async ({ page, getLocalTestUrl }) => {
12-
if (shouldSkipTracingTest()) {
13-
// Profiling only works when tracing is enabled
14-
sentryTest.skip();
15-
}
16-
17-
const url = await getLocalTestUrl({ testDir: __dirname });
18-
19-
// Assert that no profile_chunk envelope is sent without policy header
20-
const chunkCount = await countEnvelopes(page, { url, envelopeType: 'profile_chunk', timeout: 1500 });
21-
expect(chunkCount).toBe(0);
22-
});
23-
24-
sentryTest('sends profile_chunk envelopes in trace mode (multiple chunks)', async ({ page, getLocalTestUrl, browserName }) => {
25-
if (shouldSkipTracingTest() || browserName !== 'chromium') {
26-
// Profiling only works when tracing is enabled
27-
sentryTest.skip();
28-
}
29-
30-
const url = await getLocalTestUrl({ testDir: __dirname, responseHeaders: { 'Document-Policy': 'js-profiling' } });
31-
await page.goto(url);
32-
33-
// Expect at least 2 chunks because subject creates two separate root spans,
34-
// causing the profiler to stop and emit a chunk after each root span ends.
35-
const profileChunkEnvelopes = await getMultipleSentryEnvelopeRequests<ProfileChunkEnvelope>(
36-
page,
37-
2,
38-
{ envelopeType: 'profile_chunk', timeout: 5000 },
39-
properFullEnvelopeRequestParser,
40-
);
41-
42-
expect(profileChunkEnvelopes.length).toBeGreaterThanOrEqual(2);
43-
44-
// Validate the first chunk thoroughly
45-
const profileChunkEnvelopeItem = profileChunkEnvelopes[0][1][0];
46-
const envelopeItemHeader = profileChunkEnvelopeItem[0];
47-
const envelopeItemPayload = profileChunkEnvelopeItem[1];
48-
49-
expect(envelopeItemHeader).toHaveProperty('type', 'profile_chunk');
50-
51-
expect(envelopeItemPayload.profile).toBeDefined();
52-
expect(envelopeItemPayload.version).toBe('2');
53-
expect(envelopeItemPayload.platform).toBe('javascript');
54-
55-
const profile = envelopeItemPayload.profile;
56-
57-
expect(profile.samples).toBeDefined();
58-
expect(profile.stacks).toBeDefined();
59-
expect(profile.frames).toBeDefined();
60-
expect(profile.thread_metadata).toBeDefined();
61-
62-
// Samples
63-
expect(profile.samples.length).toBeGreaterThanOrEqual(2);
64-
let previousTimestamp = Number.NEGATIVE_INFINITY;
65-
for (const sample of profile.samples) {
66-
expect(typeof sample.stack_id).toBe('number');
67-
expect(sample.stack_id).toBeGreaterThanOrEqual(0);
68-
expect(sample.stack_id).toBeLessThan(profile.stacks.length);
69-
70-
// In trace lifecycle mode, samples carry a numeric timestamp (ms since epoch or similar clock)
71-
expect(typeof (sample as any).timestamp).toBe('number');
72-
const ts = (sample as any).timestamp as number;
73-
expect(Number.isFinite(ts)).toBe(true);
74-
expect(ts).toBeGreaterThan(0);
75-
// Monotonic non-decreasing timestamps
76-
expect(ts).toBeGreaterThanOrEqual(previousTimestamp);
77-
previousTimestamp = ts;
78-
79-
expect(sample.thread_id).toBe('0'); // Should be main thread
80-
}
81-
82-
// Stacks
83-
expect(profile.stacks.length).toBeGreaterThan(0);
84-
for (const stack of profile.stacks) {
85-
expect(Array.isArray(stack)).toBe(true);
86-
for (const frameIndex of stack) {
87-
expect(typeof frameIndex).toBe('number');
88-
expect(frameIndex).toBeGreaterThanOrEqual(0);
89-
expect(frameIndex).toBeLessThan(profile.frames.length);
11+
sentryTest(
12+
'does not send profile envelope when document-policy is not set',
13+
async ({ page, getLocalTestUrl, browserName }) => {
14+
if (shouldSkipTracingTest() || browserName !== 'chromium') {
15+
// Profiling only works when tracing is enabled
16+
sentryTest.skip();
9017
}
91-
}
92-
93-
// Frames
94-
expect(profile.frames.length).toBeGreaterThan(0);
95-
for (const frame of profile.frames) {
96-
expect(frame).toHaveProperty('function');
97-
expect(frame).toHaveProperty('abs_path');
98-
expect(frame).toHaveProperty('lineno');
99-
expect(frame).toHaveProperty('colno');
100-
101-
expect(typeof frame.function).toBe('string');
102-
expect(typeof frame.abs_path).toBe('string');
103-
expect(typeof frame.lineno).toBe('number');
104-
expect(typeof frame.colno).toBe('number');
105-
}
106-
107-
const functionNames = profile.frames.map(frame => frame.function).filter(name => name !== '');
108-
109-
if ((process.env.PW_BUNDLE || '').endsWith('min')) {
110-
// In bundled mode, function names are minified
111-
expect(functionNames.length).toBeGreaterThan(0);
112-
expect((functionNames as string[]).every(name => name?.length > 0)).toBe(true); // Just make sure they're not empty strings
113-
} else {
114-
expect(functionNames).toEqual(
115-
expect.arrayContaining([
116-
'_startRootSpan',
117-
'withScope',
118-
'createChildOrRootSpan',
119-
'startSpanManual',
120-
'startJSSelfProfile',
121-
122-
// both functions are captured
123-
'fibonacci',
124-
'largeSum',
125-
]),
18+
19+
const url = await getLocalTestUrl({ testDir: __dirname });
20+
21+
// Assert that no profile_chunk envelope is sent without policy header
22+
const chunkCount = await countEnvelopes(page, { url, envelopeType: 'profile_chunk', timeout: 1500 });
23+
expect(chunkCount).toBe(0);
24+
},
25+
);
26+
27+
sentryTest(
28+
'sends profile_chunk envelopes in trace mode (multiple chunks)',
29+
async ({ page, getLocalTestUrl, browserName }) => {
30+
if (shouldSkipTracingTest() || browserName !== 'chromium') {
31+
// Profiling only works when tracing is enabled
32+
sentryTest.skip();
33+
}
34+
35+
const url = await getLocalTestUrl({ testDir: __dirname, responseHeaders: { 'Document-Policy': 'js-profiling' } });
36+
await page.goto(url);
37+
38+
// Expect at least 2 chunks because subject creates two separate root spans,
39+
// causing the profiler to stop and emit a chunk after each root span ends.
40+
const profileChunkEnvelopes = await getMultipleSentryEnvelopeRequests<ProfileChunkEnvelope>(
41+
page,
42+
2,
43+
{ envelopeType: 'profile_chunk', timeout: 5000 },
44+
properFullEnvelopeRequestParser,
12645
);
127-
}
128-
129-
expect(profile.thread_metadata).toHaveProperty('0');
130-
expect(profile.thread_metadata['0']).toHaveProperty('name');
131-
expect(profile.thread_metadata['0'].name).toBe('main');
132-
133-
// Test that profile duration makes sense (should be > 20ms based on test setup)
134-
const startTimeMs = (profile.samples[0] as any).timestamp as number;
135-
const endTimeMs = (profile.samples[profile.samples.length - 1] as any).timestamp as number;
136-
const durationMs = endTimeMs - startTimeMs;
137-
138-
// Should be at least 20ms based on our setTimeout(21) in the test
139-
expect(durationMs).toBeGreaterThan(20);
140-
141-
// Basic sanity on the second chunk: has correct envelope type and structure
142-
const secondChunkItem = profileChunkEnvelopes[1][1][0];
143-
const secondHeader = secondChunkItem[0];
144-
const secondPayload = secondChunkItem[1];
145-
expect(secondHeader).toHaveProperty('type', 'profile_chunk');
146-
expect(secondPayload.profile).toBeDefined();
147-
expect(secondPayload.version).toBe('2');
148-
expect(secondPayload.platform).toBe('javascript');
149-
});
46+
47+
expect(profileChunkEnvelopes.length).toBeGreaterThanOrEqual(2);
48+
49+
// Validate the first chunk thoroughly
50+
const profileChunkEnvelopeItem = profileChunkEnvelopes[0][1][0];
51+
const envelopeItemHeader = profileChunkEnvelopeItem[0];
52+
const envelopeItemPayload1 = profileChunkEnvelopeItem[1];
53+
54+
expect(envelopeItemHeader).toHaveProperty('type', 'profile_chunk');
55+
56+
expect(envelopeItemPayload1.profile).toBeDefined();
57+
expect(envelopeItemPayload1.version).toBe('2');
58+
expect(envelopeItemPayload1.platform).toBe('javascript');
59+
60+
const profile1 = envelopeItemPayload1.profile;
61+
62+
expect(profile1.samples).toBeDefined();
63+
expect(profile1.stacks).toBeDefined();
64+
expect(profile1.frames).toBeDefined();
65+
expect(profile1.thread_metadata).toBeDefined();
66+
67+
// Samples
68+
expect(profile1.samples.length).toBeGreaterThanOrEqual(2);
69+
let previousTimestamp = Number.NEGATIVE_INFINITY;
70+
for (const sample of profile1.samples) {
71+
expect(typeof sample.stack_id).toBe('number');
72+
expect(sample.stack_id).toBeGreaterThanOrEqual(0);
73+
expect(sample.stack_id).toBeLessThan(profile1.stacks.length);
74+
75+
// In trace lifecycle mode, samples carry a numeric timestamp (ms since epoch or similar clock)
76+
expect(typeof (sample as any).timestamp).toBe('number');
77+
const ts = (sample as any).timestamp as number;
78+
expect(Number.isFinite(ts)).toBe(true);
79+
expect(ts).toBeGreaterThan(0);
80+
// Monotonic non-decreasing timestamps
81+
expect(ts).toBeGreaterThanOrEqual(previousTimestamp);
82+
previousTimestamp = ts;
83+
84+
expect(sample.thread_id).toBe('0'); // Should be main thread
85+
}
86+
87+
// Stacks
88+
expect(profile1.stacks.length).toBeGreaterThan(0);
89+
for (const stack of profile1.stacks) {
90+
expect(Array.isArray(stack)).toBe(true);
91+
for (const frameIndex of stack) {
92+
expect(typeof frameIndex).toBe('number');
93+
expect(frameIndex).toBeGreaterThanOrEqual(0);
94+
expect(frameIndex).toBeLessThan(profile1.frames.length);
95+
}
96+
}
97+
98+
// Frames
99+
expect(profile1.frames.length).toBeGreaterThan(0);
100+
for (const frame of profile1.frames) {
101+
expect(frame).toHaveProperty('function');
102+
expect(frame).toHaveProperty('abs_path');
103+
expect(frame).toHaveProperty('lineno');
104+
expect(frame).toHaveProperty('colno');
105+
106+
expect(typeof frame.function).toBe('string');
107+
expect(typeof frame.abs_path).toBe('string');
108+
expect(typeof frame.lineno).toBe('number');
109+
expect(typeof frame.colno).toBe('number');
110+
}
111+
112+
const functionNames = profile1.frames.map(frame => frame.function).filter(name => name !== '');
113+
114+
if ((process.env.PW_BUNDLE || '').endsWith('min')) {
115+
// In bundled mode, function names are minified
116+
expect(functionNames.length).toBeGreaterThan(0);
117+
expect((functionNames as string[]).every(name => name?.length > 0)).toBe(true); // Just make sure they're not empty strings
118+
} else {
119+
expect(functionNames).toEqual(
120+
expect.arrayContaining([
121+
'_startRootSpan',
122+
'withScope',
123+
'createChildOrRootSpan',
124+
'startSpanManual',
125+
'startJSSelfProfile',
126+
127+
// first function is captured (other one is in other chunk)
128+
'fibonacci',
129+
]),
130+
);
131+
}
132+
133+
expect(profile1.thread_metadata).toHaveProperty('0');
134+
expect(profile1.thread_metadata['0']).toHaveProperty('name');
135+
expect(profile1.thread_metadata['0'].name).toBe('main');
136+
137+
// Test that profile duration makes sense (should be > 20ms based on test setup)
138+
const startTimeMs = (profile1.samples[0] as any).timestamp as number;
139+
const endTimeMs = (profile1.samples[profile1.samples.length - 1] as any).timestamp as number;
140+
const durationMs = endTimeMs - startTimeMs;
141+
142+
// Should be at least 20ms based on our setTimeout(21) in the test
143+
expect(durationMs).toBeGreaterThan(20);
144+
145+
// === PROFILE CHUNK 2 ===
146+
147+
const profileChunkEnvelopeItem2 = profileChunkEnvelopes[1][1][0];
148+
const envelopeItemHeader2 = profileChunkEnvelopeItem2[0];
149+
const envelopeItemPayload2 = profileChunkEnvelopeItem2[1];
150+
151+
// Basic sanity on the second chunk: has correct envelope type and structure
152+
expect(envelopeItemHeader2).toHaveProperty('type', 'profile_chunk');
153+
expect(envelopeItemPayload2.profile).toBeDefined();
154+
expect(envelopeItemPayload2.version).toBe('2');
155+
expect(envelopeItemPayload2.platform).toBe('javascript');
156+
expect(envelopeItemPayload2?.profile).toBeDefined();
157+
158+
const profile2 = envelopeItemPayload2.profile;
159+
160+
const functionNames2 = profile2.frames.map(frame => frame.function).filter(name => name !== '');
161+
162+
if ((process.env.PW_BUNDLE || '').endsWith('min')) {
163+
// In bundled mode, function names are minified
164+
expect(functionNames2.length).toBeGreaterThan(0);
165+
expect((functionNames2 as string[]).every(name => name?.length > 0)).toBe(true); // Just make sure they're not empty strings
166+
} else {
167+
expect(functionNames2).toEqual(
168+
expect.arrayContaining([
169+
'_startRootSpan',
170+
'withScope',
171+
'createChildOrRootSpan',
172+
'startSpanManual',
173+
'startJSSelfProfile',
174+
175+
// second function is captured (other one is in other chunk)
176+
'largeSum',
177+
]),
178+
);
179+
}
180+
},
181+
);

dev-packages/browser-integration-tests/suites/profiling/traceLifecycleMode_overlapping-spans/test.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,25 @@ import {
99
waitForTransactionRequestOnUrl,
1010
} from '../../../utils/helpers';
1111

12-
sentryTest('does not send profile envelope when document-policy is not set', async ({ page, getLocalTestUrl }) => {
13-
if (shouldSkipTracingTest()) {
14-
// Profiling only works when tracing is enabled
15-
sentryTest.skip();
16-
}
12+
sentryTest(
13+
'does not send profile envelope when document-policy is not set',
14+
async ({ page, getLocalTestUrl, browserName }) => {
15+
if (shouldSkipTracingTest() || browserName !== 'chromium') {
16+
// Profiling only works when tracing is enabled
17+
sentryTest.skip();
18+
}
1719

18-
const url = await getLocalTestUrl({ testDir: __dirname });
20+
const url = await getLocalTestUrl({ testDir: __dirname });
1921

20-
const req = await waitForTransactionRequestOnUrl(page, url);
21-
const transactionEvent = properEnvelopeRequestParser<Event>(req, 0);
22-
const profileEvent = properEnvelopeRequestParser<Profile>(req, 1);
22+
const req = await waitForTransactionRequestOnUrl(page, url);
23+
const transactionEvent = properEnvelopeRequestParser<Event>(req, 0);
24+
const profileEvent = properEnvelopeRequestParser<Profile>(req, 1);
2325

24-
expect(transactionEvent).toBeDefined();
26+
expect(transactionEvent).toBeDefined();
2527

26-
expect(profileEvent).toBeUndefined();
27-
});
28+
expect(profileEvent).toBeUndefined();
29+
},
30+
);
2831

2932
sentryTest(
3033
'sends profile envelope in trace mode (single chunk for overlapping spans)',

0 commit comments

Comments
 (0)