diff --git a/dev-packages/bun-integration-tests/node-suites/excludes.ts b/dev-packages/bun-integration-tests/node-suites/excludes.ts index 86aa8f9a65e1..94f084f717d8 100644 --- a/dev-packages/bun-integration-tests/node-suites/excludes.ts +++ b/dev-packages/bun-integration-tests/node-suites/excludes.ts @@ -1,6 +1,7 @@ // Node suites that do not run on Bun, relative to `node-integration-tests`. A single test that // fails on Bun runs only on the other runtimes, with `test.runIf(supports({ runtimes }))` in the -// Node suite, and is not listed here. +// Node suite, and a suite or test that fails only on older Bun versions runs with +// `supports({ bunMin })`. Neither is listed here. // Node-only features: ANR and native thread watchdogs, child processes, the AWS Lambda Node runtime, // `node:sqlite`, which `flue` needs, and the Vercel keep-alive, which needs `http.server.response.finish`. @@ -57,23 +58,6 @@ const NO_FETCH_INSTRUMENTATION = [ 'suites/tracing/requests/traceparent/test.ts', ]; -// Bun 1.3.14 (the CI version) does not instrument outgoing `node:http` requests. These suites pass -// on Bun 1.4.2. See https://github.com/getsentry/sentry-javascript/issues/23881 -const NO_OUTGOING_HTTP_INSTRUMENTATION = [ - 'suites/tracing/dsc-txn-name-update/test.ts', - 'suites/tracing/http-client-spans/http-basic/test.ts', - 'suites/tracing/http-client-spans/http-strip-query/test.ts', - 'suites/tracing/requests/http-breadcrumbs/test.ts', - 'suites/tracing/requests/http-maxed-out-sockets/test.ts', - 'suites/tracing/requests/http-no-trace-propagation/test.ts', - 'suites/tracing/requests/http-no-tracing-no-spans/test.ts', - 'suites/tracing/requests/http-no-tracing/test.ts', - 'suites/tracing/requests/http-sampled-no-active-span/test.ts', - 'suites/tracing/requests/http-sampled/test.ts', - 'suites/tracing/requests/http-unsampled/test.ts', - 'suites/tracing/tracePropagationTargets/**', -]; - // `bun run` cannot inject the diagnostics channels into libraries, so framework, database and AI // instrumentation creates no spans. Apps must be built with `@sentry/bun/plugin`. // See https://github.com/getsentry/sentry-javascript/issues/23882 @@ -142,17 +126,16 @@ export const NO_AUTO_INSTRUMENTATION = [ 'suites/tracing/vercelai/**', ]; -// Fail on Bun, cause not investigated yet. `system-error` and `tracer-start-active-span-error` -// fail on Bun 1.3.14 and pass on Bun 1.4.2. With the `@sentry/bun` alias, `system-error` also -// fails because `@sentry/bun` does not include `nodeSystemErrorIntegration`. +// Fail on Bun. The cause is not investigated yet. const NOT_TRIAGED = [ 'suites/contextLines/filename-with-spaces/test.ts', 'suites/modules/test.ts', 'suites/proxy/test.ts', - 'suites/system-error/test.ts', - 'suites/tracing/tracer-start-active-span-error/test.ts', ]; +// The suite expects the events of `nodeSystemErrorIntegration`, which `@sentry/bun` does not include. +const NO_SYSTEM_ERROR_INTEGRATION = ['suites/system-error/test.ts']; + // The scenario configures `nativeNodeFetchIntegration`, which `@sentry/bun` does not export. const NO_NATIVE_NODE_FETCH_INTEGRATION = [ 'suites/tracing/http-client-spans/fetch-forward-request-hook/test.ts', @@ -202,13 +185,7 @@ const NO_EXPRESS_INSTRUMENTATION = [ 'suites/tracing/traceid-recycling-with-spans/test.ts', ]; -export const NODE_SUITES_EXCLUDE = [ - '**/node_modules/**', - ...NODE_ONLY, - ...NO_OUTGOING_HTTP_INSTRUMENTATION, - ...NO_AUTO_INSTRUMENTATION, - ...NOT_TRIAGED, -]; +export const NODE_SUITES_EXCLUDE = ['**/node_modules/**', ...NODE_ONLY, ...NO_AUTO_INSTRUMENTATION, ...NOT_TRIAGED]; // Excluded only in the `node-suites` project, which runs the suites with `@sentry/node`. export const SENTRY_NODE_EXCLUDE = [...NO_HTTP_SERVER_SPANS, ...NO_FETCH_INSTRUMENTATION]; @@ -217,6 +194,7 @@ export const SENTRY_NODE_EXCLUDE = [...NO_HTTP_SERVER_SPANS, ...NO_FETCH_INSTRUM export const SENTRY_BUN_EXCLUDE = [ ...HTTP_SERVER_OPTIONS_IGNORED, ...NO_EXPRESS_INSTRUMENTATION, + ...NO_SYSTEM_ERROR_INTEGRATION, ...NO_NATIVE_NODE_FETCH_INTEGRATION, ...FETCH_INTEGRATION_DIFFERS, ]; @@ -233,7 +211,7 @@ const BUN_BUILD_EAGER_SUBSCRIPTION = ['suites/tracing/orchestrion-lazy-registrat // `http.server.request.start`. const BUN_BUILD_NO_HTTP_SERVER_INTEGRATION = ['suites/express/multiple-init/test.ts']; -// Some or all tests fail with the bundled scenarios, cause not investigated yet. In +// Some or all tests fail with the bundled scenarios. The cause is not investigated yet. In // `express/tracing` only the request data tests fail: they set `httpIntegration` options, and with // `@sentry/bun` the request body comes from `bunHttpServerIntegration`. const BUN_BUILD_NOT_TRIAGED = [ diff --git a/dev-packages/deno-integration-tests/node-suites/excludes.ts b/dev-packages/deno-integration-tests/node-suites/excludes.ts index b2a6b1b851a8..a6ad2a290f16 100644 --- a/dev-packages/deno-integration-tests/node-suites/excludes.ts +++ b/dev-packages/deno-integration-tests/node-suites/excludes.ts @@ -45,7 +45,7 @@ const REQUIRE_OF_ESM_ONLY_DEPENDENCY = [ 'suites/tracing/prisma-orm-v8/test.ts', ]; -// Some or all tests fail on Deno, cause not investigated yet. In most AI suites the span +// Some or all tests fail on Deno. The cause is not investigated yet. In most AI suites the span // streaming test fails. `apollo-graphql` (CJS tests only) and `mongodb` fail on Deno 2.8.3 (the CI // version) and pass on Deno 2.9.0. const NOT_TRIAGED = [ diff --git a/dev-packages/node-integration-tests/README.md b/dev-packages/node-integration-tests/README.md index 67272bf5f6b0..bfdbc2a63957 100644 --- a/dev-packages/node-integration-tests/README.md +++ b/dev-packages/node-integration-tests/README.md @@ -68,7 +68,8 @@ arriving after its condition is satisfied. `dev-packages/bun-integration-tests` and `dev-packages/deno-integration-tests` run every suite of this package on Bun and Deno as well. When you add a suite, check that it passes on both. If it cannot, add it to `node-suites/excludes.ts` of the runtime's package with the reason, or run the single tests that fail only on the -other runtimes, for example `test.runIf(supports({ runtimes: ['node', 'deno'] }))` for a test that fails on Bun. +other runtimes, for example `test.runIf(supports({ runtimes: ['node', 'deno'] }))` for a test that fails on Bun. A +suite or test that fails only on Bun versions older than a given one runs with `supports({ bunMin: '1.4.0' })`. ## Running Tests Locally diff --git a/dev-packages/node-integration-tests/suites/system-error/test.ts b/dev-packages/node-integration-tests/suites/system-error/test.ts index e04fef7afec9..2b5f8f1ccf96 100644 --- a/dev-packages/node-integration-tests/suites/system-error/test.ts +++ b/dev-packages/node-integration-tests/suites/system-error/test.ts @@ -1,11 +1,13 @@ import { afterAll, describe, test } from 'vitest'; import { cleanupChildProcesses, createRunner } from '../../utils/runner'; +import { supports } from '../../utils'; afterAll(() => { cleanupChildProcesses(); }); -describe('SystemError integration', () => { +// Fails on Bun before 1.4. The cause is not investigated yet. +describe.runIf(supports({ bunMin: '1.4.0' }))('SystemError integration', () => { test('userInfo: false', async () => { await createRunner(__dirname, 'basic.mjs') .expect({ diff --git a/dev-packages/node-integration-tests/suites/tracing/dsc-txn-name-update/test.ts b/dev-packages/node-integration-tests/suites/tracing/dsc-txn-name-update/test.ts index 821662369b80..01dc6a8effd6 100644 --- a/dev-packages/node-integration-tests/suites/tracing/dsc-txn-name-update/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/dsc-txn-name-update/test.ts @@ -1,64 +1,70 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { expect, test } from 'vitest'; import { createRunner } from '../../../utils/runner'; +import { supports } from '../../../utils'; -test('adds current transaction name to baggage when the txn name is high-quality', async () => { - expect.assertions(5); +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +test.runIf(supports({ bunMin: '1.4.0' }))( + 'adds current transaction name to baggage when the txn name is high-quality', + async () => { + expect.assertions(5); - let traceId: string | undefined; + let traceId: string | undefined; - const [SERVER_URL, closeTestServer] = await createTestServer() - .get('/api/v0', headers => { - const baggageItems = getBaggageHeaderItems(headers); - traceId = baggageItems.find(item => item.startsWith('sentry-trace_id='))?.split('=')[1] as string; + const [SERVER_URL, closeTestServer] = await createTestServer() + .get('/api/v0', headers => { + const baggageItems = getBaggageHeaderItems(headers); + traceId = baggageItems.find(item => item.startsWith('sentry-trace_id='))?.split('=')[1] as string; - expect(traceId).toMatch(/^[\da-f]{32}$/); + expect(traceId).toMatch(/^[\da-f]{32}$/); - expect(baggageItems).toEqual([ - 'sentry-environment=production', - 'sentry-public_key=public', - 'sentry-release=1.0', - expect.stringMatching(/sentry-sample_rand=0\.\d+/), - 'sentry-sample_rate=1', - 'sentry-sampled=true', - `sentry-trace_id=${traceId}`, - ]); - }) - .get('/api/v1', headers => { - expect(getBaggageHeaderItems(headers)).toEqual([ - 'sentry-environment=production', - 'sentry-public_key=public', - 'sentry-release=1.0', - expect.stringMatching(/sentry-sample_rand=0\.\d+/), - 'sentry-sample_rate=1', - 'sentry-sampled=true', - `sentry-trace_id=${traceId}`, - 'sentry-transaction=updated-name-1', - ]); - }) - .get('/api/v2', headers => { - expect(getBaggageHeaderItems(headers)).toEqual([ - 'sentry-environment=production', - 'sentry-public_key=public', - 'sentry-release=1.0', - expect.stringMatching(/sentry-sample_rand=0\.\d+/), - 'sentry-sample_rate=1', - 'sentry-sampled=true', - `sentry-trace_id=${traceId}`, - 'sentry-transaction=updated-name-2', - ]); - }) - .start(); + expect(baggageItems).toEqual([ + 'sentry-environment=production', + 'sentry-public_key=public', + 'sentry-release=1.0', + expect.stringMatching(/sentry-sample_rand=0\.\d+/), + 'sentry-sample_rate=1', + 'sentry-sampled=true', + `sentry-trace_id=${traceId}`, + ]); + }) + .get('/api/v1', headers => { + expect(getBaggageHeaderItems(headers)).toEqual([ + 'sentry-environment=production', + 'sentry-public_key=public', + 'sentry-release=1.0', + expect.stringMatching(/sentry-sample_rand=0\.\d+/), + 'sentry-sample_rate=1', + 'sentry-sampled=true', + `sentry-trace_id=${traceId}`, + 'sentry-transaction=updated-name-1', + ]); + }) + .get('/api/v2', headers => { + expect(getBaggageHeaderItems(headers)).toEqual([ + 'sentry-environment=production', + 'sentry-public_key=public', + 'sentry-release=1.0', + expect.stringMatching(/sentry-sample_rand=0\.\d+/), + 'sentry-sample_rate=1', + 'sentry-sampled=true', + `sentry-trace_id=${traceId}`, + 'sentry-transaction=updated-name-2', + ]); + }) + .start(); - await createRunner(__dirname, 'scenario-headers.ts') - .withEnv({ SERVER_URL }) - .expect({ - span: {}, - }) - .start() - .completed(); - closeTestServer(); -}); + await createRunner(__dirname, 'scenario-headers.ts') + .withEnv({ SERVER_URL }) + .expect({ + span: {}, + }) + .start() + .completed(); + closeTestServer(); + }, +); test('adds current transaction name to trace envelope header when the txn name is high-quality', async () => { expect.assertions(4); diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts index 8d10084ce45e..7540e4df4c74 100644 --- a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { afterAll, describe, expect } from 'vitest'; import { cleanupChildProcesses, createCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http spans', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http spans', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts index e018a905ba28..ea01d0e2d6ce 100644 --- a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts @@ -17,8 +17,11 @@ import { import { createTestServer } from '@sentry-internal/test-utils'; import { afterAll, describe, expect } from 'vitest'; import { cleanupChildProcesses, createCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http spans - strip query', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http spans - strip query', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/ignoreSpans/continued-trace-segment/test.ts b/dev-packages/node-integration-tests/suites/tracing/ignoreSpans/continued-trace-segment/test.ts index 69c9874cd27f..cca3404c8c77 100644 --- a/dev-packages/node-integration-tests/suites/tracing/ignoreSpans/continued-trace-segment/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/ignoreSpans/continued-trace-segment/test.ts @@ -41,9 +41,9 @@ describe('ignoring a continued server segment', () => { }; test('propagates a negative sampling decision to outgoing fetch requests', () => testPropagation('/ignored')); - // Bun 1.3.14 does not instrument outgoing `node:http` requests. + // Bun before 1.4 does not instrument outgoing `node:http` requests. // See https://github.com/getsentry/sentry-javascript/issues/23881 - test.runIf(supports({ runtimes: ['node', 'deno'] }))( + test.runIf(supports({ bunMin: '1.4.0' }))( 'propagates a negative sampling decision to outgoing node:http requests', () => testPropagation('/ignored-http'), ); diff --git a/dev-packages/node-integration-tests/suites/tracing/no-parent-span-client-report/test.ts b/dev-packages/node-integration-tests/suites/tracing/no-parent-span-client-report/test.ts index 86702f80ee20..7119c19386ca 100644 --- a/dev-packages/node-integration-tests/suites/tracing/no-parent-span-client-report/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/no-parent-span-client-report/test.ts @@ -8,9 +8,9 @@ describe('no_parent_span client report', () => { }); createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { - // Bun 1.3.14 does not instrument outgoing `node:http` requests. + // Bun before 1.4 does not instrument outgoing `node:http` requests. // See https://github.com/getsentry/sentry-javascript/issues/23881 - test.runIf(supports({ runtimes: ['node', 'deno'] }))( + test.runIf(supports({ bunMin: '1.4.0' }))( 'records no_parent_span outcome for an outgoing http request without a local parent', async () => { const runner = createRunner() diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-breadcrumbs/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-breadcrumbs/test.ts index adf08ca19664..b11a2b17af8d 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-breadcrumbs/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-breadcrumbs/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('outgoing http requests create breadcrumbs', async () => { const [SERVER_URL, closeTestServer] = await createTestServer().start(); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-maxed-out-sockets/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-maxed-out-sockets/test.ts index 1f3f507c699f..dea41c1e52b0 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-maxed-out-sockets/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-maxed-out-sockets/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http with maxed-out agent sockets', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http with maxed-out agent sockets', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('injects trace headers into requests queued behind a busy socket', async () => { expect.assertions(5); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-trace-propagation/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-trace-propagation/test.ts index e4a592e5b571..e8c9f713943b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-trace-propagation/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-trace-propagation/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http with tracePropagation disabled', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http with tracePropagation disabled', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('does not inject trace headers but still creates breadcrumbs', async () => { expect.assertions(5); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts index df073d2c7ef0..8b63c5f18139 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http requests with tracing & spans disabled', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http requests with tracing & spans disabled', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('outgoing http requests are correctly instrumented with tracing & spans disabled', async () => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing/test.ts index 6bc9f3f06c6a..f28e25d77fb0 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('outgoing http requests are correctly instrumented with tracing disabled', async () => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-no-active-span/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-no-active-span/test.ts index b00148c26142..b1dec11ae4ae 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-no-active-span/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-no-active-span/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('outgoing sampled http requests without active span are correctly instrumented', async () => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled/test.ts index fe3621236b80..5be9793baae3 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('outgoing sampled http requests are correctly instrumented', async () => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-unsampled/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-unsampled/test.ts index 1b40af0b6ec3..357fd39cf28c 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-unsampled/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-unsampled/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; import { createEsmAndCjsTests } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -describe('outgoing http', () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('outgoing http', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { test('outgoing http requests are correctly instrumented when not sampled', async () => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/traceparent/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/traceparent/test.ts index 4443209e17aa..642f6bcf407e 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/traceparent/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/traceparent/test.ts @@ -42,33 +42,30 @@ describe('outgoing traceparent', () => { }); createEsmAndCjsTests(__dirname, 'scenario-http.mjs', 'instrument.mjs', (createRunner, test) => { - // Bun 1.3.14 does not instrument outgoing `node:http` requests. + // Bun before 1.4 does not instrument outgoing `node:http` requests. // See https://github.com/getsentry/sentry-javascript/issues/23881 - test.runIf(supports({ runtimes: ['node', 'deno'] }))( - 'outgoing http requests should get traceparent headers', - async () => { - expect.assertions(5); + test.runIf(supports({ bunMin: '1.4.0' }))('outgoing http requests should get traceparent headers', async () => { + expect.assertions(5); - const [SERVER_URL, closeTestServer] = await createTestServer() - .get('/api/v1', headers => { - expect(headers['baggage']).toEqual(expect.any(String)); - expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})-1$/)); - expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000-0'); - expect(headers['traceparent']).toEqual(expect.stringMatching(/^00-([a-f\d]{32})-([a-f\d]{16})-01$/)); - }) - .start(); + const [SERVER_URL, closeTestServer] = await createTestServer() + .get('/api/v1', headers => { + expect(headers['baggage']).toEqual(expect.any(String)); + expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})-1$/)); + expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000-0'); + expect(headers['traceparent']).toEqual(expect.stringMatching(/^00-([a-f\d]{32})-([a-f\d]{16})-01$/)); + }) + .start(); - await createRunner() - .withEnv({ SERVER_URL }) - .expect({ - span: { - // Span contents are tested elsewhere. - }, - }) - .start() - .completed(); - closeTestServer(); - }, - ); + await createRunner() + .withEnv({ SERVER_URL }) + .expect({ + span: { + // Span contents are tested elsewhere. + }, + }) + .start() + .completed(); + closeTestServer(); + }); }); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/baggage-org-id/test.ts b/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/baggage-org-id/test.ts index 732473ac4880..19991857bfcb 100644 --- a/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/baggage-org-id/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/baggage-org-id/test.ts @@ -1,37 +1,42 @@ -import { afterAll, expect, test } from 'vitest'; +import { afterAll, describe, expect, test } from 'vitest'; import { cleanupChildProcesses, createRunner } from '../../../../utils/runner'; import type { TestAPIResponse } from './server'; +import { supports } from '../../../../utils'; afterAll(() => { cleanupChildProcesses(); }); -test('should include explicitly set org_id in the baggage header', async () => { - const runner = createRunner(__dirname, 'server.ts').start(); +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +describe.runIf(supports({ bunMin: '1.4.0' }))('baggage org_id', () => { + test('should include explicitly set org_id in the baggage header', async () => { + const runner = createRunner(__dirname, 'server.ts').start(); - const response = await runner.makeRequest('get', '/test/express'); - expect(response).toBeDefined(); + const response = await runner.makeRequest('get', '/test/express'); + expect(response).toBeDefined(); - const baggage = response?.test_data.baggage; - expect(baggage).toContain('sentry-org_id=01234987'); -}); + const baggage = response?.test_data.baggage; + expect(baggage).toContain('sentry-org_id=01234987'); + }); -test('should extract org_id from DSN host when not explicitly set', async () => { - const runner = createRunner(__dirname, 'server-no-explicit-org-id.ts').start(); + test('should extract org_id from DSN host when not explicitly set', async () => { + const runner = createRunner(__dirname, 'server-no-explicit-org-id.ts').start(); - const response = await runner.makeRequest('get', '/test/express'); - expect(response).toBeDefined(); + const response = await runner.makeRequest('get', '/test/express'); + expect(response).toBeDefined(); - const baggage = response?.test_data.baggage; - expect(baggage).toContain('sentry-org_id=01234987'); -}); + const baggage = response?.test_data.baggage; + expect(baggage).toContain('sentry-org_id=01234987'); + }); -test('should set undefined org_id when it cannot be extracted', async () => { - const runner = createRunner(__dirname, 'server-no-org-id.ts').start(); + test('should set undefined org_id when it cannot be extracted', async () => { + const runner = createRunner(__dirname, 'server-no-org-id.ts').start(); - const response = await runner.makeRequest('get', '/test/express'); - expect(response).toBeDefined(); + const response = await runner.makeRequest('get', '/test/express'); + expect(response).toBeDefined(); - const baggage = response?.test_data.baggage; - expect(baggage).not.toContain('sentry-org_id'); + const baggage = response?.test_data.baggage; + expect(baggage).not.toContain('sentry-org_id'); + }); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/case-insensitive/test.ts b/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/case-insensitive/test.ts index 46eba247aa1b..2a72b31b5c7c 100644 --- a/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/case-insensitive/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/case-insensitive/test.ts @@ -1,8 +1,11 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { expect, test } from 'vitest'; import { createRunner } from '../../../../utils/runner'; +import { supports } from '../../../../utils'; -test('tracePropagationTargets match regardless of casing', async () => { +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +test.runIf(supports({ bunMin: '1.4.0' }))('tracePropagationTargets match regardless of casing', async () => { expect.assertions(9); const [SERVER_URL, closeTestServer] = await createTestServer() diff --git a/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/test.ts b/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/test.ts index 4ef1bb6c4bfe..8f212e94e72b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/tracePropagationTargets/test.ts @@ -1,39 +1,45 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { expect, test } from 'vitest'; import { createRunner } from '../../../utils/runner'; +import { supports } from '../../../utils'; -test('HttpIntegration should instrument correct requests when tracePropagationTargets option is provided', async () => { - expect.assertions(11); +// Bun before 1.4 does not instrument outgoing `node:http` requests. +// See https://github.com/getsentry/sentry-javascript/issues/23881 +test.runIf(supports({ bunMin: '1.4.0' }))( + 'HttpIntegration should instrument correct requests when tracePropagationTargets option is provided', + async () => { + expect.assertions(11); - const [SERVER_URL, closeTestServer] = await createTestServer() - .get('/api/v0', headers => { - expect(headers['baggage']).toEqual(expect.any(String)); - expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})-1$/)); - expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000-1'); - }) - .get('/api/v1', headers => { - expect(headers['baggage']).toEqual(expect.any(String)); - expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})-1$/)); - expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000-1'); - }) - .get('/api/v2', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v3', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .start(); + const [SERVER_URL, closeTestServer] = await createTestServer() + .get('/api/v0', headers => { + expect(headers['baggage']).toEqual(expect.any(String)); + expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})-1$/)); + expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000-1'); + }) + .get('/api/v1', headers => { + expect(headers['baggage']).toEqual(expect.any(String)); + expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})-1$/)); + expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000-1'); + }) + .get('/api/v2', headers => { + expect(headers['baggage']).toBeUndefined(); + expect(headers['sentry-trace']).toBeUndefined(); + }) + .get('/api/v3', headers => { + expect(headers['baggage']).toBeUndefined(); + expect(headers['sentry-trace']).toBeUndefined(); + }) + .start(); - await createRunner(__dirname, 'scenario.ts') - .withEnv({ SERVER_URL }) - .expect({ - span: { - // Span contents are tested elsewhere. - }, - }) - .start() - .completed(); - closeTestServer(); -}); + await createRunner(__dirname, 'scenario.ts') + .withEnv({ SERVER_URL }) + .expect({ + span: { + // Span contents are tested elsewhere. + }, + }) + .start() + .completed(); + closeTestServer(); + }, +); diff --git a/dev-packages/node-integration-tests/suites/tracing/tracer-start-active-span-error/test.ts b/dev-packages/node-integration-tests/suites/tracing/tracer-start-active-span-error/test.ts index b8d33d7976cf..993777eb2ca2 100644 --- a/dev-packages/node-integration-tests/suites/tracing/tracer-start-active-span-error/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/tracer-start-active-span-error/test.ts @@ -1,7 +1,9 @@ import { afterAll, describe, expect } from 'vitest'; import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; +import { supports } from '../../../utils'; -describe('tracer.startActiveSpan errors', () => { +// Fails on Bun before 1.4. The cause is not investigated yet. +describe.runIf(supports({ bunMin: '1.4.0' }))('tracer.startActiveSpan errors', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/dev-packages/node-integration-tests/utils/index.ts b/dev-packages/node-integration-tests/utils/index.ts index 4a6b9a4dde96..b3a1dfd8153d 100644 --- a/dev-packages/node-integration-tests/utils/index.ts +++ b/dev-packages/node-integration-tests/utils/index.ts @@ -1,5 +1,6 @@ import type { EnvelopeItemType } from '@sentry/core'; import { parseSemver } from '@sentry/core'; +import { execFileSync } from 'child_process'; import type * as http from 'http'; export const NODE_VERSION = parseSemver(process.versions.node).major || 0; @@ -10,6 +11,9 @@ export const NODE_VERSION = parseSemver(process.versions.node).major || 0; export type Runtime = 'cloudflare' | 'node' | 'bun' | 'deno'; export const RUNTIME = (process.env.RUNTIME || 'node') as Runtime; +// Vitest runs on Node, so it cannot read `Bun.version` of the `bun` binary that runs the scenarios. +const BUN_VERSION = RUNTIME === 'bun' ? execFileSync('bun', ['--version'], { encoding: 'utf8' }).trim() : undefined; + /** * The `sdk.name` the scenarios send. It is `sentry.javascript.node`, unless a runtime package * maps `@sentry/node` to its own SDK and sets the `EXPECTED_SDK_NAME` env var to that SDK's name. @@ -44,13 +48,15 @@ export type Requirements = { min?: number; /** Highest Node major version that runs the tests. */ max?: number; + /** Lowest Bun version that runs the tests, for tests that fail on the oldest Bun version in CI. */ + bunMin?: string; /** Runtimes that run the tests. All runtimes run them when this is not set. */ runtimes?: Runtime[]; }; /** - * Whether the Node version and the runtime that runs the scenarios meet the requirements of the - * tests, for use in `test.runIf` and `describe.runIf`. + * Whether the Node version, the runtime and the Bun version that run the scenarios meet the + * requirements of the tests, for use in `test.runIf` and `describe.runIf`. * * On Bun and Deno the Node version requirement does not apply. A suite that cannot run on a Node * version must also be excluded for these runtimes, in @@ -61,6 +67,9 @@ export function supports(requirements: Requirements): boolean { if (requirements.runtimes && !requirements.runtimes.includes(RUNTIME)) { return false; } + if (RUNTIME === 'bun') { + return !requirements.bunMin || !isBunOlderThan(requirements.bunMin); + } // Vitest always runs on Node, so its Node version says nothing about Bun or Deno running the // scenario. Those runtimes list the suites they cannot run in their own exclude lists. if (RUNTIME !== 'node') { @@ -77,6 +86,21 @@ function matchesNodeVersion({ min, max }: { min?: number; max?: number }): boole return !(NODE_VERSION < (min || -Infinity) || NODE_VERSION > (max || Infinity)); } +function isBunOlderThan(version: string): boolean { + if (!BUN_VERSION) { + return false; + } + + const current = parseSemver(BUN_VERSION); + const required = parseSemver(version); + const difference = + (current.major || 0) - (required.major || 0) || + (current.minor || 0) - (required.minor || 0) || + (current.patch || 0) - (required.patch || 0); + + return difference < 0; +} + /** * Parses response body containing an Envelope *