Skip to content

Commit

Permalink
refactor unit tests, strengthen integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
Lms24 committed Jan 27, 2025
1 parent 41eeee6 commit 590a5ed
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Route } from '@playwright/test';
import { expect } from '@playwright/test';
import type { Event } from '@sentry/core';
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, type Event } from '@sentry/core';

import { sentryTest } from '../../../../utils/fixtures';
import { getFirstSentryEnvelopeRequest, shouldSkipTracingTest } from '../../../../utils/helpers';
Expand All @@ -12,13 +12,31 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca

// Intercepting asset requests to avoid network-related flakiness and random retries (on Firefox).
await page.route('https://example.com/path/to/image.svg', (route: Route) =>
route.fulfill({ path: `${__dirname}/assets/image.svg` }),
route.fulfill({
path: `${__dirname}/assets/image.svg`,
headers: {
'Timing-Allow-Origin': '*',
'Content-Type': 'image/svg+xml',
},
}),
);
await page.route('https://example.com/path/to/script.js', (route: Route) =>
route.fulfill({ path: `${__dirname}/assets/script.js` }),
route.fulfill({
path: `${__dirname}/assets/script.js`,
headers: {
'Timing-Allow-Origin': '*',
'Content-Type': 'application/javascript',
},
}),
);
await page.route('https://example.com/path/to/style.css', (route: Route) =>
route.fulfill({ path: `${__dirname}/assets/style.css` }),
route.fulfill({
path: `${__dirname}/assets/style.css`,
headers: {
'Timing-Allow-Origin': '*',
'Content-Type': 'text/css',
},
}),
);

const url = await getLocalTestUrl({ testDir: __dirname });
Expand All @@ -27,11 +45,14 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca
const resourceSpans = eventData.spans?.filter(({ op }) => op?.startsWith('resource'));

const scriptSpans = resourceSpans?.filter(({ op }) => op === 'resource.script');
const linkSpans = resourceSpans?.filter(({ op }) => op === 'resource.link');
const imgSpans = resourceSpans?.filter(({ op }) => op === 'resource.img');
const linkSpan = resourceSpans?.filter(({ op }) => op === 'resource.link')[0];
const imgSpan = resourceSpans?.filter(({ op }) => op === 'resource.img')[0];

expect(imgSpans).toHaveLength(1);
expect(linkSpans).toHaveLength(1);
const spanId = eventData.contexts?.trace?.span_id;
const traceId = eventData.contexts?.trace?.trace_id;

expect(spanId).toBeDefined();
expect(traceId).toBeDefined();

const hasCdnBundle = (process.env.PW_BUNDLE || '').startsWith('bundle');

