From 7c30c4ba5bb86dd68637dc778b6075f02ec9275a Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 23 Sep 2026 17:48:04 +0200 Subject: [PATCH 1/8] test(deno): Run all Node integration suites on Deno The Deno package now selects every Node suite and excludes the ones that do not run on Deno, grouped by cause: Node-only features, no `fetch` instrumentation because Deno's `fetch` does not publish undici channels, a Prisma interop limit, suites that fail for a cause not investigated yet, and one flaky suite. The list is based on Deno 2.8.3, the version CI pins. The database suites run too, so the Deno CI job gets the disk space step and the 20 minute timeout of the Node integration job. The runner now starts every scenario in the `node-integration-tests` folder, because the Deno and Bun packages run the suites from their own folder and scenarios such as `modules` read the working directory. When a test times out, it prints the child output with the child state. `yarn test ` now filters the shared suites, as in the other packages. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/build.yml | 15 +++- .../node-suites/excludes.ts | 72 +++++++++++++++++++ .../deno-integration-tests/package.json | 4 +- .../scripts/run-tests.mjs | 27 +++++++ .../deno-integration-tests/vite.config.mts | 15 ++-- .../suites/tracing/httpIntegration/test.ts | 4 +- .../suites/tracing/postgres-streamed/test.ts | 5 +- .../suites/tracing/postgres/test.ts | 5 +- .../suites/tracing/postgresjs/test.ts | 4 +- .../tracer-start-active-span-error/test.ts | 3 + .../utils/runner/createRunner.ts | 38 +++++++++- 11 files changed, 169 insertions(+), 23 deletions(-) create mode 100644 dev-packages/deno-integration-tests/node-suites/excludes.ts create mode 100644 dev-packages/deno-integration-tests/scripts/run-tests.mjs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 908dfc211966..453f752a3931 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -935,12 +935,25 @@ jobs: needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_deno_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04 - timeout-minutes: 15 + timeout-minutes: 20 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v7 with: ref: ${{ env.HEAD_COMMIT }} + - name: Free up disk space if low + # The shared Node suites pull several DB docker images (mssql alone is ~1.5GB) + # Available disk space is not consistent, if we detect low space this cleans up some unused toolchains + run: | + df -h / + avail_kb=$(df -k --output=avail / | tail -1) + if [ "$avail_kb" -lt $((40 * 1024 * 1024)) ]; then + echo "Low disk space (<40GB free), reclaiming unused toolchains" + sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc /usr/local/.ghcup /opt/hostedtoolcache/CodeQL + df -h / + else + echo "Sufficient disk space, skipping cleanup" + fi - name: Set up Node uses: actions/setup-node@v7 with: diff --git a/dev-packages/deno-integration-tests/node-suites/excludes.ts b/dev-packages/deno-integration-tests/node-suites/excludes.ts new file mode 100644 index 000000000000..e1700b84c9cd --- /dev/null +++ b/dev-packages/deno-integration-tests/node-suites/excludes.ts @@ -0,0 +1,72 @@ +// Node suites that do not run on Deno, relative to `node-integration-tests`. A single test that +// fails on Deno is skipped with `test.skipIf` on `RUNTIME` in the Node suite, not listed here. + +// Node-only features: ANR and native thread watchdogs, child process and worker thread breadcrumbs. +const NODE_ONLY = ['suites/anr/test.ts', 'suites/breadcrumbs/**', 'suites/thread-blocked-native/test.ts']; + +// `@sentry/node` instruments `fetch` through undici's diagnostics channels, which Deno's `fetch` +// does not publish. `@sentry/deno` has its own `fetchIntegration` for this. These suites check +// spans, breadcrumbs or headers of outgoing `fetch` requests. +const NO_FETCH_INSTRUMENTATION = [ + 'suites/tracing/double-baggage/**', + 'suites/tracing/http-client-span-streamed/test.ts', + 'suites/tracing/http-client-spans/fetch-basic-streamed/test.ts', + 'suites/tracing/http-client-spans/fetch-basic/test.ts', + 'suites/tracing/http-client-spans/fetch-error/test.ts', + 'suites/tracing/http-client-spans/fetch-forward-request-hook/test.ts', + 'suites/tracing/http-client-spans/fetch-headers-to-span-attributes/test.ts', + 'suites/tracing/http-client-spans/fetch-strip-query/test.ts', + 'suites/tracing/ignoreSpans-streamed/continued-trace-child/test.ts', + 'suites/tracing/ignoreSpans-streamed/continued-trace-http-client/test.ts', + 'suites/tracing/ignoreSpans-streamed/continued-trace-segment/test.ts', + 'suites/tracing/no-parent-span-client-report/test.ts', + 'suites/tracing/requests/fetch-breadcrumbs/test.ts', + 'suites/tracing/requests/fetch-no-trace-propagation/test.ts', + 'suites/tracing/requests/fetch-no-tracing-no-spans/test.ts', + 'suites/tracing/requests/fetch-no-tracing/test.ts', + 'suites/tracing/requests/fetch-sampled-no-active-span/test.ts', + 'suites/tracing/requests/fetch-unsampled/test.ts', + 'suites/tracing/requests/traceparent/test.ts', + 'suites/tracing/sample-rand-propagation/test.ts', + 'suites/tracing/sample-rate-propagation/**', +]; + +// In the ESM tests Deno cannot find `PrismaClient`, a CommonJS export of `@prisma/client`. +const PRISMA_ESM_INTEROP = ['suites/tracing/prisma-orm-v5/test.ts', 'suites/tracing/prisma-orm-v6/test.ts']; + +// Some or all tests fail on Deno, cause 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 = [ + 'suites/tracing/anthropic/test.ts', + 'suites/tracing/apollo-graphql/**', + 'suites/tracing/fastify/test.ts', + 'suites/tracing/google-genai/test.ts', + 'suites/tracing/groq/test.ts', + 'suites/tracing/http-client-spans/http-strip-query/test.ts', + 'suites/tracing/ioredis-dc/test.ts', + 'suites/tracing/koa/test.ts', + 'suites/tracing/langchain/test.ts', + 'suites/tracing/langgraph/test.ts', + 'suites/tracing/mistral/test.ts', + 'suites/tracing/mongodb/test.ts', + 'suites/tracing/mongoose-v5/test.ts', + 'suites/tracing/mysql/test.ts', + 'suites/tracing/openai/test.ts', + 'suites/tracing/orchestrion-lazy-registration/test.ts', + 'suites/tracing/prisma-orm-v7/test.ts', + 'suites/tracing/together-ai/test.ts', + 'suites/tracing/vercelai/v6_v7/test.ts', +]; + +// Passes on Deno when run alone, but failed in about 1 of 3 full runs of this package. +const FLAKY = ['suites/tracing/tracePropagationTargets/**']; + +export const NODE_SUITES_EXCLUDE = [ + '**/node_modules/**', + ...NODE_ONLY, + ...NO_FETCH_INSTRUMENTATION, + ...PRISMA_ESM_INTEROP, + ...NOT_TRIAGED, + ...FLAKY, +]; diff --git a/dev-packages/deno-integration-tests/package.json b/dev-packages/deno-integration-tests/package.json index 9cfb31eef59a..f2b8cc9335e9 100644 --- a/dev-packages/deno-integration-tests/package.json +++ b/dev-packages/deno-integration-tests/package.json @@ -11,8 +11,8 @@ "install:deno": "node ./scripts/install-deno.mjs", "lint": "oxlint . --type-aware", "lint:fix": "oxlint . --fix --type-aware", - "test": "run-s install:deno deno-types test:unit test:node-suites", - "test:unit": "deno test --allow-net --allow-read --allow-run --allow-env --no-check", + "test": "node ./scripts/run-tests.mjs", + "test:unit": "deno test --allow-net --allow-read --allow-run --allow-env --no-check suites", "test:node-suites": "vitest run" }, "dependencies": { diff --git a/dev-packages/deno-integration-tests/scripts/run-tests.mjs b/dev-packages/deno-integration-tests/scripts/run-tests.mjs new file mode 100644 index 000000000000..dd6114395553 --- /dev/null +++ b/dev-packages/deno-integration-tests/scripts/run-tests.mjs @@ -0,0 +1,27 @@ +// `yarn test` runs the Deno-only suites (`deno test`) and then the shared Node suites (vitest), +// like the other integration test packages. +// +// `yarn test ` runs only the shared Node suites with that filter, e.g. `yarn test express`, +// because `deno test` does not take vitest filters. To filter the Deno-only suites by test name, +// run `yarn test:unit --filter `. +import { spawnSync } from 'node:child_process'; + +const filters = process.argv.slice(2); + +function run(script, args = []) { + const result = spawnSync('yarn', ['--silent', script, ...args], { + stdio: 'inherit', + shell: process.platform === 'win32', + }); + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} + +if (filters.length === 0) { + run('install:deno'); + run('deno-types'); + run('test:unit'); +} + +run('test:node-suites', filters); diff --git a/dev-packages/deno-integration-tests/vite.config.mts b/dev-packages/deno-integration-tests/vite.config.mts index fd87eb1f2d26..6dccfdc74a5e 100644 --- a/dev-packages/deno-integration-tests/vite.config.mts +++ b/dev-packages/deno-integration-tests/vite.config.mts @@ -1,8 +1,9 @@ import { fileURLToPath } from 'node:url'; import { defineConfig } from 'vitest/config'; import baseConfig from '../../vite/vite.config'; +import { NODE_SUITES_EXCLUDE } from './node-suites/excludes'; -// Runs the Node suites below on Deno. The scenarios stay in `node-integration-tests`, and the +// Runs all Node suites on Deno. The scenarios stay in `node-integration-tests`, and the // Deno-only suites in `suites/` run with `deno test`. export default defineConfig({ ...baseConfig, @@ -13,16 +14,8 @@ export default defineConfig({ enabled: false, }, isolate: false, - include: [ - 'suites/public-api/**/test.ts', - 'suites/client-reports/**/test.ts', - 'suites/featureFlags/**/test.ts', - 'suites/express/tracing/**/test.ts', - 'suites/tracing/httpIntegration/test.ts', - 'suites/tracing/httpIntegration-streamed/test.ts', - ], - // Single tests that fail on Deno are skipped with `test.skipIf` on `RUNTIME` in the Node suite. - exclude: ['**/node_modules/**'], + include: ['suites/**/test.ts'], + exclude: NODE_SUITES_EXCLUDE, env: { RUNTIME: 'deno', DENO_IMPORT_MAP: fileURLToPath(new URL('./node-suites/import-map.json', import.meta.url)), diff --git a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts index 76c62fdf7bd3..afd5cbe927a6 100644 --- a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts @@ -2,6 +2,7 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; import { afterAll, describe, expect, test } from 'vitest'; import { cleanupChildProcesses, createEsmAndCjsTests, createRunner } from '../../../utils/runner'; +import { RUNTIME } from '../../../utils'; function getCommonHttpRequestHeaders(): Record { return { @@ -173,7 +174,8 @@ describe('httpIntegration', () => { }); }); - describe('custom server.emit', () => { + // Deno: the requests sometimes get a 500 response when `server.emit` is overwritten. + describe.skipIf(RUNTIME === 'deno')('custom server.emit', () => { createEsmAndCjsTests( __dirname, 'scenario-overwrite-server-emit.mjs', diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts b/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts index 645fe2ff8d12..c1bb8ef83855 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts @@ -2,7 +2,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core'; import type { SerializedStreamedSpanContainer } from '@sentry/core'; import { SENTRY_TRACE_LIFECYCLE } from '@sentry/conventions/attributes'; import { afterAll, describe, expect } from 'vitest'; -import { conditionalTest } from '../../../utils'; +import { conditionalTest, RUNTIME } from '../../../utils'; import { cleanupChildProcesses, createEsmAndCjsTests, describeWithDockerCompose } from '../../../utils/runner'; // Query-span origin depends on which instrumentation is active. Blocks driving the SDK's default @@ -227,7 +227,8 @@ describeWithDockerCompose('postgres auto instrumentation (streamed)', { workingD }); }); - conditionalTest({ max: 25 })('pg-native', () => { + // Deno: with a module load hook installed, Deno compiles a native addon (`libpq`) as JavaScript. + (RUNTIME === 'deno' ? describe.skip : conditionalTest({ max: 25 }))('pg-native', () => { createEsmAndCjsTests( __dirname, 'scenario-native.mjs', diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts index ce96a147a315..0bba595a1c1d 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts @@ -1,5 +1,5 @@ import { afterAll, describe, expect } from 'vitest'; -import { conditionalTest } from '../../../utils'; +import { conditionalTest, RUNTIME } from '../../../utils'; import { cleanupChildProcesses, createEsmAndCjsTests, describeWithDockerCompose } from '../../../utils/runner'; describeWithDockerCompose('postgres auto instrumentation', { workingDirectory: [__dirname] }, () => { @@ -276,7 +276,8 @@ describeWithDockerCompose('postgres auto instrumentation', { workingDirectory: [ }); }); - conditionalTest({ max: 25 })('pg-native', () => { + // Deno: with a module load hook installed, Deno compiles a native addon (`libpq`) as JavaScript. + (RUNTIME === 'deno' ? describe.skip : conditionalTest({ max: 25 }))('pg-native', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts b/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts index 7e99d58dedff..d893e5200004 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts @@ -488,7 +488,9 @@ describeWithDockerCompose('postgresjs auto instrumentation', { workingDirectory: createEsmAndCjsTests(__dirname, 'scenario-unsafe.mjs', 'instrument.mjs', (createTestRunner, test) => { test('should instrument sql.unsafe() queries', { timeout: 90_000 }, async () => { - await createTestRunner().expect({ transaction: EXPECTED_TRANSACTION }).start().completed(); + // The last query fails on purpose, and its unhandled rejection also sends an error event, which can + // arrive before the transaction. + await createTestRunner().ignore('event').expect({ transaction: EXPECTED_TRANSACTION }).start().completed(); }); }); }); 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 64809c28aa24..c315cf866900 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 @@ -16,6 +16,9 @@ describe('tracer.startActiveSpan errors', () => { // `catch` inside the callback. test('does NOT mark span errored when uncaught error escapes raw tracer.startActiveSpan callback', async () => { await createRunner() + // The rejection is captured as an error event, which can reach the transport before the + // transaction. + .ignore('event') .expect({ transaction: { transaction: 'test span name', diff --git a/dev-packages/node-integration-tests/utils/runner/createRunner.ts b/dev-packages/node-integration-tests/utils/runner/createRunner.ts index 3312be42dd8c..e737cfa4be8e 100644 --- a/dev-packages/node-integration-tests/utils/runner/createRunner.ts +++ b/dev-packages/node-integration-tests/utils/runner/createRunner.ts @@ -19,6 +19,7 @@ import { existsSync } from 'fs'; import { tmpdir } from 'os'; import { join } from 'path'; import { inspect } from 'util'; +import { onTestFailed } from 'vitest'; import type { DeepPartial } from './../assertions'; import { assertEnvelopeHeader, @@ -108,6 +109,10 @@ const NODE_MAJOR = Number(process.versions.node.split('.')[0]); const COMPILE_CACHE_ENV: Record = NODE_MAJOR >= 22 ? { NODE_COMPILE_CACHE: join(tmpdir(), 'sentry-node-it-compile-cache') } : {}; +// The Bun and Deno packages run these suites from their own folder. Scenarios read the working +// directory (e.g. `modulesIntegration` reads its `package.json`), so it is always this package. +const PACKAGE_ROOT = join(__dirname, '..', '..'); + /** Node flags that preload a module before the entry point. */ const PRELOAD_FLAGS = ['--import', '--require', '-r']; @@ -277,7 +282,11 @@ export function createRunner(...paths: string[]) { let envelopeCount = 0; let scenarioServerPort: number | undefined; let hasExited = false; + let exitStatus: string | undefined; let child: ReturnType | undefined; + let spawnedAt: number | undefined; + let lastOutputAt: number | undefined; + let logsDumped = false; // Resolved the moment `complete()` runs, so `completed()` can await the result directly // instead of polling — see the comment on `waitForEvent`. @@ -285,6 +294,14 @@ export function createRunner(...paths: string[]) { // Resolved once the scenario reports its server port, so `makeRequest` can await it directly. const portReady = createDeferred(); + // Vitest stops a test at its own timeout before `completed()` gives up, so print the child + // output then too. `completed()` prints it for the failures it reports itself. + onTestFailed(() => { + if (!isComplete) { + dumpCapturedLogs(); + } + }); + function complete(error?: Error): void { if (isComplete) { return; @@ -322,12 +339,23 @@ export function createRunner(...paths: string[]) { function dumpCapturedLogs(): void { // Skip when the failure is expected (`test.fails` variants) — the output would just be noise. // In debug mode the same lines are already streamed live, so skip then too. - if (process.env.DEBUG || suppressErrorLogs) { + if (process.env.DEBUG || suppressErrorLogs || logsDumped) { return; } + logsDumped = true; + const now = Date.now(); + const state = [ + `runtime=${getRuntime()}`, + `pid=${child?.pid ?? 'none'}`, + hasExited ? `exited (${exitStatus})` : 'running', + `envelopes=${envelopeCount}/${expectedEnvelopeCount}`, + `ms since spawn=${spawnedAt ? now - spawnedAt : 'not spawned'}`, + `ms since last output=${lastOutputAt ? now - lastOutputAt : 'no output'}`, + ].join(', '); + // eslint-disable-next-line no-console - console.log(`\n--- Captured child process output for ${testPath} ---`); + console.log(`\n--- Captured child process output for ${testPath} (${state}) ---`); if (logs.length === 0) { // eslint-disable-next-line no-console console.log('(no output captured)'); @@ -474,7 +502,8 @@ export function createRunner(...paths: string[]) { const runtime = getRuntime(); const childFlags = wantsAutoFlush ? [...buildAutoFlushFlags(flags, testPath, runtime), ...flags] : flags; - child = spawn(runtime, buildRuntimeArgs(runtime, childFlags, testPath), { env }); + child = spawn(runtime, buildRuntimeArgs(runtime, childFlags, testPath), { env, cwd: PACKAGE_ROOT }); + spawnedAt = Date.now(); child.on('error', e => { // eslint-disable-next-line no-console @@ -491,6 +520,7 @@ export function createRunner(...paths: string[]) { }); child.stderr?.on('data', (data: Buffer) => { + lastOutputAt = Date.now(); const output = data.toString(); logs.push(output.trim()); @@ -504,6 +534,7 @@ export function createRunner(...paths: string[]) { child.on('close', (code, signal) => { hasExited = true; + exitStatus = signal ? `signal ${signal}` : `code ${code ?? 'unknown'}`; if (ensureNoErrorOutput) { complete(); @@ -562,6 +593,7 @@ export function createRunner(...paths: string[]) { let buffer = Buffer.alloc(0); child.stdout?.on('data', (data: Buffer) => { + lastOutputAt = Date.now(); // This is horribly memory inefficient but it's only for tests buffer = Buffer.concat([buffer, data]); From 538d5473890bb4827d1f85340fc69b6546587133 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 23 Sep 2026 18:51:38 +0200 Subject: [PATCH 2/8] fixup! test(deno): Run all Node integration suites on Deno Co-Authored-By: Claude Opus 5.5 --- .github/workflows/build.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 453f752a3931..c464eb4ecb1c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -941,19 +941,6 @@ jobs: uses: actions/checkout@v7 with: ref: ${{ env.HEAD_COMMIT }} - - name: Free up disk space if low - # The shared Node suites pull several DB docker images (mssql alone is ~1.5GB) - # Available disk space is not consistent, if we detect low space this cleans up some unused toolchains - run: | - df -h / - avail_kb=$(df -k --output=avail / | tail -1) - if [ "$avail_kb" -lt $((40 * 1024 * 1024)) ]; then - echo "Low disk space (<40GB free), reclaiming unused toolchains" - sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc /usr/local/.ghcup /opt/hostedtoolcache/CodeQL - df -h / - else - echo "Sufficient disk space, skipping cleanup" - fi - name: Set up Node uses: actions/setup-node@v7 with: From 276d2eaee7b2c9400e5787af50e92119083c6579 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 23 Sep 2026 18:58:54 +0200 Subject: [PATCH 3/8] fixup! test(deno): Run all Node integration suites on Deno Co-Authored-By: Claude Opus 5.5 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c464eb4ecb1c..908dfc211966 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -935,7 +935,7 @@ jobs: needs: [job_get_metadata, job_build] if: needs.job_build.outputs.changed_deno_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-24.04 - timeout-minutes: 20 + timeout-minutes: 15 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v7 From 6992fae79263f746eb41d098c01d5d90e11994b2 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Thu, 24 Sep 2026 12:31:57 +0200 Subject: [PATCH 4/8] fixup! test(deno): Run all Node integration suites on Deno Co-Authored-By: Claude Opus 5.5 --- .../deno-integration-tests/node-suites/excludes.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dev-packages/deno-integration-tests/node-suites/excludes.ts b/dev-packages/deno-integration-tests/node-suites/excludes.ts index e1700b84c9cd..90e45b4971b6 100644 --- a/dev-packages/deno-integration-tests/node-suites/excludes.ts +++ b/dev-packages/deno-integration-tests/node-suites/excludes.ts @@ -34,6 +34,10 @@ const NO_FETCH_INSTRUMENTATION = [ // In the ESM tests Deno cannot find `PrismaClient`, a CommonJS export of `@prisma/client`. const PRISMA_ESM_INTEROP = ['suites/tracing/prisma-orm-v5/test.ts', 'suites/tracing/prisma-orm-v6/test.ts']; +// In the CJS tests Deno cannot `require()` a dependency that ships only ES modules: `graphql` 17, +// and `escape-string-regexp` under `mastra`. The ESM tests of `mastra` also check `fetch` spans. +const REQUIRE_OF_ESM_ONLY_DEPENDENCY = ['suites/tracing/graphql-tracing-channel/**', 'suites/tracing/mastra/test.ts']; + // Some or all tests fail on Deno, cause 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. @@ -41,6 +45,7 @@ const NOT_TRIAGED = [ 'suites/tracing/anthropic/test.ts', 'suites/tracing/apollo-graphql/**', 'suites/tracing/fastify/test.ts', + 'suites/tracing/flue/test.ts', 'suites/tracing/google-genai/test.ts', 'suites/tracing/groq/test.ts', 'suites/tracing/http-client-spans/http-strip-query/test.ts', @@ -53,6 +58,7 @@ const NOT_TRIAGED = [ 'suites/tracing/mongoose-v5/test.ts', 'suites/tracing/mysql/test.ts', 'suites/tracing/openai/test.ts', + 'suites/tracing/openai/v7/test.ts', 'suites/tracing/orchestrion-lazy-registration/test.ts', 'suites/tracing/prisma-orm-v7/test.ts', 'suites/tracing/together-ai/test.ts', @@ -67,6 +73,7 @@ export const NODE_SUITES_EXCLUDE = [ ...NODE_ONLY, ...NO_FETCH_INSTRUMENTATION, ...PRISMA_ESM_INTEROP, + ...REQUIRE_OF_ESM_ONLY_DEPENDENCY, ...NOT_TRIAGED, ...FLAKY, ]; From a4ad52de20a8a5691b1f14131e14041452136c80 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Fri, 25 Sep 2026 10:35:07 +0200 Subject: [PATCH 5/8] fixup! test(deno): Run all Node integration suites on Deno Co-Authored-By: Claude Opus 5.5 --- .../suites/tracing/postgres-streamed/test.ts | 4 ++-- .../suites/tracing/postgres/test.ts | 4 ++-- .../node-integration-tests/utils/index.ts | 15 +++++++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts b/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts index c1bb8ef83855..92a48d809282 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres-streamed/test.ts @@ -2,7 +2,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core'; import type { SerializedStreamedSpanContainer } from '@sentry/core'; import { SENTRY_TRACE_LIFECYCLE } from '@sentry/conventions/attributes'; import { afterAll, describe, expect } from 'vitest'; -import { conditionalTest, RUNTIME } from '../../../utils'; +import { conditionalTest } from '../../../utils'; import { cleanupChildProcesses, createEsmAndCjsTests, describeWithDockerCompose } from '../../../utils/runner'; // Query-span origin depends on which instrumentation is active. Blocks driving the SDK's default @@ -228,7 +228,7 @@ describeWithDockerCompose('postgres auto instrumentation (streamed)', { workingD }); // Deno: with a module load hook installed, Deno compiles a native addon (`libpq`) as JavaScript. - (RUNTIME === 'deno' ? describe.skip : conditionalTest({ max: 25 }))('pg-native', () => { + conditionalTest({ max: 25, skipRuntimes: ['deno'] })('pg-native', () => { createEsmAndCjsTests( __dirname, 'scenario-native.mjs', diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts index 0bba595a1c1d..304af1aaffb0 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts @@ -1,5 +1,5 @@ import { afterAll, describe, expect } from 'vitest'; -import { conditionalTest, RUNTIME } from '../../../utils'; +import { conditionalTest } from '../../../utils'; import { cleanupChildProcesses, createEsmAndCjsTests, describeWithDockerCompose } from '../../../utils/runner'; describeWithDockerCompose('postgres auto instrumentation', { workingDirectory: [__dirname] }, () => { @@ -277,7 +277,7 @@ describeWithDockerCompose('postgres auto instrumentation', { workingDirectory: [ }); // Deno: with a module load hook installed, Deno compiles a native addon (`libpq`) as JavaScript. - (RUNTIME === 'deno' ? describe.skip : conditionalTest({ max: 25 }))('pg-native', () => { + conditionalTest({ max: 25, skipRuntimes: ['deno'] })('pg-native', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ diff --git a/dev-packages/node-integration-tests/utils/index.ts b/dev-packages/node-integration-tests/utils/index.ts index 38586f26eff9..cc9b0e330a3a 100644 --- a/dev-packages/node-integration-tests/utils/index.ts +++ b/dev-packages/node-integration-tests/utils/index.ts @@ -42,24 +42,31 @@ export type DataCollectorOptions = { }; /** - * Returns`describe` or `describe.skip` depending on allowed major versions of Node. + * Returns`describe` or `describe.skip` depending on allowed major versions of Node and on the + * runtime that runs the scenarios. * * On Bun the version gate does not apply and the block always runs. A suite that the gate keeps * off a Node version because it cannot run there must also be excluded for Bun in * `dev-packages/bun-integration-tests/node-suites/excludes.ts`. * - * @param {{ min?: number; max?: number }} allowedVersion + * @param options.min Lowest Node major version that runs the block. + * @param options.max Highest Node major version that runs the block. + * @param options.skipRuntimes Runtimes that skip the block, for a block that cannot run there. */ -export function conditionalTest(allowedVersion: { +export function conditionalTest(options: { min?: number; max?: number; + skipRuntimes?: Runtime[]; }): typeof describe | typeof describe.skip { + if (options.skipRuntimes?.includes(RUNTIME)) { + return describe.skip; + } // 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') { return describe; } - return describe.skipIf(!matchesNodeVersion(allowedVersion)); + return describe.skipIf(!matchesNodeVersion(options)); } function matchesNodeVersion({ min, max }: { min?: number; max?: number }): boolean { From 496501ff77cafda2fa5db054d16b27879cc58cd6 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Sun, 27 Sep 2026 15:36:57 +0200 Subject: [PATCH 6/8] fixup! test(deno): Run all Node integration suites on Deno Co-Authored-By: Claude Opus 5.5 --- .../deno-integration-tests/node-suites/excludes.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dev-packages/deno-integration-tests/node-suites/excludes.ts b/dev-packages/deno-integration-tests/node-suites/excludes.ts index 90e45b4971b6..e2b5e0cd5b01 100644 --- a/dev-packages/deno-integration-tests/node-suites/excludes.ts +++ b/dev-packages/deno-integration-tests/node-suites/excludes.ts @@ -35,8 +35,14 @@ const NO_FETCH_INSTRUMENTATION = [ const PRISMA_ESM_INTEROP = ['suites/tracing/prisma-orm-v5/test.ts', 'suites/tracing/prisma-orm-v6/test.ts']; // In the CJS tests Deno cannot `require()` a dependency that ships only ES modules: `graphql` 17, -// and `escape-string-regexp` under `mastra`. The ESM tests of `mastra` also check `fetch` spans. -const REQUIRE_OF_ESM_ONLY_DEPENDENCY = ['suites/tracing/graphql-tracing-channel/**', 'suites/tracing/mastra/test.ts']; +// `escape-string-regexp` under `mastra`, and `@prisma/orm-postgres`. The ESM tests of `mastra` also +// check `fetch` spans. The ESM test of `prisma-orm-v8` imports JSON with `with { type: 'json' }`, +// which any module load hook breaks on Deno 2.8.3 (the CI version); it passes on Deno 2.9.0. +const REQUIRE_OF_ESM_ONLY_DEPENDENCY = [ + 'suites/tracing/graphql-tracing-channel/**', + 'suites/tracing/mastra/test.ts', + 'suites/tracing/prisma-orm-v8/test.ts', +]; // Some or all tests fail on Deno, cause 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 From 0d806b3bb61e9f550ba88e9f2afc99a0d1e6568e Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Sun, 27 Sep 2026 16:39:41 +0200 Subject: [PATCH 7/8] fixup! test(deno): Run all Node integration suites on Deno Document that conditionalTest does not gate Deno either, and point at the Deno exclude list and skipRuntimes. Co-Authored-By: Claude Opus 5.5 --- dev-packages/node-integration-tests/utils/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dev-packages/node-integration-tests/utils/index.ts b/dev-packages/node-integration-tests/utils/index.ts index cc9b0e330a3a..21fdff8fe8a8 100644 --- a/dev-packages/node-integration-tests/utils/index.ts +++ b/dev-packages/node-integration-tests/utils/index.ts @@ -45,9 +45,10 @@ export type DataCollectorOptions = { * Returns`describe` or `describe.skip` depending on allowed major versions of Node and on the * runtime that runs the scenarios. * - * On Bun the version gate does not apply and the block always runs. A suite that the gate keeps - * off a Node version because it cannot run there must also be excluded for Bun in - * `dev-packages/bun-integration-tests/node-suites/excludes.ts`. + * On Bun and Deno the version gate does not apply and the block always runs. A suite that the gate + * keeps off a Node version because it cannot run there must also be excluded for these runtimes, + * in `dev-packages/bun-integration-tests/node-suites/excludes.ts` and + * `dev-packages/deno-integration-tests/node-suites/excludes.ts`, or skipped with `skipRuntimes`. * * @param options.min Lowest Node major version that runs the block. * @param options.max Highest Node major version that runs the block. From 378d93413cd0a5f0f5a9be43dbf412c446008cdb Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Sun, 27 Sep 2026 16:39:49 +0200 Subject: [PATCH 8/8] fixup! test(deno): Run all Node integration suites on Deno Point new Node suites at the Deno exclude list in the README. Co-Authored-By: Claude Opus 5.5 --- dev-packages/node-integration-tests/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dev-packages/node-integration-tests/README.md b/dev-packages/node-integration-tests/README.md index 07385c42ffd1..e8e9aedf5620 100644 --- a/dev-packages/node-integration-tests/README.md +++ b/dev-packages/node-integration-tests/README.md @@ -36,9 +36,10 @@ flakiness. ## Other Runtimes -`dev-packages/bun-integration-tests` runs every suite of this package on Bun as well. When you add a suite, check that it -passes on Bun. If it cannot, add it to `dev-packages/bun-integration-tests/node-suites/excludes.ts` with the reason, or -skip the single tests that fail with `test.skipIf(RUNTIME === 'bun')`. +`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 skip the single tests that fail with +`test.skipIf(RUNTIME === 'bun')` or `test.skipIf(RUNTIME === 'deno')`. ## Running Tests Locally