From de1a69398653f2e9c8aa9126892039c1ee3bbb0f Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 23 Sep 2026 17:48:04 +0200 Subject: [PATCH 1/5] 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 408f25af61407a93c0aeb365eba96d6d1d5f3ce0 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 23 Sep 2026 18:51:38 +0200 Subject: [PATCH 2/5] 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 7e8277e52e11d9839d20b70bf90ca1c7706f7d21 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 23 Sep 2026 18:58:54 +0200 Subject: [PATCH 3/5] 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 f4b61671e132f48a9974556f302b5c2f3c461ecf Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Thu, 24 Sep 2026 12:31:57 +0200 Subject: [PATCH 4/5] 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 0406e7679b039267558fd1dd58828b6298ef07c2 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Fri, 25 Sep 2026 10:35:07 +0200 Subject: [PATCH 5/5] 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 054fa9b28cc6..20dc8513b28e 100644 --- a/dev-packages/node-integration-tests/utils/index.ts +++ b/dev-packages/node-integration-tests/utils/index.ts @@ -42,20 +42,27 @@ 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. * - * @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 {