Expand All @@ -41,11 +62,84 @@ sentryTest('should add resource spans to pageload transaction', async ({ getLoca
}

expect(scriptSpans?.map(({ description }) => description).sort()).toEqual(expectedScripts);
expect(scriptSpans?.map(({ parent_span_id }) => parent_span_id)).toEqual(expectedScripts.map(() => spanId));

const spanId = eventData.contexts?.trace?.span_id;
const customScriptSpan = scriptSpans?.find(
({ description }) => description === 'https://example.com/path/to/script.js',
);

expect(spanId).toBeDefined();
expect(imgSpans?.[0].parent_span_id).toBe(spanId);
expect(linkSpans?.[0].parent_span_id).toBe(spanId);
expect(scriptSpans?.map(({ parent_span_id }) => parent_span_id)).toEqual(expectedScripts.map(() => spanId));
expect(imgSpan).toEqual({
data: {
'http.decoded_response_content_length': expect.any(Number),
'http.response_content_length': expect.any(Number),
'http.response_delivery_type': '',
'http.response_transfer_size': expect.any(Number),
'network.protocol.name': 'unknown',
'network.protocol.version': 'unknown',
'resource.render_blocking_status': 'non-blocking',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.img',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',
'server.address': 'example.com',
'url.same_origin': false,
'url.scheme': 'https',
},
description: 'https://example.com/path/to/image.svg',
op: 'resource.img',
origin: 'auto.resource.browser.metrics',
parent_span_id: spanId,
span_id: expect.stringMatching(/^[a-f0-9]{16}$/),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
trace_id: traceId,
});

expect(linkSpan).toEqual({
data: {
'http.decoded_response_content_length': expect.any(Number),
'http.response_content_length': expect.any(Number),
'http.response_delivery_type': '',
'http.response_transfer_size': expect.any(Number),
'network.protocol.name': 'unknown',
'network.protocol.version': 'unknown',
'resource.render_blocking_status': 'non-blocking',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'resource.link',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.resource.browser.metrics',
'server.address': 'example.com',
'url.same_origin': false,
'url.scheme': 'https',
},
description: 'https://example.com/path/to/style.css',
op: 'resource.link',
origin: 'auto.resource.browser.metrics',
parent_span_id: spanId,
span_id: expect.stringMatching(/^[a-f0-9]{16}$/),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
trace_id: traceId,
});

expect(customScriptSpan).toEqual({
data: {
'http.decoded_response_content_length': expect.any(Number),
'http.response_content_length': expect.any(Number),
'http.response_delivery_type': '',
'http.response_transfer_size': expect.any(Number),
'network.protocol.name': 'unknown',
'network.protocol.version': 'unknown',
'resource.render_blocking_status': 'non-blocking',
'sentry.op': 'resource.script',
'sentry.origin': 'auto.resource.browser.metrics',
'server.address': 'example.com',
'url.same_origin': false,
'url.scheme': 'https',
},
description: 'https://example.com/path/to/script.js',
op: 'resource.script',
origin: 'auto.resource.browser.metrics',
parent_span_id: spanId,
span_id: expect.stringMatching(/^[a-f0-9]{16}$/),
start_timestamp: expect.any(Number),
timestamp: expect.any(Number),
trace_id: traceId,
});
});
5 changes: 5 additions & 0 deletions packages/browser-utils/src/metrics/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ export function msToSec(time: number): number {
export function extractNetworkProtocol(nextHopProtocol: string): { name: string; version: string } {
let name = 'unknown';
let version = 'unknown';

if (!nextHopProtocol) {
return { name, version };
}

let _name = '';
for (const char of nextHopProtocol) {
// http/1.1 etc.
Expand Down
84 changes: 37 additions & 47 deletions packages/browser-utils/test/browser/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,53 +55,43 @@ describe('startAndEndSpan()', () => {
});
});

interface ProtocolInfo {
name: string;
version: string;
}

describe('HTTPTimings', () => {
test('Extracting version from ALPN protocol', () => {
const nextHopToNetworkVersion: Record<string, ProtocolInfo> = {
'http/0.9': { name: 'http', version: '0.9' },
'http/1.0': { name: 'http', version: '1.0' },
'http/1.1': { name: 'http', version: '1.1' },
'spdy/1': { name: 'spdy', version: '1' },
'spdy/2': { name: 'spdy', version: '2' },
'spdy/3': { name: 'spdy', version: '3' },
'stun.turn': { name: 'stun.turn', version: 'unknown' },
'stun.nat-discovery': { name: 'stun.nat-discovery', version: 'unknown' },
h2: { name: 'http', version: '2' },
h2c: { name: 'http', version: '2c' },
webrtc: { name: 'webrtc', version: 'unknown' },
'c-webrtc': { name: 'c-webrtc', version: 'unknown' },
ftp: { name: 'ftp', version: 'unknown' },
imap: { name: 'imap', version: 'unknown' },
pop3: { name: 'pop', version: '3' },
managesieve: { name: 'managesieve', version: 'unknown' },
coap: { name: 'coap', version: 'unknown' },
'xmpp-client': { name: 'xmpp-client', version: 'unknown' },
'xmpp-server': { name: 'xmpp-server', version: 'unknown' },
'acme-tls/1': { name: 'acme-tls', version: '1' },
mqtt: { name: 'mqtt', version: 'unknown' },
dot: { name: 'dot', version: 'unknown' },
'ntske/1': { name: 'ntske', version: '1' },
sunrpc: { name: 'sunrpc', version: 'unknown' },
h3: { name: 'http', version: '3' },
smb: { name: 'smb', version: 'unknown' },
irc: { name: 'irc', version: 'unknown' },
nntp: { name: 'nntp', version: 'unknown' },
nnsp: { name: 'nnsp', version: 'unknown' },
doq: { name: 'doq', version: 'unknown' },
'sip/2': { name: 'sip', version: '2' },
'tds/8.0': { name: 'tds', version: '8.0' },
dicom: { name: 'dicom', version: 'unknown' },
};

const protocols = Object.keys(nextHopToNetworkVersion);
for (const protocol of protocols) {
const expected = nextHopToNetworkVersion[protocol]!;
expect(extractNetworkProtocol(protocol)).toMatchObject(expected);
}
test.each([
['http/0.9', { name: 'http', version: '0.9' }],
['http/1.0', { name: 'http', version: '1.0' }],
['http/1.1', { name: 'http', version: '1.1' }],
['spdy/1', { name: 'spdy', version: '1' }],
['spdy/2', { name: 'spdy', version: '2' }],
['spdy/3', { name: 'spdy', version: '3' }],
['stun.turn', { name: 'stun.turn', version: 'unknown' }],
['stun.nat-discovery', { name: 'stun.nat-discovery', version: 'unknown' }],
['h2', { name: 'http', version: '2' }],
['h2c', { name: 'http', version: '2c' }],
['webrtc', { name: 'webrtc', version: 'unknown' }],
['c-webrtc', { name: 'c-webrtc', version: 'unknown' }],
['ftp', { name: 'ftp', version: 'unknown' }],
['imap', { name: 'imap', version: 'unknown' }],
['pop3', { name: 'pop', version: '3' }],
['managesieve', { name: 'managesieve', version: 'unknown' }],
['coap', { name: 'coap', version: 'unknown' }],
['xmpp-client', { name: 'xmpp-client', version: 'unknown' }],
['xmpp-server', { name: 'xmpp-server', version: 'unknown' }],
['acme-tls/1', { name: 'acme-tls', version: '1' }],
['mqtt', { name: 'mqtt', version: 'unknown' }],
['dot', { name: 'dot', version: 'unknown' }],
['ntske/1', { name: 'ntske', version: '1' }],
['sunrpc', { name: 'sunrpc', version: 'unknown' }],
['h3', { name: 'http', version: '3' }],
['smb', { name: 'smb', version: 'unknown' }],
['irc', { name: 'irc', version: 'unknown' }],
['nntp', { name: 'nntp', version: 'unknown' }],
['nnsp', { name: 'nnsp', version: 'unknown' }],
['doq', { name: 'doq', version: 'unknown' }],
['sip/2', { name: 'sip', version: '2' }],
['tds/8.0', { name: 'tds', version: '8.0' }],
['dicom', { name: 'dicom', version: 'unknown' }],
['', { name: 'unknown', version: 'unknown' }],
])('Extracting version from ALPN protocol %s', (protocol, expected) => {
expect(extractNetworkProtocol(protocol)).toMatchObject(expected);
});
});

0 comments on commit 590a5ed

Please sign in to comment.