diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/init.js b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/init.js new file mode 100644 index 000000000000..de6b87574482 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [Sentry.browserTracingIntegration({ instrumentPageLoad: false, instrumentNavigation: false })], + tracePropagationTargets: ['http://sentry-test-site.example'], + tracesSampleRate: 1, + autoSessionTracking: false, +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/subject.js b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/subject.js new file mode 100644 index 000000000000..37441bf4463a --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/subject.js @@ -0,0 +1,19 @@ +function withRootSpan(cb) { + return Sentry.startSpan({ name: 'rootSpan' }, cb); +} + +document.getElementById('btnQuery').addEventListener('click', async () => { + await withRootSpan(() => fetch('http://sentry-test-site.example/0?id=123;page=5')); +}); + +document.getElementById('btnFragment').addEventListener('click', async () => { + await withRootSpan(() => fetch('http://sentry-test-site.example/1#fragment')); +}); + +document.getElementById('btnQueryFragment').addEventListener('click', async () => { + await withRootSpan(() => fetch('http://sentry-test-site.example/2?id=1#fragment')); +}); + +document.getElementById('btnQueryFragmentSameOrigin').addEventListener('click', async () => { + await withRootSpan(() => fetch('/api/users?id=1#fragment')); +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/template.html b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/template.html new file mode 100644 index 000000000000..d02fa0868f56 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/template.html @@ -0,0 +1,12 @@ + + +
+ + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/test.ts b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/test.ts new file mode 100644 index 000000000000..a0fea6e6af29 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/fetch-strip-query-and-fragment/test.ts @@ -0,0 +1,176 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../../utils/fixtures'; +import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers'; + +sentryTest('strips query params in fetch request spans', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnQuery').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET http://sentry-test-site.example/0', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test-site.example/0?id=123;page=5', + 'http.query': '?id=123;page=5', + 'http.response.status_code': 200, + 'http.response_content_length': 2, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'fetch', + 'server.address': 'sentry-test-site.example', + url: 'http://sentry-test-site.example/0?id=123;page=5', + }), + }); + + expect(requestSpan?.data).not.toHaveProperty('http.fragment'); +}); + +sentryTest('strips hash fragment in fetch request spans', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnFragment').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET http://sentry-test-site.example/1', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test-site.example/1#fragment', + 'http.fragment': '#fragment', + 'http.response.status_code': 200, + 'http.response_content_length': 2, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'fetch', + 'server.address': 'sentry-test-site.example', + url: 'http://sentry-test-site.example/1#fragment', + }), + }); + + expect(requestSpan?.data).not.toHaveProperty('http.query'); +}); + +sentryTest('strips hash fragment and query params in fetch request spans', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnQueryFragment').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET http://sentry-test-site.example/2', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test-site.example/2?id=1#fragment', + 'http.query': '?id=1', + 'http.fragment': '#fragment', + 'http.response.status_code': 200, + 'http.response_content_length': 2, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'fetch', + 'server.address': 'sentry-test-site.example', + url: 'http://sentry-test-site.example/2?id=1#fragment', + }), + }); +}); + +sentryTest( + 'strips hash fragment and query params in same-origin fetch request spans', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('**/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnQueryFragmentSameOrigin').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET /api/users', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test.io/api/users?id=1#fragment', + 'http.query': '?id=1', + 'http.fragment': '#fragment', + 'http.response.status_code': 200, + 'http.response_content_length': 2, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'fetch', + 'server.address': 'sentry-test.io', + url: '/api/users?id=1#fragment', + }), + }); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/init.js b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/init.js new file mode 100644 index 000000000000..de6b87574482 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [Sentry.browserTracingIntegration({ instrumentPageLoad: false, instrumentNavigation: false })], + tracePropagationTargets: ['http://sentry-test-site.example'], + tracesSampleRate: 1, + autoSessionTracking: false, +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/subject.js b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/subject.js new file mode 100644 index 000000000000..e27c6d3cf013 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/subject.js @@ -0,0 +1,29 @@ +function withRootSpan(cb) { + return Sentry.startSpan({ name: 'rootSpan' }, cb); +} + +function makeXHRRequest(url) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.onload = () => resolve(xhr.responseText); + xhr.onerror = () => reject(xhr.statusText); + xhr.send(); + }); +} + +document.getElementById('btnQuery').addEventListener('click', async () => { + await withRootSpan(() => makeXHRRequest('http://sentry-test-site.example/0?id=123;page=5')); +}); + +document.getElementById('btnFragment').addEventListener('click', async () => { + await withRootSpan(() => makeXHRRequest('http://sentry-test-site.example/1#fragment')); +}); + +document.getElementById('btnQueryFragment').addEventListener('click', async () => { + await withRootSpan(() => makeXHRRequest('http://sentry-test-site.example/2?id=1#fragment')); +}); + +document.getElementById('btnQueryFragmentSameOrigin').addEventListener('click', async () => { + await withRootSpan(() => makeXHRRequest('/api/users?id=1#fragment')); +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/template.html b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/template.html new file mode 100644 index 000000000000..533636f821c3 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/template.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/test.ts b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/test.ts new file mode 100644 index 000000000000..d4ed06fcdd4e --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/request/xhr-strip-query-and-fragment/test.ts @@ -0,0 +1,172 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../../utils/fixtures'; +import { envelopeRequestParser, shouldSkipTracingTest, waitForTransactionRequest } from '../../../../utils/helpers'; + +sentryTest('strips query params in XHR request spans', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnQuery').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET http://sentry-test-site.example/0', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test-site.example/0?id=123;page=5', + 'http.query': '?id=123;page=5', + 'http.response.status_code': 200, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'xhr', + 'server.address': 'sentry-test-site.example', + url: 'http://sentry-test-site.example/0?id=123;page=5', + }), + }); + + expect(requestSpan?.data).not.toHaveProperty('http.fragment'); +}); + +sentryTest('strips hash fragment in XHR request spans', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnFragment').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET http://sentry-test-site.example/1', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test-site.example/1#fragment', + 'http.fragment': '#fragment', + 'http.response.status_code': 200, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'xhr', + 'server.address': 'sentry-test-site.example', + url: 'http://sentry-test-site.example/1#fragment', + }), + }); + + expect(requestSpan?.data).not.toHaveProperty('http.query'); +}); + +sentryTest('strips hash fragment and query params in XHR request spans', async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('http://sentry-test-site.example/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnQueryFragment').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET http://sentry-test-site.example/2', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test-site.example/2?id=1#fragment', + 'http.query': '?id=1', + 'http.fragment': '#fragment', + 'http.response.status_code': 200, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'xhr', + 'server.address': 'sentry-test-site.example', + url: 'http://sentry-test-site.example/2?id=1#fragment', + }), + }); +}); + +sentryTest( + 'strips hash fragment and query params in same-origin XHR request spans', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + await page.route('**/*', route => route.fulfill({ body: 'ok' })); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const txnPromise = waitForTransactionRequest(page); + await page.locator('#btnQueryFragmentSameOrigin').click(); + const transactionEvent = envelopeRequestParser(await txnPromise); + + expect(transactionEvent.transaction).toEqual('rootSpan'); + + const requestSpan = transactionEvent.spans?.find(({ op }) => op === 'http.client'); + + expect(requestSpan).toMatchObject({ + description: 'GET /api/users', + parent_span_id: transactionEvent.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + start_timestamp: expect.any(Number), + timestamp: expect.any(Number), + trace_id: transactionEvent.contexts?.trace?.trace_id, + data: expect.objectContaining({ + 'http.method': 'GET', + 'http.url': 'http://sentry-test.io/api/users?id=1#fragment', + 'http.query': '?id=1', + 'http.fragment': '#fragment', + 'http.response.status_code': 200, + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.browser', + type: 'xhr', + 'server.address': 'sentry-test.io', + url: '/api/users?id=1#fragment', + }), + }); + }, +); diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index e123e852f4b9..9d89dea67940 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -20,6 +20,7 @@ "fix": "eslint . --format stylish --fix", "type-check": "tsc", "test": "jest --config ./jest.config.js", + "test:no-prisma": "jest --config ./jest.config.js", "test:watch": "yarn test --watch" }, "dependencies": { diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-basic/scenario.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-basic/scenario.ts new file mode 100644 index 000000000000..44ea548bab8f --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-basic/scenario.ts @@ -0,0 +1,15 @@ +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import * as Sentry from '@sentry/node'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +Sentry.startSpan({ name: 'test_transaction' }, async () => { + await fetch(`${process.env.SERVER_URL}/api/v0`); + await fetch(`${process.env.SERVER_URL}/api/v1`); +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-basic/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-basic/test.ts new file mode 100644 index 000000000000..006190864fe6 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-basic/test.ts @@ -0,0 +1,48 @@ +import { createRunner } from '../../../../utils/runner'; +import { createTestServer } from '../../../../utils/server'; + +test('captures spans for outgoing fetch requests', done => { + expect.assertions(3); + + createTestServer(done) + .get('/api/v0', () => { + // Just ensure we're called + expect(true).toBe(true); + }) + .get( + '/api/v1', + () => { + // Just ensure we're called + expect(true).toBe(true); + }, + 404, + ) + .start() + .then(([SERVER_URL, closeTestServer]) => { + createRunner(__dirname, 'scenario.ts') + .withEnv({ SERVER_URL }) + .expect({ + transaction: { + transaction: 'test_transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + description: expect.stringMatching(/GET .*\/api\/v0/), + op: 'http.client', + origin: 'auto.http.otel.node_fetch', + status: 'ok', + }), + expect.objectContaining({ + description: expect.stringMatching(/GET .*\/api\/v1/), + op: 'http.client', + origin: 'auto.http.otel.node_fetch', + status: 'not_found', + data: expect.objectContaining({ + 'http.response.status_code': 404, + }), + }), + ]), + }, + }) + .start(closeTestServer); + }); +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/scenario.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/scenario.ts new file mode 100644 index 000000000000..0c72d545c39b --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/scenario.ts @@ -0,0 +1,14 @@ +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import * as Sentry from '@sentry/node'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +Sentry.startSpan({ name: 'test_transaction' }, async () => { + await fetch(`${process.env.SERVER_URL}/api/v0/users?id=1#fragment`); +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/test.ts new file mode 100644 index 000000000000..12bb11727228 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/fetch-strip-query/test.ts @@ -0,0 +1,53 @@ +import { createRunner } from '../../../../utils/runner'; +import { createTestServer } from '../../../../utils/server'; + +test('strips and handles query params in spans of outgoing fetch requests', done => { + expect.assertions(4); + + createTestServer(done) + .get('/api/v0/users', () => { + // Just ensure we're called + expect(true).toBe(true); + }) + .start() + .then(([SERVER_URL, closeTestServer]) => { + createRunner(__dirname, 'scenario.ts') + .withEnv({ SERVER_URL }) + .expect({ + transaction: txn => { + expect(txn.transaction).toEqual('test_transaction'); + expect(txn.spans).toHaveLength(1); + expect(txn.spans?.[0]).toMatchObject({ + data: { + url: `${SERVER_URL}/api/v0/users`, + 'url.full': `${SERVER_URL}/api/v0/users?id=1`, + 'url.path': '/api/v0/users', + 'url.query': '?id=1', + 'url.scheme': 'http', + 'http.query': 'id=1', + 'http.request.method': 'GET', + 'http.request.method_original': 'GET', + 'http.response.header.content-length': 0, + 'http.response.status_code': 200, + 'network.peer.address': '::1', + 'network.peer.port': expect.any(Number), + 'otel.kind': 'CLIENT', + 'server.port': expect.any(Number), + 'user_agent.original': 'node', + 'sentry.op': 'http.client', + 'sentry.origin': 'auto.http.otel.node_fetch', + 'server.address': 'localhost', + }, + description: `GET ${SERVER_URL}/api/v0/users`, + op: 'http.client', + origin: 'auto.http.otel.node_fetch', + status: 'ok', + parent_span_id: txn.contexts?.trace?.span_id, + span_id: expect.stringMatching(/[a-f0-9]{16}/), + trace_id: txn.contexts?.trace?.trace_id, + }); + }, + }) + .start(closeTestServer); + }); +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/spans/scenario.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/scenario.ts similarity index 100% rename from dev-packages/node-integration-tests/suites/tracing/spans/scenario.ts rename to dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/scenario.ts diff --git a/dev-packages/node-integration-tests/suites/tracing/spans/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts similarity index 87% rename from dev-packages/node-integration-tests/suites/tracing/spans/test.ts rename to dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts index e349622d39f8..bb642baf0e1c 100644 --- a/dev-packages/node-integration-tests/suites/tracing/spans/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts @@ -1,7 +1,7 @@ -import { createRunner } from '../../../utils/runner'; -import { createTestServer } from '../../../utils/server'; +import { createRunner } from '../../../../utils/runner'; +import { createTestServer } from '../../../../utils/server'; -test('should capture spans for outgoing http requests', done => { +test('captures spans for outgoing http requests', done => { expect.assertions(3); createTestServer(done) diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/scenario.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/scenario.ts new file mode 100644 index 000000000000..074c9778aa75 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/scenario.ts @@ -0,0 +1,31 @@ +import { loggingTransport } from '@sentry-internal/node-integration-tests'; +import * as Sentry from '@sentry/node'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); + +import * as http from 'http'; + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +Sentry.startSpan({ name: 'test_transaction' }, async () => { + await makeHttpRequest(`${process.env.SERVER_URL}/api/v0/users?id=1#fragment`); +}); + +function makeHttpRequest(url: string): Promise