From 9879c1eb1188d4adb0529c9be0d69d5a67f40961 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 09:59:56 +0200 Subject: [PATCH 01/16] migrate tedious tests (skipped) --- .../suites/tracing/tedious/instrument.mjs | 9 +++ .../tedious/{scenario.js => scenario.mjs} | 13 +-- .../suites/tracing/tedious/test.ts | 80 ++++++++++--------- 3 files changed, 52 insertions(+), 50 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/tedious/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/tedious/{scenario.js => scenario.mjs} (74%) diff --git a/dev-packages/node-integration-tests/suites/tracing/tedious/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/tedious/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/tedious/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/tedious/scenario.js b/dev-packages/node-integration-tests/suites/tracing/tedious/scenario.mjs similarity index 74% rename from dev-packages/node-integration-tests/suites/tracing/tedious/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/tedious/scenario.mjs index 1a375cfb78e9..371b0038f1d9 100644 --- a/dev-packages/node-integration-tests/suites/tracing/tedious/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/tedious/scenario.mjs @@ -1,14 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const { Connection, Request } = require('tedious'); +import * as Sentry from '@sentry/node'; +import { Connection, Request } from 'tedious'; const config = { server: '127.0.0.1', diff --git a/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts b/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts index a8d45ad43877..fb9aa4a67fdd 100644 --- a/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts @@ -1,50 +1,52 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe.skip('tedious auto instrumentation', { timeout: 75_000 }, () => { afterAll(() => { cleanupChildProcesses(); }); - test('should auto-instrument `tedious` package', async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'SELECT GETDATE()', - data: expect.objectContaining({ - 'sentry.origin': 'auto.db.otel.tedious', - 'sentry.op': 'db', - 'db.name': 'master', - 'db.statement': 'SELECT GETDATE()', - 'db.system': 'mssql', - 'db.user': 'sa', - 'net.peer.name': '127.0.0.1', - 'net.peer.port': 1433, - }), - status: 'ok', + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + description: 'SELECT GETDATE()', + data: expect.objectContaining({ + 'sentry.origin': 'auto.db.otel.tedious', + 'sentry.op': 'db', + 'db.name': 'master', + 'db.statement': 'SELECT GETDATE()', + 'db.system': 'mssql', + 'db.user': 'sa', + 'net.peer.name': '127.0.0.1', + 'net.peer.port': 1433, }), - expect.objectContaining({ - description: 'SELECT 1 + 1 AS solution', - data: expect.objectContaining({ - 'sentry.origin': 'auto.db.otel.tedious', - 'sentry.op': 'db', - 'db.name': 'master', - 'db.statement': 'SELECT 1 + 1 AS solution', - 'db.system': 'mssql', - 'db.user': 'sa', - 'net.peer.name': '127.0.0.1', - 'net.peer.port': 1433, - }), - status: 'ok', + status: 'ok', + }), + expect.objectContaining({ + description: 'SELECT 1 + 1 AS solution', + data: expect.objectContaining({ + 'sentry.origin': 'auto.db.otel.tedious', + 'sentry.op': 'db', + 'db.name': 'master', + 'db.statement': 'SELECT 1 + 1 AS solution', + 'db.system': 'mssql', + 'db.user': 'sa', + 'net.peer.name': '127.0.0.1', + 'net.peer.port': 1433, }), - ]), - }; + status: 'ok', + }), + ]), + }; - await createRunner(__dirname, 'scenario.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('should auto-instrument `tedious` package', async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); }); }); From c86b222f408e7db71d0800cd34b729f3167eed08 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:00:55 +0200 Subject: [PATCH 02/16] migrate redis tests --- .../suites/tracing/redis/instrument.mjs | 9 ++ ...enario-ioredis.js => scenario-ioredis.mjs} | 13 +-- .../suites/tracing/redis/test.ts | 90 ++++++++++--------- 3 files changed, 57 insertions(+), 55 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/redis/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/redis/{scenario-ioredis.js => scenario-ioredis.mjs} (54%) diff --git a/dev-packages/node-integration-tests/suites/tracing/redis/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/redis/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/redis/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/redis/scenario-ioredis.js b/dev-packages/node-integration-tests/suites/tracing/redis/scenario-ioredis.mjs similarity index 54% rename from dev-packages/node-integration-tests/suites/tracing/redis/scenario-ioredis.js rename to dev-packages/node-integration-tests/suites/tracing/redis/scenario-ioredis.mjs index a3d92ee31624..c7b31c799f52 100644 --- a/dev-packages/node-integration-tests/suites/tracing/redis/scenario-ioredis.js +++ b/dev-packages/node-integration-tests/suites/tracing/redis/scenario-ioredis.mjs @@ -1,14 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const Redis = require('ioredis'); +import * as Sentry from '@sentry/node'; +import Redis from 'ioredis'; const redis = new Redis({ port: 6379 }); diff --git a/dev-packages/node-integration-tests/suites/tracing/redis/test.ts b/dev-packages/node-integration-tests/suites/tracing/redis/test.ts index 7add18746f3a..59a5b9ca929c 100644 --- a/dev-packages/node-integration-tests/suites/tracing/redis/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/redis/test.ts @@ -1,52 +1,54 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('redis auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); - test( - 'should auto-instrument `ioredis` package when using redis.set() and redis.get()', - { timeout: 75_000 }, - async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Span', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'set test-key [1 other arguments]', - op: 'db', - origin: 'auto.db.otel.redis', - data: expect.objectContaining({ - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.otel.redis', - 'db.system': 'redis', - 'net.peer.name': 'localhost', - 'net.peer.port': 6379, - 'db.statement': 'set test-key [1 other arguments]', - }), - }), - expect.objectContaining({ - description: 'get test-key', - op: 'db', - origin: 'auto.db.otel.redis', - data: expect.objectContaining({ - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.otel.redis', - 'db.system': 'redis', - 'net.peer.name': 'localhost', - 'net.peer.port': 6379, - 'db.statement': 'get test-key', - }), - }), - ]), - }; + const EXPECTED_TRANSACTION = { + transaction: 'Test Span', + spans: expect.arrayContaining([ + expect.objectContaining({ + description: 'set test-key [1 other arguments]', + op: 'db', + origin: 'auto.db.otel.redis', + data: expect.objectContaining({ + 'sentry.op': 'db', + 'sentry.origin': 'auto.db.otel.redis', + 'db.system': 'redis', + 'net.peer.name': 'localhost', + 'net.peer.port': 6379, + 'db.statement': 'set test-key [1 other arguments]', + }), + }), + expect.objectContaining({ + description: 'get test-key', + op: 'db', + origin: 'auto.db.otel.redis', + data: expect.objectContaining({ + 'sentry.op': 'db', + 'sentry.origin': 'auto.db.otel.redis', + 'db.system': 'redis', + 'net.peer.name': 'localhost', + 'net.peer.port': 6379, + 'db.statement': 'get test-key', + }), + }), + ]), + }; - await createRunner(__dirname, 'scenario-ioredis.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }, - ); + createEsmAndCjsTests(__dirname, 'scenario-ioredis.mjs', 'instrument.mjs', (createTestRunner, test) => { + test( + 'should auto-instrument `ioredis` package when using redis.set() and redis.get()', + { timeout: 75_000 }, + async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }, + ); + }); }); From d866f4196944dfe080ddf72f6b66585d129abd0b Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:02:36 +0200 Subject: [PATCH 03/16] migrate redis dc tests --- .../suites/tracing/redis-dc/instrument.mjs | 10 + ...enario-redis-5.js => scenario-redis-5.mjs} | 13 +- .../suites/tracing/redis-dc/test.ts | 188 +++++++++--------- 3 files changed, 107 insertions(+), 104 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/redis-dc/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/redis-dc/{scenario-redis-5.js => scenario-redis-5.mjs} (72%) diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-dc/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/redis-dc/instrument.mjs new file mode 100644 index 000000000000..db5276b8c536 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/redis-dc/instrument.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, + integrations: [Sentry.redisIntegration({ cachePrefixes: ['dc-cache:'] })], +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-dc/scenario-redis-5.js b/dev-packages/node-integration-tests/suites/tracing/redis-dc/scenario-redis-5.mjs similarity index 72% rename from dev-packages/node-integration-tests/suites/tracing/redis-dc/scenario-redis-5.js rename to dev-packages/node-integration-tests/suites/tracing/redis-dc/scenario-redis-5.mjs index ae92a6cbf2ce..c42fc5704ed5 100644 --- a/dev-packages/node-integration-tests/suites/tracing/redis-dc/scenario-redis-5.js +++ b/dev-packages/node-integration-tests/suites/tracing/redis-dc/scenario-redis-5.mjs @@ -1,20 +1,11 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, - integrations: [Sentry.redisIntegration({ cachePrefixes: ['dc-cache:'] })], -}); +import * as Sentry from '@sentry/node'; async function run() { // Yield a microtick so the DC subscriber (deferred via Promise.resolve().then) // is registered before node-redis eagerly creates its native TracingChannels on require(). await Promise.resolve(); - const { createClient } = require('redis-5'); + const { createClient } = await import('redis-5'); const redisClient = await createClient({ socket: { host: '127.0.0.1', port: 6379 } }).connect(); await Sentry.startSpan( diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-dc/test.ts b/dev-packages/node-integration-tests/suites/tracing/redis-dc/test.ts index 7b7c111f4d29..df8c26b23b63 100644 --- a/dev-packages/node-integration-tests/suites/tracing/redis-dc/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/redis-dc/test.ts @@ -1,110 +1,112 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('redis v5 diagnostics_channel auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); - test('should create spans for redis v5 commands via diagnostics_channel', { timeout: 60_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Span Redis 5 DC', - spans: expect.arrayContaining([ - expect.objectContaining({ - op: 'db.redis', - origin: 'auto.db.redis.diagnostic_channel', - data: expect.objectContaining({ - 'sentry.op': 'db.redis', - 'sentry.origin': 'auto.db.redis.diagnostic_channel', - 'db.system': 'redis', - 'db.statement': 'SET dc-test-key [1 other arguments]', - }), + const EXPECTED_TRANSACTION = { + transaction: 'Test Span Redis 5 DC', + spans: expect.arrayContaining([ + expect.objectContaining({ + op: 'db.redis', + origin: 'auto.db.redis.diagnostic_channel', + data: expect.objectContaining({ + 'sentry.op': 'db.redis', + 'sentry.origin': 'auto.db.redis.diagnostic_channel', + 'db.system': 'redis', + 'db.statement': 'SET dc-test-key [1 other arguments]', }), - // cache SET: span name updated to key by cacheResponseHook - expect.objectContaining({ - description: 'dc-cache:test-key', - op: 'cache.put', - origin: 'auto.db.redis.diagnostic_channel', - data: expect.objectContaining({ - 'sentry.origin': 'auto.db.redis.diagnostic_channel', - 'db.statement': 'SET dc-cache:test-key [1 other arguments]', - 'cache.key': ['dc-cache:test-key'], - 'cache.item_size': 2, - }), + }), + // cache SET: span name updated to key by cacheResponseHook + expect.objectContaining({ + description: 'dc-cache:test-key', + op: 'cache.put', + origin: 'auto.db.redis.diagnostic_channel', + data: expect.objectContaining({ + 'sentry.origin': 'auto.db.redis.diagnostic_channel', + 'db.statement': 'SET dc-cache:test-key [1 other arguments]', + 'cache.key': ['dc-cache:test-key'], + 'cache.item_size': 2, }), - // cache SET with EX option: redis v5 sends SET key value EX 10 as the command - expect.objectContaining({ - description: 'dc-cache:test-key-ex', - op: 'cache.put', - origin: 'auto.db.redis.diagnostic_channel', - data: expect.objectContaining({ - 'sentry.origin': 'auto.db.redis.diagnostic_channel', - 'db.statement': 'SET dc-cache:test-key-ex [3 other arguments]', - 'cache.key': ['dc-cache:test-key-ex'], - 'cache.item_size': 2, - }), + }), + // cache SET with EX option: redis v5 sends SET key value EX 10 as the command + expect.objectContaining({ + description: 'dc-cache:test-key-ex', + op: 'cache.put', + origin: 'auto.db.redis.diagnostic_channel', + data: expect.objectContaining({ + 'sentry.origin': 'auto.db.redis.diagnostic_channel', + 'db.statement': 'SET dc-cache:test-key-ex [3 other arguments]', + 'cache.key': ['dc-cache:test-key-ex'], + 'cache.item_size': 2, }), - expect.objectContaining({ - op: 'db.redis', - origin: 'auto.db.redis.diagnostic_channel', - data: expect.objectContaining({ - 'sentry.op': 'db.redis', - 'sentry.origin': 'auto.db.redis.diagnostic_channel', - 'db.system': 'redis', - 'db.statement': 'GET dc-test-key', - }), + }), + expect.objectContaining({ + op: 'db.redis', + origin: 'auto.db.redis.diagnostic_channel', + data: expect.objectContaining({ + 'sentry.op': 'db.redis', + 'sentry.origin': 'auto.db.redis.diagnostic_channel', + 'db.system': 'redis', + 'db.statement': 'GET dc-test-key', }), - // cache GET (hit) - expect.objectContaining({ - description: 'dc-cache:test-key', - op: 'cache.get', - origin: 'auto.db.redis.diagnostic_channel', - data: expect.objectContaining({ - 'sentry.origin': 'auto.db.redis.diagnostic_channel', - 'db.statement': 'GET dc-cache:test-key', - 'cache.hit': true, - 'cache.key': ['dc-cache:test-key'], - 'cache.item_size': 10, - }), + }), + // cache GET (hit) + expect.objectContaining({ + description: 'dc-cache:test-key', + op: 'cache.get', + origin: 'auto.db.redis.diagnostic_channel', + data: expect.objectContaining({ + 'sentry.origin': 'auto.db.redis.diagnostic_channel', + 'db.statement': 'GET dc-cache:test-key', + 'cache.hit': true, + 'cache.key': ['dc-cache:test-key'], + 'cache.item_size': 10, }), - // cache GET (miss) - expect.objectContaining({ - description: 'dc-cache:unavailable-data', - op: 'cache.get', - origin: 'auto.db.redis.diagnostic_channel', - data: expect.objectContaining({ - 'sentry.origin': 'auto.db.redis.diagnostic_channel', - 'db.statement': 'GET dc-cache:unavailable-data', - 'cache.hit': false, - 'cache.key': ['dc-cache:unavailable-data'], - }), + }), + // cache GET (miss) + expect.objectContaining({ + description: 'dc-cache:unavailable-data', + op: 'cache.get', + origin: 'auto.db.redis.diagnostic_channel', + data: expect.objectContaining({ + 'sentry.origin': 'auto.db.redis.diagnostic_channel', + 'db.statement': 'GET dc-cache:unavailable-data', + 'cache.hit': false, + 'cache.key': ['dc-cache:unavailable-data'], }), - // MGET: node-redis sanitizes args for diagnostics_channel (keys become '?'), - // so cache detection cannot match prefixes — remains a plain db.redis span. - expect.objectContaining({ - op: 'db.redis', - origin: 'auto.db.redis.diagnostic_channel', - data: expect.objectContaining({ - 'sentry.op': 'db.redis', - 'sentry.origin': 'auto.db.redis.diagnostic_channel', - 'db.system': 'redis', - 'db.statement': 'MGET [3 other arguments]', - }), + }), + // MGET: node-redis sanitizes args for diagnostics_channel (keys become '?'), + // so cache detection cannot match prefixes — remains a plain db.redis span. + expect.objectContaining({ + op: 'db.redis', + origin: 'auto.db.redis.diagnostic_channel', + data: expect.objectContaining({ + 'sentry.op': 'db.redis', + 'sentry.origin': 'auto.db.redis.diagnostic_channel', + 'db.system': 'redis', + 'db.statement': 'MGET [3 other arguments]', }), - ]), - }; + }), + ]), + }; - // node-redis emits a node-redis:connect DC event for the initial connection. - // That fires before startSpan so it arrives as the first envelope. - const EXPECTED_CONNECT = { - transaction: 'redis-connect', - }; + // node-redis emits a node-redis:connect DC event for the initial connection. + // That fires before startSpan so it arrives as the first envelope. + const EXPECTED_CONNECT = { + transaction: 'redis-connect', + }; - await createRunner(__dirname, 'scenario-redis-5.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_CONNECT }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario-redis-5.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('should create spans for redis v5 commands via diagnostics_channel', { timeout: 60_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_CONNECT }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); }); }); From 5f0dbe5f520a7f96c704ee78a37458296867271a Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:03:20 +0200 Subject: [PATCH 04/16] migrate redis cache tests --- .../redis-cache/instrument-ioredis.mjs | 10 ++++ .../redis-cache/instrument-redis-4.mjs | 10 ++++ ...enario-ioredis.js => scenario-ioredis.mjs} | 14 +---- ...enario-redis-4.js => scenario-redis-4.mjs} | 14 +---- .../suites/tracing/redis-cache/test.ts | 54 +++++++++++-------- 5 files changed, 57 insertions(+), 45 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-ioredis.mjs create mode 100644 dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-redis-4.mjs rename dev-packages/node-integration-tests/suites/tracing/redis-cache/{scenario-ioredis.js => scenario-ioredis.mjs} (67%) rename dev-packages/node-integration-tests/suites/tracing/redis-cache/{scenario-redis-4.js => scenario-redis-4.mjs} (69%) diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-ioredis.mjs b/dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-ioredis.mjs new file mode 100644 index 000000000000..4a6ca8a42ec4 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-ioredis.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, + integrations: [Sentry.redisIntegration({ cachePrefixes: ['ioredis-cache:'] })], +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-redis-4.mjs b/dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-redis-4.mjs new file mode 100644 index 000000000000..df9d0ca876df --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/redis-cache/instrument-redis-4.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, + integrations: [Sentry.redisIntegration({ cachePrefixes: ['redis-cache:'] })], +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-ioredis.js b/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-ioredis.mjs similarity index 67% rename from dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-ioredis.js rename to dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-ioredis.mjs index 4d6b87978d83..79ef8de8c9b5 100644 --- a/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-ioredis.js +++ b/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-ioredis.mjs @@ -1,15 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, - integrations: [Sentry.redisIntegration({ cachePrefixes: ['ioredis-cache:'] })], -}); - -const Redis = require('ioredis'); +import * as Sentry from '@sentry/node'; +import Redis from 'ioredis'; const redis = new Redis({ port: 6379 }); diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-redis-4.js b/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-redis-4.mjs similarity index 69% rename from dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-redis-4.js rename to dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-redis-4.mjs index 8e1a78023638..4e1c69d8e4f8 100644 --- a/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-redis-4.js +++ b/dev-packages/node-integration-tests/suites/tracing/redis-cache/scenario-redis-4.mjs @@ -1,15 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, - integrations: [Sentry.redisIntegration({ cachePrefixes: ['redis-cache:'] })], -}); - -const { createClient } = require('redis-4'); +import * as Sentry from '@sentry/node'; +import { createClient } from 'redis-4'; async function run() { const redisClient = await createClient().connect(); diff --git a/dev-packages/node-integration-tests/suites/tracing/redis-cache/test.ts b/dev-packages/node-integration-tests/suites/tracing/redis-cache/test.ts index c27957c37b06..a123c81e9796 100644 --- a/dev-packages/node-integration-tests/suites/tracing/redis-cache/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/redis-cache/test.ts @@ -1,12 +1,12 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('redis cache auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); - test('should not add cache spans when key is not prefixed', { timeout: 60_000 }, async () => { + describe('ioredis non-cache keys', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Span', spans: expect.arrayContaining([ @@ -37,14 +37,18 @@ describe('redis cache auto instrumentation', () => { ]), }; - await createRunner(__dirname, 'scenario-ioredis.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario-ioredis.mjs', 'instrument-ioredis.mjs', (createTestRunner, test) => { + test('should not add cache spans when key is not prefixed', { timeout: 60_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); - test('should create cache spans for prefixed keys (ioredis)', { timeout: 60_000 }, async () => { + describe('ioredis cache keys', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Span', spans: expect.arrayContaining([ @@ -136,14 +140,18 @@ describe('redis cache auto instrumentation', () => { ]), }; - await createRunner(__dirname, 'scenario-ioredis.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario-ioredis.mjs', 'instrument-ioredis.mjs', (createTestRunner, test) => { + test('should create cache spans for prefixed keys (ioredis)', { timeout: 60_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); - test('should create cache spans for prefixed keys (redis-4)', async () => { + describe('redis-4 cache keys', () => { const EXPECTED_REDIS_CONNECT = { transaction: 'redis-connect', }; @@ -227,11 +235,15 @@ describe('redis cache auto instrumentation', () => { ]), }; - await createRunner(__dirname, 'scenario-redis-4.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_REDIS_CONNECT }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario-redis-4.mjs', 'instrument-redis-4.mjs', (createTestRunner, test) => { + test('should create cache spans for prefixed keys (redis-4)', async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_REDIS_CONNECT }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); }); From 89fdc4915fe79c499bce773b4f386c3066a10fc0 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:04:03 +0200 Subject: [PATCH 05/16] migrate mysql tests --- .../suites/tracing/mysql/instrument.mjs | 9 ++ ...ithConnect.js => scenario-withConnect.mjs} | 13 +- ...llback.js => scenario-withoutCallback.mjs} | 13 +- ...Connect.js => scenario-withoutConnect.mjs} | 13 +- .../suites/tracing/mysql/test.ts | 153 +++++++----------- 5 files changed, 76 insertions(+), 125 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/mysql/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/mysql/{scenario-withConnect.js => scenario-withConnect.mjs} (60%) rename dev-packages/node-integration-tests/suites/tracing/mysql/{scenario-withoutCallback.js => scenario-withoutCallback.mjs} (66%) rename dev-packages/node-integration-tests/suites/tracing/mysql/{scenario-withoutConnect.js => scenario-withoutConnect.mjs} (56%) diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/mysql/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/mysql/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withConnect.js b/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withConnect.mjs similarity index 60% rename from dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withConnect.js rename to dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withConnect.mjs index dfe00fffaf08..235c120be91a 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withConnect.js +++ b/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withConnect.mjs @@ -1,14 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const mysql = require('mysql'); +import * as Sentry from '@sentry/node'; +import mysql from 'mysql'; const connection = mysql.createConnection({ user: 'root', diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutCallback.js b/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutCallback.mjs similarity index 66% rename from dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutCallback.js rename to dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutCallback.mjs index 5065484d310e..4979832c9006 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutCallback.js +++ b/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutCallback.mjs @@ -1,14 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const mysql = require('mysql'); +import * as Sentry from '@sentry/node'; +import mysql from 'mysql'; const connection = mysql.createConnection({ user: 'root', diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutConnect.js b/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutConnect.mjs similarity index 56% rename from dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutConnect.js rename to dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutConnect.mjs index 653c50324cc7..d2d5254d7bd6 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutConnect.js +++ b/dev-packages/node-integration-tests/suites/tracing/mysql/scenario-withoutConnect.mjs @@ -1,14 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const mysql = require('mysql'); +import * as Sentry from '@sentry/node'; +import mysql from 'mysql'; const connection = mysql.createConnection({ user: 'root', diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql/test.ts b/dev-packages/node-integration-tests/suites/tracing/mysql/test.ts index adb35f1c0025..2cb58e662a6b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mysql/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/mysql/test.ts @@ -1,107 +1,76 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('mysql auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); - test('should auto-instrument `mysql` package when using connection.connect()', async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'SELECT 1 + 1 AS solution', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + description: 'SELECT 1 + 1 AS solution', + op: 'db', + data: expect.objectContaining({ + 'db.system': 'mysql', + 'net.peer.name': 'localhost', + 'net.peer.port': 3306, + 'db.user': 'root', }), - expect.objectContaining({ - description: 'SELECT NOW()', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), + }), + expect.objectContaining({ + description: 'SELECT NOW()', + op: 'db', + data: expect.objectContaining({ + 'db.system': 'mysql', + 'net.peer.name': 'localhost', + 'net.peer.port': 3306, + 'db.user': 'root', }), - ]), - }; + }), + ]), + }; - await createRunner(__dirname, 'scenario-withConnect.js') - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + describe('with connection.connect()', () => { + createEsmAndCjsTests( + __dirname, + 'scenario-withConnect.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should auto-instrument `mysql` package when using connection.connect()', async () => { + await createTestRunner().expect({ transaction: EXPECTED_TRANSACTION }).start().completed(); + }); + }, + { failsOnEsm: true }, + ); }); - test('should auto-instrument `mysql` package when using query without callback', async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'SELECT 1 + 1 AS solution', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), - }), - expect.objectContaining({ - description: 'SELECT NOW()', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), - }), - ]), - }; - - await createRunner(__dirname, 'scenario-withoutCallback.js') - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + describe('query without callback', () => { + createEsmAndCjsTests( + __dirname, + 'scenario-withoutCallback.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should auto-instrument `mysql` package when using query without callback', async () => { + await createTestRunner().expect({ transaction: EXPECTED_TRANSACTION }).start().completed(); + }); + }, + { failsOnEsm: true }, + ); }); - test('should auto-instrument `mysql` package without connection.connect()', async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'SELECT 1 + 1 AS solution', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), - }), - expect.objectContaining({ - description: 'SELECT NOW()', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), - }), - ]), - }; - - await createRunner(__dirname, 'scenario-withoutConnect.js') - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + describe('without connection.connect()', () => { + createEsmAndCjsTests( + __dirname, + 'scenario-withoutConnect.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should auto-instrument `mysql` package without connection.connect()', async () => { + await createTestRunner().expect({ transaction: EXPECTED_TRANSACTION }).start().completed(); + }); + }, + { failsOnEsm: true }, + ); }); }); From 22b193ab035087820e8c523e595cd131412d046c Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:04:25 +0200 Subject: [PATCH 06/16] migrate mysql2 tests --- .../suites/tracing/mysql2/instrument.mjs | 9 +++ .../mysql2/{scenario.js => scenario.mjs} | 13 +--- .../suites/tracing/mysql2/test.ts | 64 ++++++++++--------- 3 files changed, 44 insertions(+), 42 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/mysql2/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/mysql2/{scenario.js => scenario.mjs} (57%) diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql2/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/mysql2/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/mysql2/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql2/scenario.js b/dev-packages/node-integration-tests/suites/tracing/mysql2/scenario.mjs similarity index 57% rename from dev-packages/node-integration-tests/suites/tracing/mysql2/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/mysql2/scenario.mjs index f0e7e0486d5f..9b6d0279e58d 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mysql2/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/mysql2/scenario.mjs @@ -1,14 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const mysql = require('mysql2/promise'); +import * as Sentry from '@sentry/node'; +import mysql from 'mysql2/promise'; mysql .createConnection({ diff --git a/dev-packages/node-integration-tests/suites/tracing/mysql2/test.ts b/dev-packages/node-integration-tests/suites/tracing/mysql2/test.ts index 4c3078b922f7..fef931399723 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mysql2/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/mysql2/test.ts @@ -1,42 +1,44 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('mysql2 auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); - test('should auto-instrument `mysql` package without connection.connect()', { timeout: 75_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'SELECT 1 + 1 AS solution', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + description: 'SELECT 1 + 1 AS solution', + op: 'db', + data: expect.objectContaining({ + 'db.system': 'mysql', + 'net.peer.name': 'localhost', + 'net.peer.port': 3306, + 'db.user': 'root', }), - expect.objectContaining({ - description: 'SELECT NOW()', - op: 'db', - data: expect.objectContaining({ - 'db.system': 'mysql', - 'net.peer.name': 'localhost', - 'net.peer.port': 3306, - 'db.user': 'root', - }), + }), + expect.objectContaining({ + description: 'SELECT NOW()', + op: 'db', + data: expect.objectContaining({ + 'db.system': 'mysql', + 'net.peer.name': 'localhost', + 'net.peer.port': 3306, + 'db.user': 'root', }), - ]), - }; + }), + ]), + }; - await createRunner(__dirname, 'scenario.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('should auto-instrument `mysql` package without connection.connect()', { timeout: 75_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); }); }); From 6200f363eec938034a8160409b6ed791fb92a10c Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:04:49 +0200 Subject: [PATCH 07/16] migrate mongoose tests --- .../suites/tracing/mongoose/instrument.mjs | 9 +++++++++ .../tracing/mongoose/{scenario.js => scenario.mjs} | 14 ++------------ .../suites/tracing/mongoose/test.ts | 10 ++++++---- 3 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/mongoose/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/mongoose/{scenario.js => scenario.mjs} (62%) diff --git a/dev-packages/node-integration-tests/suites/tracing/mongoose/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/mongoose/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/mongoose/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/mongoose/scenario.js b/dev-packages/node-integration-tests/suites/tracing/mongoose/scenario.mjs similarity index 62% rename from dev-packages/node-integration-tests/suites/tracing/mongoose/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/mongoose/scenario.mjs index 8d1d87de0a2f..434c1db10e7d 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mongoose/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/mongoose/scenario.mjs @@ -1,15 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -// Must be required after Sentry is initialized -const mongoose = require('mongoose'); +import * as Sentry from '@sentry/node'; +import mongoose from 'mongoose'; async function run() { await mongoose.connect(process.env.MONGO_URL || ''); diff --git a/dev-packages/node-integration-tests/suites/tracing/mongoose/test.ts b/dev-packages/node-integration-tests/suites/tracing/mongoose/test.ts index 5c961a2af19e..14b5bc777098 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mongoose/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/mongoose/test.ts @@ -1,6 +1,6 @@ import { MongoMemoryServer } from 'mongodb-memory-server-global'; -import { afterAll, beforeAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, beforeAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('Mongoose experimental Test', () => { let mongoServer: MongoMemoryServer; @@ -45,7 +45,9 @@ describe('Mongoose experimental Test', () => { ]), }; - test('CJS - should auto-instrument `mongoose` package.', async () => { - await createRunner(__dirname, 'scenario.js').expect({ transaction: EXPECTED_TRANSACTION }).start().completed(); + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('should auto-instrument `mongoose` package.', async () => { + await createTestRunner().expect({ transaction: EXPECTED_TRANSACTION }).start().completed(); + }); }); }); From ab7f9e028790d884f0e97283af41ba1cc6da897e Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:05:10 +0200 Subject: [PATCH 08/16] migrate mongodb tests --- .../suites/tracing/mongodb/instrument.mjs | 9 ++++ .../mongodb/{scenario.js => scenario.mjs} | 14 ++---- .../suites/tracing/mongodb/test.ts | 48 ++++++++++--------- 3 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/mongodb/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/mongodb/{scenario.js => scenario.mjs} (69%) diff --git a/dev-packages/node-integration-tests/suites/tracing/mongodb/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/mongodb/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/mongodb/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/mongodb/scenario.js b/dev-packages/node-integration-tests/suites/tracing/mongodb/scenario.mjs similarity index 69% rename from dev-packages/node-integration-tests/suites/tracing/mongodb/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/mongodb/scenario.mjs index d65c1c3c306f..e8d0eef31739 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mongodb/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/mongodb/scenario.mjs @@ -1,15 +1,7 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); +import * as Sentry from '@sentry/node'; +import mongodb from 'mongodb'; -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -// Must be required after Sentry is initialized -const { MongoClient } = require('mongodb'); +const { MongoClient } = mongodb; const client = new MongoClient(process.env.MONGO_URL || '', { useUnifiedTopology: true, diff --git a/dev-packages/node-integration-tests/suites/tracing/mongodb/test.ts b/dev-packages/node-integration-tests/suites/tracing/mongodb/test.ts index 13fb7a12fa85..f3c82988b679 100644 --- a/dev-packages/node-integration-tests/suites/tracing/mongodb/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/mongodb/test.ts @@ -1,8 +1,8 @@ import type { TransactionEvent } from '@sentry/core'; import { MongoMemoryServer } from 'mongodb-memory-server-global'; -import { afterAll, beforeAll, describe, expect, test } from 'vitest'; +import { afterAll, beforeAll, describe, expect } from 'vitest'; import { assertSentryTransaction } from '../../../utils/assertions'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('MongoDB experimental Test', () => { let mongoServer: MongoMemoryServer; @@ -115,29 +115,31 @@ describe('MongoDB experimental Test', () => { origin: 'auto.db.otel.mongo', }); - test('CJS - should auto-instrument `mongodb` package.', async () => { - await createRunner(__dirname, 'scenario.js') - .expect({ - transaction: (txn: TransactionEvent) => { - assertSentryTransaction(txn, { transaction: 'Test Transaction' }); - const spans = txn.spans || []; - expect(spans).toHaveLength(8); + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('should auto-instrument `mongodb` package.', async () => { + await createTestRunner() + .expect({ + transaction: (txn: TransactionEvent) => { + assertSentryTransaction(txn, { transaction: 'Test Transaction' }); + const spans = txn.spans || []; + expect(spans).toHaveLength(8); - expect(spans).toContainEqual(SPAN_FIND_MATCHER); - expect(spans).toContainEqual(SPAN_INSERT_MATCHER); - expect(spans).toContainEqual(SPAN_ISMASTER_MATCHER); - expect(spans).toContainEqual(SPAN_UPDATE_MATCHER); - expect(spans).toContainEqual(SPAN_ENDSESSIONS_MATCHER); + expect(spans).toContainEqual(SPAN_FIND_MATCHER); + expect(spans).toContainEqual(SPAN_INSERT_MATCHER); + expect(spans).toContainEqual(SPAN_ISMASTER_MATCHER); + expect(spans).toContainEqual(SPAN_UPDATE_MATCHER); + expect(spans).toContainEqual(SPAN_ENDSESSIONS_MATCHER); - // Ensure duplicate spans are correctly there - const findSpans = spans.filter(span => span.data['db.operation'] === 'find'); - expect(findSpans).toHaveLength(3); + // Ensure duplicate spans are correctly there + const findSpans = spans.filter(span => span.data['db.operation'] === 'find'); + expect(findSpans).toHaveLength(3); - const isMasterSpans = spans.filter(span => span.data['db.operation'] === 'isMaster'); - expect(isMasterSpans).toHaveLength(2); - }, - }) - .start() - .completed(); + const isMasterSpans = spans.filter(span => span.data['db.operation'] === 'isMaster'); + expect(isMasterSpans).toHaveLength(2); + }, + }) + .start() + .completed(); + }); }); }); From 38d211537887cefa5fe5f4e2866d4c698bee56fd Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:05:33 +0200 Subject: [PATCH 09/16] migrate lrumemoizer tests --- .../tracing/lru-memoizer/instrument.mjs | 9 +++ .../{scenario.js => scenario.mjs} | 13 +---- .../suites/tracing/lru-memoizer/test.ts | 56 +++++++++++-------- 3 files changed, 43 insertions(+), 35 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/lru-memoizer/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/lru-memoizer/{scenario.js => scenario.mjs} (76%) diff --git a/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/scenario.js b/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/scenario.mjs similarity index 76% rename from dev-packages/node-integration-tests/suites/tracing/lru-memoizer/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/lru-memoizer/scenario.mjs index 74a7e8cfa4ef..7de93b7aa901 100644 --- a/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/scenario.mjs @@ -1,18 +1,9 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); +import * as Sentry from '@sentry/node'; +import memoizer from 'lru-memoizer'; const run = async () => { // Test ported from the OTEL implementation: // https://github.com/open-telemetry/opentelemetry-js-contrib/blob/0d6ebded313bb75b5a0e7a6422206c922daf3943/plugins/node/instrumentation-lru-memoizer/test/index.test.ts#L28 - const memoizer = require('lru-memoizer'); - let memoizerLoadCallback; const memoizedFoo = memoizer({ load: (_param, callback) => { diff --git a/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/test.ts b/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/test.ts index 7caccfc97144..9228b1228cc1 100644 --- a/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/lru-memoizer/test.ts @@ -1,31 +1,39 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('lru-memoizer', () => { afterAll(() => { cleanupChildProcesses(); }); - test('keeps outer context inside the memoized inner functions', async () => { - await createRunner(__dirname, 'scenario.js') - // We expect only one transaction and nothing else. - // A failed test will result in an error event being sent to Sentry. - // Which will fail this suite. - .expect({ - transaction: { - transaction: '', - contexts: { - trace: expect.objectContaining({ - op: 'run', - data: expect.objectContaining({ - 'sentry.op': 'run', - 'sentry.origin': 'manual', - }), - }), - }, - }, - }) - .start() - .completed(); - }); + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('keeps outer context inside the memoized inner functions', async () => { + await createTestRunner() + // We expect only one transaction and nothing else. + // A failed test will result in an error event being sent to Sentry. + // Which will fail this suite. + .expect({ + transaction: { + transaction: '', + contexts: { + trace: expect.objectContaining({ + op: 'run', + data: expect.objectContaining({ + 'sentry.op': 'run', + 'sentry.origin': 'manual', + }), + }), + }, + }, + }) + .start() + .completed(); + }); + }, + { failsOnEsm: true }, + ); }); From 42d3e6591405a4eb0fa3daaea50cf4a28e771494 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:07:12 +0200 Subject: [PATCH 10/16] migrate apollo-server tests --- .../{apollo-server.js => apollo-server.mjs} | 10 +- .../tracing/apollo-graphql/instrument.mjs | 9 ++ .../{scenario-error.js => scenario-error.mjs} | 15 +-- ...ario-mutation.js => scenario-mutation.mjs} | 15 +-- .../{scenario-query.js => scenario-query.mjs} | 13 +- .../suites/tracing/apollo-graphql/test.ts | 74 ++++++++--- .../instrument.mjs | 10 ++ .../scenario-invalid-root-span.js | 30 ----- .../scenario-invalid-root-span.mjs | 22 ++++ ... => scenario-multiple-operations-many.mjs} | 16 +-- ...ns.js => scenario-multiple-operations.mjs} | 16 +-- ...ario-mutation.js => scenario-mutation.mjs} | 18 +-- ...name.js => scenario-no-operation-name.mjs} | 16 +-- .../{scenario-query.js => scenario-query.mjs} | 16 +-- .../useOperationNameForRootSpan/test.ts | 124 ++++++++++++------ 15 files changed, 218 insertions(+), 186 deletions(-) rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/{apollo-server.js => apollo-server.mjs} (79%) create mode 100644 dev-packages/node-integration-tests/suites/tracing/apollo-graphql/instrument.mjs rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/{scenario-error.js => scenario-error.mjs} (64%) rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/{scenario-mutation.js => scenario-mutation.mjs} (62%) rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/{scenario-query.js => scenario-query.mjs} (58%) create mode 100644 dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/instrument.mjs delete mode 100644 dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.js create mode 100644 dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.mjs rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/{scenario-multiple-operations-many.js => scenario-multiple-operations-many.mjs} (56%) rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/{scenario-multiple-operations.js => scenario-multiple-operations.mjs} (57%) rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/{scenario-mutation.js => scenario-mutation.mjs} (57%) rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/{scenario-no-operation-name.js => scenario-no-operation-name.mjs} (53%) rename dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/{scenario-query.js => scenario-query.mjs} (53%) diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/apollo-server.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/apollo-server.mjs similarity index 79% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/apollo-server.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/apollo-server.mjs index 30980683a221..8bae5b820634 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/apollo-server.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/apollo-server.mjs @@ -1,8 +1,8 @@ -const { ApolloServer } = require('@apollo/server'); -const gql = require('graphql-tag'); -const Sentry = require('@sentry/node'); +import { ApolloServer } from '@apollo/server'; +import * as Sentry from '@sentry/node'; +import gql from 'graphql-tag'; -module.exports = () => { +export function createApolloServer() { return Sentry.startSpan({ name: 'Test Server Start' }, () => { return new ApolloServer({ typeDefs: gql` @@ -32,4 +32,4 @@ module.exports = () => { introspection: false, }); }); -}; +} diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/instrument.mjs new file mode 100644 index 000000000000..46a27dd03b74 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/instrument.mjs @@ -0,0 +1,9 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-error.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-error.mjs similarity index 64% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-error.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-error.mjs index 00a02fc6faf0..d6345f7d45e0 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-error.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-error.mjs @@ -1,16 +1,9 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); +import * as Sentry from '@sentry/node'; +import gql from 'graphql-tag'; async function run() { - const gql = require('graphql-tag'); - const server = require('./apollo-server')(); + const { createApolloServer } = await import('./apollo-server.mjs'); + const server = createApolloServer(); await Sentry.startSpan( { diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-mutation.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-mutation.mjs similarity index 62% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-mutation.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-mutation.mjs index b67877f23a43..27f9facba0e2 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-mutation.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-mutation.mjs @@ -1,16 +1,9 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); +import * as Sentry from '@sentry/node'; +import gql from 'graphql-tag'; async function run() { - const gql = require('graphql-tag'); - const server = require('./apollo-server')(); + const { createApolloServer } = await import('./apollo-server.mjs'); + const server = createApolloServer(); await Sentry.startSpan( { diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-query.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-query.mjs similarity index 58% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-query.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-query.mjs index 5388e28a19df..ae1f754a8fc9 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-query.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-query.mjs @@ -1,15 +1,8 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); +import * as Sentry from '@sentry/node'; async function run() { - const server = require('./apollo-server')(); + const { createApolloServer } = await import('./apollo-server.mjs'); + const server = createApolloServer(); await Sentry.startSpan( { diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/test.ts b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/test.ts index 106fc299a783..65acb67a94ac 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/test.ts @@ -1,5 +1,5 @@ -import { describe, expect, test } from 'vitest'; -import { createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; // Server start transaction (Apollo Server v5 no longer runs introspection query on start) const EXPECTED_START_SERVER_TRANSACTION = { @@ -7,7 +7,11 @@ const EXPECTED_START_SERVER_TRANSACTION = { }; describe('GraphQL/Apollo Tests', () => { - test('should instrument GraphQL queries used from Apollo Server.', async () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + describe('query', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction (query)', spans: expect.arrayContaining([ @@ -24,14 +28,24 @@ describe('GraphQL/Apollo Tests', () => { ]), }; - await createRunner(__dirname, 'scenario-query.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-query.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should instrument GraphQL queries used from Apollo Server.', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + { copyPaths: ['apollo-server.mjs'] }, + ); }); - test('should instrument GraphQL mutations used from Apollo Server.', async () => { + describe('mutation', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction (mutation Mutation)', spans: expect.arrayContaining([ @@ -49,14 +63,24 @@ describe('GraphQL/Apollo Tests', () => { ]), }; - await createRunner(__dirname, 'scenario-mutation.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-mutation.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should instrument GraphQL mutations used from Apollo Server.', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + { copyPaths: ['apollo-server.mjs'] }, + ); }); - test('should handle GraphQL errors.', async () => { + describe('error', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction (mutation Mutation)', spans: expect.arrayContaining([ @@ -74,10 +98,20 @@ describe('GraphQL/Apollo Tests', () => { ]), }; - await createRunner(__dirname, 'scenario-error.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-error.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should handle GraphQL errors.', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + { copyPaths: ['apollo-server.mjs'] }, + ); }); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/instrument.mjs b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/instrument.mjs new file mode 100644 index 000000000000..4f8eddd456c8 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/instrument.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })], + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.js deleted file mode 100644 index 9bc92c81a0cb..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.js +++ /dev/null @@ -1,30 +0,0 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); - -const client = Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })], - transport: loggingTransport, -}); - -const tracer = client.tracer; - -async function run() { - const server = require('../apollo-server')(); - - await tracer.startActiveSpan('test span name', async span => { - // Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation - await server.executeOperation({ - query: 'query GetHello {hello}', - }); - - setTimeout(() => { - span.end(); - server.stop(); - }, 500); - }); -} - -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.mjs b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.mjs new file mode 100644 index 000000000000..08402aadda43 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-invalid-root-span.mjs @@ -0,0 +1,22 @@ +import * as Sentry from '@sentry/node'; + +const tracer = Sentry.getClient().tracer; + +async function run() { + const { createApolloServer } = await import('../../apollo-server.mjs'); + const server = createApolloServer(); + + await tracer.startActiveSpan('test span name', async span => { + // Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation + await server.executeOperation({ + query: 'query GetHello {hello}', + }); + + setTimeout(() => { + span.end(); + server.stop(); + }, 500); + }); +} + +run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations-many.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations-many.mjs similarity index 56% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations-many.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations-many.mjs index ec321ef548c0..f69099bd19b1 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations-many.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations-many.mjs @@ -1,18 +1,10 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +import * as Sentry from '@sentry/node'; -const client = Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })], - transport: loggingTransport, -}); - -const tracer = client.tracer; +const tracer = Sentry.getClient().tracer; async function run() { - const server = require('../apollo-server')(); + const { createApolloServer } = await import('../../apollo-server.mjs'); + const server = createApolloServer(); await tracer.startActiveSpan( 'test span name', diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations.mjs similarity index 57% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations.mjs index bde04db9fc06..99b4cce96828 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-multiple-operations.mjs @@ -1,18 +1,10 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +import * as Sentry from '@sentry/node'; -const client = Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })], - transport: loggingTransport, -}); - -const tracer = client.tracer; +const tracer = Sentry.getClient().tracer; async function run() { - const server = require('../apollo-server')(); + const { createApolloServer } = await import('../../apollo-server.mjs'); + const server = createApolloServer(); await tracer.startActiveSpan( 'test span name', diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-mutation.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-mutation.mjs similarity index 57% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-mutation.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-mutation.mjs index ebc99c3fff08..3779e8e73094 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-mutation.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-mutation.mjs @@ -1,19 +1,11 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +import * as Sentry from '@sentry/node'; +import gql from 'graphql-tag'; -const client = Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })], - transport: loggingTransport, -}); - -const tracer = client.tracer; +const tracer = Sentry.getClient().tracer; async function run() { - const gql = require('graphql-tag'); - const server = require('../apollo-server')(); + const { createApolloServer } = await import('../../apollo-server.mjs'); + const server = createApolloServer(); await tracer.startActiveSpan( 'test span name', diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-no-operation-name.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-no-operation-name.mjs similarity index 53% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-no-operation-name.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-no-operation-name.mjs index 2b93a8b74916..02afc51d5034 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-no-operation-name.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-no-operation-name.mjs @@ -1,18 +1,10 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +import * as Sentry from '@sentry/node'; -const client = Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })], - transport: loggingTransport, -}); - -const tracer = client.tracer; +const tracer = Sentry.getClient().tracer; async function run() { - const server = require('../apollo-server')(); + const { createApolloServer } = await import('../../apollo-server.mjs'); + const server = createApolloServer(); await tracer.startActiveSpan( 'test span name', diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-query.js b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-query.mjs similarity index 53% rename from dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-query.js rename to dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-query.mjs index d269dfe77a91..ee3f579ec26e 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-query.js +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/scenario-query.mjs @@ -1,18 +1,10 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +import * as Sentry from '@sentry/node'; -const client = Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })], - transport: loggingTransport, -}); - -const tracer = client.tracer; +const tracer = Sentry.getClient().tracer; async function run() { - const server = require('../apollo-server')(); + const { createApolloServer } = await import('../../apollo-server.mjs'); + const server = createApolloServer(); await tracer.startActiveSpan( 'test span name', diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts index f38d94ddfd72..66d34a1fa5a2 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts @@ -1,5 +1,5 @@ -import { describe, expect, test } from 'vitest'; -import { createRunner } from '../../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../../utils/runner'; // Server start transaction (Apollo Server v5 no longer runs introspection query on start) const EXPECTED_START_SERVER_TRANSACTION = { @@ -7,7 +7,11 @@ const EXPECTED_START_SERVER_TRANSACTION = { }; describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { - test('useOperationNameForRootSpan works with single query operation', async () => { + afterAll(() => { + cleanupChildProcesses(); + }); + + describe('single query operation', () => { const EXPECTED_TRANSACTION = { transaction: 'GET /test-graphql (query GetHello)', spans: expect.arrayContaining([ @@ -25,14 +29,18 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - await createRunner(__dirname, 'scenario-query.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario-query.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('useOperationNameForRootSpan works with single query operation', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); - test('useOperationNameForRootSpan works with single mutation operation', async () => { + describe('single mutation operation', () => { const EXPECTED_TRANSACTION = { transaction: 'GET /test-graphql (mutation TestMutation)', spans: expect.arrayContaining([ @@ -52,14 +60,18 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - await createRunner(__dirname, 'scenario-mutation.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario-mutation.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('useOperationNameForRootSpan works with single mutation operation', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); - test('useOperationNameForRootSpan ignores an invalid root span', async () => { + describe('invalid root span', () => { const EXPECTED_TRANSACTION = { transaction: 'test span name (query GetHello)', spans: expect.arrayContaining([ @@ -77,14 +89,23 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - await createRunner(__dirname, 'scenario-invalid-root-span.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-invalid-root-span.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('useOperationNameForRootSpan ignores an invalid root span', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + ); }); - test('useOperationNameForRootSpan works with single query operation without name', async () => { + describe('query without name', () => { const EXPECTED_TRANSACTION = { transaction: 'GET /test-graphql (query)', spans: expect.arrayContaining([ @@ -101,14 +122,23 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - await createRunner(__dirname, 'scenario-no-operation-name.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-no-operation-name.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('useOperationNameForRootSpan works with single query operation without name', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + ); }); - test('useOperationNameForRootSpan works with multiple query operations', async () => { + describe('multiple operations', () => { const EXPECTED_TRANSACTION = { transaction: 'GET /test-graphql (query GetHello, query GetWorld)', spans: expect.arrayContaining([ @@ -137,23 +167,41 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - await createRunner(__dirname, 'scenario-multiple-operations.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-multiple-operations.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('useOperationNameForRootSpan works with multiple query operations', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + ); }); - test('useOperationNameForRootSpan works with more than 5 query operations', async () => { + describe('many operations', () => { const EXPECTED_TRANSACTION = { transaction: 'GET /test-graphql (query GetHello1, query GetHello2, query GetHello3, query GetHello4, query GetHello5, +4)', }; - await createRunner(__dirname, 'scenario-multiple-operations-many.js') - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-multiple-operations-many.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('useOperationNameForRootSpan works with more than 5 query operations', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + ); }); }); From 8fe83a28a595be7b9e8d342dae1b2a90c3a5d732 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:08:39 +0200 Subject: [PATCH 11/16] migrate postgres tests --- .../postgres/instrument-ignoreConnect.mjs | 10 + .../instrument.mjs} | 4 +- .../postgres/scenario-ignoreConnect.js | 43 ---- ...scenario-native.js => scenario-native.mjs} | 14 +- .../postgres/{scenario.js => scenario.mjs} | 13 +- .../suites/tracing/postgres/test.ts | 219 ++++++++++-------- 6 files changed, 134 insertions(+), 169 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/postgres/instrument-ignoreConnect.mjs rename dev-packages/node-integration-tests/suites/tracing/{postgresjs/instrument.cjs => postgres/instrument.mjs} (54%) delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgres/scenario-ignoreConnect.js rename dev-packages/node-integration-tests/suites/tracing/postgres/{scenario-native.js => scenario-native.mjs} (75%) rename dev-packages/node-integration-tests/suites/tracing/postgres/{scenario.js => scenario.mjs} (74%) diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres/instrument-ignoreConnect.mjs b/dev-packages/node-integration-tests/suites/tracing/postgres/instrument-ignoreConnect.mjs new file mode 100644 index 000000000000..cd9240108020 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/instrument-ignoreConnect.mjs @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + integrations: [Sentry.postgresIntegration({ ignoreConnectSpans: true })], + transport: loggingTransport, +}); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument.cjs b/dev-packages/node-integration-tests/suites/tracing/postgres/instrument.mjs similarity index 54% rename from dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument.cjs rename to dev-packages/node-integration-tests/suites/tracing/postgres/instrument.mjs index 6aec5f1f9384..46a27dd03b74 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument.cjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/instrument.mjs @@ -1,5 +1,5 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +import * as Sentry from '@sentry/node'; +import { loggingTransport } from '@sentry-internal/node-integration-tests'; Sentry.init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-ignoreConnect.js b/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-ignoreConnect.js deleted file mode 100644 index ca6afdae771d..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-ignoreConnect.js +++ /dev/null @@ -1,43 +0,0 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - integrations: [Sentry.postgresIntegration({ ignoreConnectSpans: true })], - transport: loggingTransport, -}); - -const { Client } = require('pg'); - -const client = new Client({ port: 5494, user: 'test', password: 'test', database: 'tests' }); - -async function run() { - await Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - async () => { - try { - await client.connect(); - - await client - .query( - 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"));', - ) - .catch(() => { - // if this is not a fresh database, the table might already exist - }); - - await client.query('INSERT INTO "User" ("email", "name") VALUES ($1, $2)', ['tim', 'tim@domain.com']); - await client.query('SELECT * FROM "User"'); - } finally { - await client.end(); - } - }, - ); -} - -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.js b/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.mjs similarity index 75% rename from dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.js rename to dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.mjs index db23800e6e1b..075b64218e19 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.js +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/scenario-native.mjs @@ -1,15 +1,7 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const { native } = require('pg'); +import * as Sentry from '@sentry/node'; +import pg from 'pg'; +const { native } = pg; const { Client } = native; const client = new Client({ port: 5494, user: 'test', password: 'test', database: 'tests' }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgres/scenario.js b/dev-packages/node-integration-tests/suites/tracing/postgres/scenario.mjs similarity index 74% rename from dev-packages/node-integration-tests/suites/tracing/postgres/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/postgres/scenario.mjs index 1f208754d771..351309e05010 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/scenario.mjs @@ -1,14 +1,5 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const { Client } = require('pg'); +import * as Sentry from '@sentry/node'; +import { Client } from 'pg'; const client = new Client({ port: 5494, user: 'test', password: 'test', database: 'tests' }); 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 e5d0e3f26fa8..5d493f94545f 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts @@ -1,9 +1,9 @@ -import { describe, expect, test } from 'vitest'; -import { createRunner } from '../../../utils/runner'; +import { describe, expect } from 'vitest'; import { conditionalTest } from '../../../utils'; +import { createEsmAndCjsTests } from '../../../utils/runner'; describe('postgres auto instrumentation', () => { - test('should auto-instrument `pg` package', { timeout: 90_000 }, async () => { + describe('default', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ @@ -47,114 +47,129 @@ describe('postgres auto instrumentation', () => { ]), }; - await createRunner(__dirname, 'scenario.js') - .withDockerCompose({ - workingDirectory: [__dirname], - }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('should auto-instrument `pg` package', { timeout: 90_000 }, async () => { + await createTestRunner() + .withDockerCompose({ + workingDirectory: [__dirname], + }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); - test("doesn't emit connect spans if ignoreConnectSpans is true", { timeout: 90_000 }, async () => { - await createRunner(__dirname, 'scenario-ignoreConnect.js') - .withDockerCompose({ - workingDirectory: [__dirname], - }) - .expect({ - transaction: txn => { - const spanNames = txn.spans?.map(span => span.description); - expect(spanNames?.find(name => name?.includes('connect'))).toBeUndefined(); - expect(txn).toMatchObject({ - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'SELECT * FROM "User"', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'SELECT * FROM "User"', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', - }), - ]), - }); - }, - }) - .start() - .completed(); + describe('ignoreConnectSpans', () => { + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument-ignoreConnect.mjs', + (createTestRunner, test) => { + test("doesn't emit connect spans if ignoreConnectSpans is true", { timeout: 90_000 }, async () => { + await createTestRunner() + .withDockerCompose({ + workingDirectory: [__dirname], + }) + .expect({ + transaction: txn => { + const spanNames = txn.spans?.map(span => span.description); + expect(spanNames?.find(name => name?.includes('connect'))).toBeUndefined(); + expect(txn).toMatchObject({ + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'postgresql', + 'db.name': 'tests', + 'db.statement': 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', + 'sentry.origin': 'auto.db.otel.postgres', + 'sentry.op': 'db', + }), + description: 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', + op: 'db', + status: 'ok', + origin: 'auto.db.otel.postgres', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'postgresql', + 'db.name': 'tests', + 'db.statement': 'SELECT * FROM "User"', + 'sentry.origin': 'auto.db.otel.postgres', + 'sentry.op': 'db', + }), + description: 'SELECT * FROM "User"', + op: 'db', + status: 'ok', + origin: 'auto.db.otel.postgres', + }), + ]), + }); + }, + }) + .start() + .completed(); + }); + }, + ); }); conditionalTest({ max: 25 })('pg-native', () => { - test('should auto-instrument `pg-native` package', { timeout: 90_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'sentry.origin': 'manual', - 'sentry.op': 'db', - }), - description: 'pg.connect', - op: 'db', - status: 'ok', + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'postgresql', + 'db.name': 'tests', + 'sentry.origin': 'manual', + 'sentry.op': 'db', }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'INSERT INTO "NativeUser" ("email", "name") VALUES ($1, $2)', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'INSERT INTO "NativeUser" ("email", "name") VALUES ($1, $2)', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', + description: 'pg.connect', + op: 'db', + status: 'ok', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'postgresql', + 'db.name': 'tests', + 'db.statement': 'INSERT INTO "NativeUser" ("email", "name") VALUES ($1, $2)', + 'sentry.origin': 'auto.db.otel.postgres', + 'sentry.op': 'db', }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'SELECT * FROM "NativeUser"', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'SELECT * FROM "NativeUser"', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', + description: 'INSERT INTO "NativeUser" ("email", "name") VALUES ($1, $2)', + op: 'db', + status: 'ok', + origin: 'auto.db.otel.postgres', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'postgresql', + 'db.name': 'tests', + 'db.statement': 'SELECT * FROM "NativeUser"', + 'sentry.origin': 'auto.db.otel.postgres', + 'sentry.op': 'db', }), - ]), - }; + description: 'SELECT * FROM "NativeUser"', + op: 'db', + status: 'ok', + origin: 'auto.db.otel.postgres', + }), + ]), + }; - await createRunner(__dirname, 'scenario-native.js') - .withDockerCompose({ - workingDirectory: [__dirname], - setupCommand: 'yarn', - }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests(__dirname, 'scenario-native.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('should auto-instrument `pg-native` package', { timeout: 90_000 }, async () => { + await createTestRunner() + .withDockerCompose({ + workingDirectory: [__dirname], + setupCommand: 'yarn', + }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); }); }); }); From d97244a4b55b5b4e68dda84ff5865034c31002b6 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:20:19 +0200 Subject: [PATCH 12/16] WIP postgresjs tests --- .../postgresjs/instrument-requestHook.cjs | 25 - .../postgresjs/scenario-requestHook.js | 38 -- .../postgresjs/scenario-requestHook.mjs | 5 +- .../tracing/postgresjs/scenario-unsafe.cjs | 45 -- .../tracing/postgresjs/scenario-unsafe.mjs | 5 +- .../tracing/postgresjs/scenario-url.cjs | 62 -- .../tracing/postgresjs/scenario-url.mjs | 5 +- .../suites/tracing/postgresjs/scenario.cjs | 59 -- .../suites/tracing/postgresjs/scenario.js | 81 --- .../suites/tracing/postgresjs/scenario.mjs | 5 +- .../suites/tracing/postgresjs/test.ts | 571 +++--------------- 11 files changed, 72 insertions(+), 829 deletions(-) delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument-requestHook.cjs delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.js delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.cjs delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.cjs delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.cjs delete mode 100644 dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.js diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument-requestHook.cjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument-requestHook.cjs deleted file mode 100644 index 0cf4c6185ef3..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/instrument-requestHook.cjs +++ /dev/null @@ -1,25 +0,0 @@ -const Sentry = require('@sentry/node'); -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, - integrations: [ - Sentry.postgresJsIntegration({ - requestHook: (span, sanitizedSqlQuery, connectionContext) => { - // Add custom attributes to demonstrate requestHook functionality - span.setAttribute('custom.requestHook', 'called'); - - // Set context information as extras for test validation - Sentry.setExtra('requestHookCalled', { - sanitizedQuery: sanitizedSqlQuery, - database: connectionContext?.ATTR_DB_NAMESPACE, - host: connectionContext?.ATTR_SERVER_ADDRESS, - port: connectionContext?.ATTR_SERVER_PORT, - }); - }, - }), - ], -}); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.js b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.js deleted file mode 100644 index b4d977c14d18..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.js +++ /dev/null @@ -1,38 +0,0 @@ -const Sentry = require('@sentry/node'); -const postgres = require('postgres'); -const { waitForPostgres } = require('./wait-for-postgres.js'); - -const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); - -async function run() { - await Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - async () => { - try { - await waitForPostgres(sql); - await sql` - CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id")); - `; - - await sql` - INSERT INTO "User" ("email", "name") VALUES ('Foo', 'bar@baz.com'); - `; - - await sql` - SELECT * FROM "User" WHERE "email" = 'bar@baz.com'; - `; - - await sql` - DROP TABLE "User"; - `; - } finally { - await sql.end(); - } - }, - ); -} - -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs index b9f93019afee..0914c2e0afcc 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs @@ -1,9 +1,6 @@ import * as Sentry from '@sentry/node'; -import { createRequire } from 'node:module'; import postgres from 'postgres'; - -const require = createRequire(import.meta.url); -const { waitForPostgres } = require('./wait-for-postgres.js'); +import { waitForPostgres } from './wait-for-postgres.js'; const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.cjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.cjs deleted file mode 100644 index c29c840906e4..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.cjs +++ /dev/null @@ -1,45 +0,0 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -// Import postgres AFTER Sentry.init() so instrumentation is set up -const postgres = require('postgres'); -const { waitForPostgres } = require('./wait-for-postgres.js'); - -// Test with plain object options -const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); - -async function run() { - await Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - async () => { - try { - await waitForPostgres(sql); - // Test sql.unsafe() - this was not being instrumented before the fix - await sql.unsafe('CREATE TABLE "User" ("id" SERIAL NOT NULL, "email" TEXT NOT NULL, PRIMARY KEY ("id"))'); - - await sql.unsafe('INSERT INTO "User" ("email") VALUES ($1)', ['test@example.com']); - - await sql.unsafe('SELECT * FROM "User" WHERE "email" = $1', ['test@example.com']); - - await sql.unsafe('DROP TABLE "User"'); - - // This will be captured as an error as the table no longer exists - await sql.unsafe('SELECT * FROM "User"'); - } finally { - await sql.end(); - } - }, - ); -} - -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs index d6ad5fa84fce..3265f4ea22cf 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs @@ -1,9 +1,6 @@ import * as Sentry from '@sentry/node'; -import { createRequire } from 'node:module'; import postgres from 'postgres'; - -const require = createRequire(import.meta.url); -const { waitForPostgres } = require('./wait-for-postgres.js'); +import { waitForPostgres } from './wait-for-postgres.js'; // Test with plain object options const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.cjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.cjs deleted file mode 100644 index 7647422acb0a..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.cjs +++ /dev/null @@ -1,62 +0,0 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -// Import postgres AFTER Sentry.init() so instrumentation is set up -const postgres = require('postgres'); -const { waitForPostgres } = require('./wait-for-postgres.js'); - -// Test URL-based initialization - this is the common pattern that was causing the regression -const sql = postgres('postgres://test:test@localhost:5444/test_db'); - -async function run() { - await Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - async () => { - try { - await waitForPostgres(sql); - await sql` - CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id")); - `; - - await sql` - INSERT INTO "User" ("email", "name") VALUES ('Foo', 'bar@baz.com'); - `; - - await sql` - UPDATE "User" SET "name" = 'Foo' WHERE "email" = 'bar@baz.com'; - `; - - await sql` - SELECT * FROM "User" WHERE "email" = 'bar@baz.com'; - `; - - await sql`SELECT * from generate_series(1,1000) as x `.cursor(10, async rows => { - await Promise.all(rows); - }); - - await sql` - DROP TABLE "User"; - `; - - // This will be captured as an error as the table no longer exists - await sql` - SELECT * FROM "User" WHERE "email" = 'foo@baz.com'; - `; - } finally { - await sql.end(); - } - }, - ); -} - -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs index e3014d461fb4..a21e6e41101b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs @@ -1,9 +1,6 @@ import * as Sentry from '@sentry/node'; -import { createRequire } from 'node:module'; import postgres from 'postgres'; - -const require = createRequire(import.meta.url); -const { waitForPostgres } = require('./wait-for-postgres.js'); +import { waitForPostgres } from './wait-for-postgres.js'; // Test URL-based initialization - this is the common pattern that was causing the regression const sql = postgres('postgres://test:test@localhost:5444/test_db'); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.cjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.cjs deleted file mode 100644 index 5a6e5d86e2b3..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.cjs +++ /dev/null @@ -1,59 +0,0 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -// Import postgres AFTER Sentry.init() so instrumentation is set up -const postgres = require('postgres'); - -const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); - -async function run() { - await Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - async () => { - try { - await sql` - CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id")); - `; - - await sql` - INSERT INTO "User" ("email", "name") VALUES ('Foo', 'bar@baz.com'); - `; - - await sql` - UPDATE "User" SET "name" = 'Foo' WHERE "email" = 'bar@baz.com'; - `; - - await sql` - SELECT * FROM "User" WHERE "email" = 'bar@baz.com'; - `; - - await sql`SELECT * from generate_series(1,1000) as x `.cursor(10, async rows => { - await Promise.all(rows); - }); - - await sql` - DROP TABLE "User"; - `; - - // This will be captured as an error as the table no longer exists - await sql` - SELECT * FROM "User" WHERE "email" = 'foo@baz.com'; - `; - } finally { - await sql.end(); - } - }, - ); -} - -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.js b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.js deleted file mode 100644 index 41d95ae3c1c1..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.js +++ /dev/null @@ -1,81 +0,0 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); -const { waitForPostgres } = require('./wait-for-postgres.js'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -const postgres = require('postgres'); - -const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); - -async function run() { - await Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - async () => { - try { - await waitForPostgres(sql); - await sql` - CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id")); - `; - - await sql` - INSERT INTO "User" ("email", "name") VALUES ('Foo', 'bar@baz.com'); - `; - - await sql` - UPDATE "User" SET "name" = 'Foo' WHERE "email" = 'bar@baz.com'; - `; - - await sql` - SELECT * FROM "User" WHERE "email" = 'bar@baz.com'; - `; - - // Test parameterized queries - await sql` - SELECT * FROM "User" WHERE "email" = ${'bar@baz.com'} AND "name" = ${'Foo'}; - `; - - // Test DELETE operation - await sql` - DELETE FROM "User" WHERE "email" = 'bar@baz.com'; - `; - - // Test INSERT with RETURNING - await sql` - INSERT INTO "User" ("email", "name") VALUES ('test@example.com', 'Test User') RETURNING *; - `; - - // Test cursor-based queries - await sql`SELECT * from generate_series(1,1000) as x `.cursor(10, async rows => { - await Promise.all(rows); - }); - - // Test multiple rows at once - await sql` - SELECT * FROM "User" LIMIT 10; - `; - - await sql` - DROP TABLE "User"; - `; - - // This will be captured as an error as the table no longer exists - await sql` - SELECT * FROM "User" WHERE "email" = 'foo@baz.com'; - `; - } finally { - await sql.end(); - } - }, - ); -} - -run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs index 33106e6115bb..2334ee36dcf1 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs @@ -1,9 +1,6 @@ import * as Sentry from '@sentry/node'; -import { createRequire } from 'node:module'; import postgres from 'postgres'; - -const require = createRequire(import.meta.url); -const { waitForPostgres } = require('./wait-for-postgres.js'); +import { waitForPostgres } from './wait-for-postgres.js'; const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); 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 f5f06208812e..d788259601ca 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts @@ -1,12 +1,12 @@ -import { afterAll, describe, expect, test } from 'vitest'; -import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; +import { afterAll, describe, expect } from 'vitest'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('postgresjs auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); - test('should auto-instrument `postgres` package (CJS)', { timeout: 60_000 }, async () => { + describe('basic', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ @@ -205,7 +205,8 @@ describe('postgresjs auto instrumentation', () => { frames: expect.arrayContaining([ expect.objectContaining({ function: 'handle', - module: 'postgres.cjs.src:connection', + // Module differs between CJS (`postgres.cjs.src:connection`) and ESM (`postgres.src:connection`) + module: expect.stringMatching(/^postgres(\.cjs)?\.src:connection$/), filename: expect.any(String), lineno: expect.any(Number), colno: expect.any(Number), @@ -217,328 +218,25 @@ describe('postgresjs auto instrumentation', () => { }, }; - await createRunner(__dirname, 'scenario.js') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .expect({ event: EXPECTED_ERROR_EVENT }) - .start() - .completed(); - }); - - test('should auto-instrument `postgres` package (ESM)', { timeout: 60_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'CREATE TABLE', - 'db.query.text': - 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(?) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"))', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: - 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(?) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"))', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'INSERT', - 'db.query.text': 'INSERT INTO "User" ("email", "name") VALUES (?, ?)', - 'sentry.origin': 'auto.db.postgresjs', - 'sentry.op': 'db', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'INSERT INTO "User" ("email", "name") VALUES (?, ?)', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'UPDATE', - 'db.query.text': 'UPDATE "User" SET "name" = ? WHERE "email" = ?', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'UPDATE "User" SET "name" = ? WHERE "email" = ?', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'SELECT', - 'db.query.text': 'SELECT * FROM "User" WHERE "email" = ?', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'SELECT * FROM "User" WHERE "email" = ?', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - // Parameterized query test - verifies that tagged template queries with interpolations - // are properly reconstructed with $1, $2 placeholders which are PRESERVED per OTEL spec - // (PostgreSQL $n placeholders indicate parameterized queries that don't leak sensitive data) - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'SELECT', - 'db.query.text': 'SELECT * FROM "User" WHERE "email" = $1 AND "name" = $2', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'SELECT * FROM "User" WHERE "email" = $1 AND "name" = $2', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'SELECT', - 'db.query.text': 'SELECT * from generate_series(?,?) as x', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'SELECT * from generate_series(?,?) as x', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'DROP TABLE', - 'db.query.text': 'DROP TABLE "User"', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'DROP TABLE "User"', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'SELECT', - 'db.response.status_code': '42P01', - 'error.type': 'PostgresError', - 'db.query.text': 'SELECT * FROM "User" WHERE "email" = ?', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'SELECT * FROM "User" WHERE "email" = ?', - op: 'db', - status: 'internal_error', - origin: 'auto.db.postgresjs', - parent_span_id: expect.any(String), - span_id: expect.any(String), - start_timestamp: expect.any(Number), - timestamp: expect.any(Number), - trace_id: expect.any(String), - }), - ]), - }; - - const EXPECTED_ERROR_EVENT = { - event_id: expect.any(String), - contexts: { - trace: { - trace_id: expect.any(String), - span_id: expect.any(String), - }, + createEsmAndCjsTests( + __dirname, + 'scenario.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should auto-instrument `postgres` package', { timeout: 60_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .expect({ event: EXPECTED_ERROR_EVENT }) + .start() + .completed(); + }); }, - exception: { - values: [ - { - type: 'PostgresError', - value: 'relation "User" does not exist', - stacktrace: expect.objectContaining({ - frames: expect.arrayContaining([ - expect.objectContaining({ - function: 'handle', - module: 'postgres.src:connection', - filename: expect.any(String), - lineno: expect.any(Number), - colno: expect.any(Number), - }), - ]), - }), - }, - ], - }, - }; - - await createRunner(__dirname, 'scenario.mjs') - .withFlags('--import', `${__dirname}/instrument.mjs`) - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .expect({ event: EXPECTED_ERROR_EVENT }) - .start() - .completed(); - }); - - test('should call requestHook when provided (CJS)', { timeout: 60_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'CREATE TABLE', - 'db.query.text': - 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(?) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"))', - 'custom.requestHook': 'called', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: - 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(?) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"))', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'INSERT', - 'db.query.text': 'INSERT INTO "User" ("email", "name") VALUES (?, ?)', - 'custom.requestHook': 'called', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'INSERT INTO "User" ("email", "name") VALUES (?, ?)', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'SELECT', - 'db.query.text': 'SELECT * FROM "User" WHERE "email" = ?', - 'custom.requestHook': 'called', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'SELECT * FROM "User" WHERE "email" = ?', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'DROP TABLE', - 'db.query.text': 'DROP TABLE "User"', - 'custom.requestHook': 'called', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'DROP TABLE "User"', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - ]), - extra: expect.objectContaining({ - requestHookCalled: expect.objectContaining({ - database: 'test_db', - host: 'localhost', - port: '5444', - sanitizedQuery: expect.any(String), - }), - }), - }; - - await createRunner(__dirname, 'scenario-requestHook.js') - .withFlags('--require', `${__dirname}/instrument-requestHook.cjs`) - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + { copyPaths: ['wait-for-postgres.js'] }, + ); }); - test('should call requestHook when provided (ESM)', { timeout: 60_000 }, async () => { + describe('requestHook', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ @@ -623,96 +321,24 @@ describe('postgresjs auto instrumentation', () => { }), }; - await createRunner(__dirname, 'scenario-requestHook.mjs') - .withFlags('--import', `${__dirname}/instrument-requestHook.mjs`) - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }); - - // Tests for URL-based initialization pattern (regression prevention) - test('should instrument postgres package with URL initialization (CJS)', { timeout: 90_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'CREATE TABLE', - 'db.query.text': - 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(?) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"))', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: - 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(?) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"))', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'INSERT', - 'db.query.text': 'INSERT INTO "User" ("email", "name") VALUES (?, ?)', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'INSERT INTO "User" ("email", "name") VALUES (?, ?)', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'UPDATE', - 'db.query.text': 'UPDATE "User" SET "name" = ? WHERE "email" = ?', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'UPDATE "User" SET "name" = ? WHERE "email" = ?', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'SELECT', - 'db.query.text': 'SELECT * FROM "User" WHERE "email" = ?', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'SELECT * FROM "User" WHERE "email" = ?', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - ]), - }; - - await createRunner(__dirname, 'scenario-url.cjs') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-requestHook.mjs', + 'instrument-requestHook.mjs', + (createTestRunner, test) => { + test('should call requestHook when provided', { timeout: 60_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + { copyPaths: ['wait-for-postgres.js'] }, + ); }); - test('should instrument postgres package with URL initialization (ESM)', { timeout: 90_000 }, async () => { + describe('url initialization', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ @@ -785,94 +411,24 @@ describe('postgresjs auto instrumentation', () => { ]), }; - await createRunner(__dirname, 'scenario-url.mjs') - .withFlags('--import', `${__dirname}/instrument.mjs`) - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }); - - test('should instrument sql.unsafe() queries (CJS)', { timeout: 90_000 }, async () => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'CREATE TABLE', - 'db.query.text': 'CREATE TABLE "User" ("id" SERIAL NOT NULL, "email" TEXT NOT NULL, PRIMARY KEY ("id"))', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'CREATE TABLE "User" ("id" SERIAL NOT NULL, "email" TEXT NOT NULL, PRIMARY KEY ("id"))', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - // sql.unsafe() with $1 placeholders - preserved per OTEL spec - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'INSERT', - 'db.query.text': 'INSERT INTO "User" ("email") VALUES ($1)', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'INSERT INTO "User" ("email") VALUES ($1)', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'SELECT', - 'db.query.text': 'SELECT * FROM "User" WHERE "email" = $1', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'SELECT * FROM "User" WHERE "email" = $1', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.namespace': 'test_db', - 'db.system.name': 'postgres', - 'db.operation.name': 'DROP TABLE', - 'db.query.text': 'DROP TABLE "User"', - 'sentry.op': 'db', - 'sentry.origin': 'auto.db.postgresjs', - 'server.address': 'localhost', - 'server.port': 5444, - }), - description: 'DROP TABLE "User"', - op: 'db', - status: 'ok', - origin: 'auto.db.postgresjs', - }), - ]), - }; - - await createRunner(__dirname, 'scenario-unsafe.cjs') - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-url.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should instrument postgres package with URL initialization', { timeout: 90_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + { copyPaths: ['wait-for-postgres.js'] }, + ); }); - test('should instrument sql.unsafe() queries (ESM)', { timeout: 90_000 }, async () => { + describe('sql.unsafe()', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ @@ -944,11 +500,20 @@ describe('postgresjs auto instrumentation', () => { ]), }; - await createRunner(__dirname, 'scenario-unsafe.mjs') - .withFlags('--import', `${__dirname}/instrument.mjs`) - .withDockerCompose({ workingDirectory: [__dirname] }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); + createEsmAndCjsTests( + __dirname, + 'scenario-unsafe.mjs', + 'instrument.mjs', + (createTestRunner, test) => { + test('should instrument sql.unsafe() queries', { timeout: 90_000 }, async () => { + await createTestRunner() + .withDockerCompose({ workingDirectory: [__dirname] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }, + { copyPaths: ['wait-for-postgres.js'] }, + ); }); }); From 88a5bb9efebd05d04438dee326abda41e413f86c Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:28:28 +0200 Subject: [PATCH 13/16] properly convert mjs files in tests --- .../postgresjs/scenario-requestHook.mjs | 2 +- .../tracing/postgresjs/scenario-unsafe.mjs | 2 +- .../tracing/postgresjs/scenario-url.mjs | 2 +- .../suites/tracing/postgresjs/scenario.mjs | 2 +- .../suites/tracing/postgresjs/test.ts | 8 +-- ...-for-postgres.js => wait-for-postgres.mjs} | 6 +- .../node-integration-tests/utils/runner.ts | 63 +++++++++++++++++-- 7 files changed, 66 insertions(+), 19 deletions(-) rename dev-packages/node-integration-tests/suites/tracing/postgresjs/{wait-for-postgres.js => wait-for-postgres.mjs} (81%) diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs index 0914c2e0afcc..6c190faeae29 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.js'; +import { waitForPostgres } from './wait-for-postgres.mjs'; const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs index 3265f4ea22cf..a2a94f56f70c 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.js'; +import { waitForPostgres } from './wait-for-postgres.mjs'; // Test with plain object options const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs index a21e6e41101b..ec7e2ae43cdc 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.js'; +import { waitForPostgres } from './wait-for-postgres.mjs'; // Test URL-based initialization - this is the common pattern that was causing the regression const sql = postgres('postgres://test:test@localhost:5444/test_db'); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs index 2334ee36dcf1..3c6891c4d645 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.js'; +import { waitForPostgres } from './wait-for-postgres.mjs'; const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); 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 d788259601ca..3f565161ff54 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts @@ -232,7 +232,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.js'] }, + { copyPaths: ['wait-for-postgres.mjs'] }, ); }); @@ -334,7 +334,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.js'] }, + { copyPaths: ['wait-for-postgres.mjs'] }, ); }); @@ -424,7 +424,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.js'] }, + { copyPaths: ['wait-for-postgres.mjs'] }, ); }); @@ -513,7 +513,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.js'] }, + { copyPaths: ['wait-for-postgres.mjs'] }, ); }); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.js b/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.mjs similarity index 81% rename from dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.js rename to dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.mjs index c8c10c6eeb80..6f1c185ba9b0 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.js +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.mjs @@ -1,10 +1,8 @@ -'use strict'; - /** * Retries until Postgres accepts connections. `docker compose up --wait` can report healthy * before the port forward on the host is ready (flaky on busy CI). */ -async function waitForPostgres(sql, maxWaitMs = 60_000) { +export async function waitForPostgres(sql, maxWaitMs = 60_000) { const deadline = Date.now() + maxWaitMs; for (;;) { try { @@ -18,5 +16,3 @@ async function waitForPostgres(sql, maxWaitMs = 60_000) { } } } - -module.exports = { waitForPostgres }; diff --git a/dev-packages/node-integration-tests/utils/runner.ts b/dev-packages/node-integration-tests/utils/runner.ts index 1634b80772b4..81984e38a53f 100644 --- a/dev-packages/node-integration-tests/utils/runner.ts +++ b/dev-packages/node-integration-tests/utils/runner.ts @@ -240,10 +240,17 @@ export function createEsmAndCjsTests( await convertEsmFileToCjs(esmScenarioPathForRun, cjsScenarioPath); await convertEsmFileToCjs(esmInstrumentPathForRun, cjsInstrumentPath); - // Copy any additional files/dirs into tmp dir + // Copy any additional files/dirs into tmp dir. + // For `.mjs` helper files, also emit a `.cjs` counterpart so they can be required + // from the CJS-converted scenario (which has its `.mjs` import paths rewritten to `.cjs`). if (options?.copyPaths) { for (const path of options.copyPaths) { - await cp(join(cwd, path), join(tmpDirPath, path), { recursive: true }); + const sourcePath = join(cwd, path); + const destPath = join(tmpDirPath, path); + await cp(sourcePath, destPath, { recursive: true }); + if (path.endsWith('.mjs')) { + await convertEsmFileToCjs(destPath, destPath.replace(/\.mjs$/, '.cjs')); + } } } @@ -869,23 +876,67 @@ function convertEsmToCjs(content: string): string { // eslint-disable-next-line regexp/optimal-quantifier-concatenation, regexp/no-super-linear-backtracking /import\s+([\w*{}\s,]+)\s+from\s+['"]([^'"]+)['"]/g, (_, imports: string, module: string) => { + const requirePath = rewriteRelativeMjsToCjs(module); if (imports.includes('* as')) { // Handle namespace imports: import * as x from 'y' -> const x = require('y') - return `const ${imports.replace('* as', '').trim()} = require('${module}')`; + return `const ${imports.replace('* as', '').trim()} = require('${requirePath}')`; } else if (imports.includes('{')) { // Handle named imports: import {x, y} from 'z' -> const {x, y} = require('z') - return `const ${imports} = require('${module}')`; + return `const ${imports} = require('${requirePath}')`; } else { // Handle default imports: import x from 'y' -> const x = require('y') - return `const ${imports} = require('${module}')`; + return `const ${imports} = require('${requirePath}')`; } }, ); // Handle side-effect imports: import 'x' -> require('x') newContent = newContent.replace(/import\s+['"]([^'"]+)['"]/g, (_, module) => { - return `require('${module}')`; + return `require('${rewriteRelativeMjsToCjs(module)}')`; + }); + + // Convert named exports. We strip the leading `export` keyword from declarations and + // collect their identifiers, then append `module.exports. = ` at the end. + const exportedNames: string[] = []; + + // export [async] function NAME / export const|let|var|class NAME + newContent = newContent.replace( + /export\s+(async\s+)?(function|const|let|var|class)\s+(\w+)/g, + (_match, asyncPrefix: string | undefined, kind: string, name: string) => { + exportedNames.push(name); + return `${asyncPrefix ?? ''}${kind} ${name}`; + }, + ); + + // export { a, b as c } + newContent = newContent.replace(/export\s*\{\s*([^}]+?)\s*\}\s*;?/g, (_match, names: string) => { + for (const raw of names.split(',')) { + const parts = raw.trim().split(/\s+as\s+/); + const exportedAs = (parts[1] ?? parts[0]).trim(); + if (exportedAs) exportedNames.push(exportedAs); + } + return ''; }); + // export default -> module.exports = + newContent = newContent.replace(/export\s+default\s+/g, 'module.exports = '); + + if (exportedNames.length > 0) { + const assignments = exportedNames.map(name => `module.exports.${name} = ${name};`).join('\n'); + newContent = `${newContent}\n${assignments}\n`; + } + return newContent; } + +/** + * Rewrites a relative ESM-helper import path from `.mjs` to `.cjs` so that the converted + * CJS scenario can `require()` the matching `.cjs` counterpart emitted by `copyPaths`. + * Non-relative or non-`.mjs` paths are returned unchanged. + */ +function rewriteRelativeMjsToCjs(modulePath: string): string { + if ((modulePath.startsWith('./') || modulePath.startsWith('../')) && modulePath.endsWith('.mjs')) { + return `${modulePath.slice(0, -'.mjs'.length)}.cjs`; + } + return modulePath; +} From 1ed36f1a4706e9421a4011e14cceab3ca5260ff5 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:31:17 +0200 Subject: [PATCH 14/16] Revert "properly convert mjs files in tests" This reverts commit b0e762416eae75861cf619f58ad003fc473c832f. --- .../postgresjs/scenario-requestHook.mjs | 2 +- .../tracing/postgresjs/scenario-unsafe.mjs | 2 +- .../tracing/postgresjs/scenario-url.mjs | 2 +- .../suites/tracing/postgresjs/scenario.mjs | 2 +- .../suites/tracing/postgresjs/test.ts | 8 +-- ...-for-postgres.mjs => wait-for-postgres.js} | 6 +- .../node-integration-tests/utils/runner.ts | 63 ++----------------- 7 files changed, 19 insertions(+), 66 deletions(-) rename dev-packages/node-integration-tests/suites/tracing/postgresjs/{wait-for-postgres.mjs => wait-for-postgres.js} (81%) diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs index 6c190faeae29..0914c2e0afcc 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-requestHook.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.mjs'; +import { waitForPostgres } from './wait-for-postgres.js'; const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs index a2a94f56f70c..3265f4ea22cf 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-unsafe.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.mjs'; +import { waitForPostgres } from './wait-for-postgres.js'; // Test with plain object options const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs index ec7e2ae43cdc..a21e6e41101b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario-url.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.mjs'; +import { waitForPostgres } from './wait-for-postgres.js'; // Test URL-based initialization - this is the common pattern that was causing the regression const sql = postgres('postgres://test:test@localhost:5444/test_db'); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs index 3c6891c4d645..2334ee36dcf1 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/scenario.mjs @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/node'; import postgres from 'postgres'; -import { waitForPostgres } from './wait-for-postgres.mjs'; +import { waitForPostgres } from './wait-for-postgres.js'; const sql = postgres({ port: 5444, user: 'test', password: 'test', database: 'test_db' }); 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 3f565161ff54..d788259601ca 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/test.ts @@ -232,7 +232,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.mjs'] }, + { copyPaths: ['wait-for-postgres.js'] }, ); }); @@ -334,7 +334,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.mjs'] }, + { copyPaths: ['wait-for-postgres.js'] }, ); }); @@ -424,7 +424,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.mjs'] }, + { copyPaths: ['wait-for-postgres.js'] }, ); }); @@ -513,7 +513,7 @@ describe('postgresjs auto instrumentation', () => { .completed(); }); }, - { copyPaths: ['wait-for-postgres.mjs'] }, + { copyPaths: ['wait-for-postgres.js'] }, ); }); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.mjs b/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.js similarity index 81% rename from dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.mjs rename to dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.js index 6f1c185ba9b0..c8c10c6eeb80 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/postgresjs/wait-for-postgres.js @@ -1,8 +1,10 @@ +'use strict'; + /** * Retries until Postgres accepts connections. `docker compose up --wait` can report healthy * before the port forward on the host is ready (flaky on busy CI). */ -export async function waitForPostgres(sql, maxWaitMs = 60_000) { +async function waitForPostgres(sql, maxWaitMs = 60_000) { const deadline = Date.now() + maxWaitMs; for (;;) { try { @@ -16,3 +18,5 @@ export async function waitForPostgres(sql, maxWaitMs = 60_000) { } } } + +module.exports = { waitForPostgres }; diff --git a/dev-packages/node-integration-tests/utils/runner.ts b/dev-packages/node-integration-tests/utils/runner.ts index 81984e38a53f..1634b80772b4 100644 --- a/dev-packages/node-integration-tests/utils/runner.ts +++ b/dev-packages/node-integration-tests/utils/runner.ts @@ -240,17 +240,10 @@ export function createEsmAndCjsTests( await convertEsmFileToCjs(esmScenarioPathForRun, cjsScenarioPath); await convertEsmFileToCjs(esmInstrumentPathForRun, cjsInstrumentPath); - // Copy any additional files/dirs into tmp dir. - // For `.mjs` helper files, also emit a `.cjs` counterpart so they can be required - // from the CJS-converted scenario (which has its `.mjs` import paths rewritten to `.cjs`). + // Copy any additional files/dirs into tmp dir if (options?.copyPaths) { for (const path of options.copyPaths) { - const sourcePath = join(cwd, path); - const destPath = join(tmpDirPath, path); - await cp(sourcePath, destPath, { recursive: true }); - if (path.endsWith('.mjs')) { - await convertEsmFileToCjs(destPath, destPath.replace(/\.mjs$/, '.cjs')); - } + await cp(join(cwd, path), join(tmpDirPath, path), { recursive: true }); } } @@ -876,67 +869,23 @@ function convertEsmToCjs(content: string): string { // eslint-disable-next-line regexp/optimal-quantifier-concatenation, regexp/no-super-linear-backtracking /import\s+([\w*{}\s,]+)\s+from\s+['"]([^'"]+)['"]/g, (_, imports: string, module: string) => { - const requirePath = rewriteRelativeMjsToCjs(module); if (imports.includes('* as')) { // Handle namespace imports: import * as x from 'y' -> const x = require('y') - return `const ${imports.replace('* as', '').trim()} = require('${requirePath}')`; + return `const ${imports.replace('* as', '').trim()} = require('${module}')`; } else if (imports.includes('{')) { // Handle named imports: import {x, y} from 'z' -> const {x, y} = require('z') - return `const ${imports} = require('${requirePath}')`; + return `const ${imports} = require('${module}')`; } else { // Handle default imports: import x from 'y' -> const x = require('y') - return `const ${imports} = require('${requirePath}')`; + return `const ${imports} = require('${module}')`; } }, ); // Handle side-effect imports: import 'x' -> require('x') newContent = newContent.replace(/import\s+['"]([^'"]+)['"]/g, (_, module) => { - return `require('${rewriteRelativeMjsToCjs(module)}')`; - }); - - // Convert named exports. We strip the leading `export` keyword from declarations and - // collect their identifiers, then append `module.exports. = ` at the end. - const exportedNames: string[] = []; - - // export [async] function NAME / export const|let|var|class NAME - newContent = newContent.replace( - /export\s+(async\s+)?(function|const|let|var|class)\s+(\w+)/g, - (_match, asyncPrefix: string | undefined, kind: string, name: string) => { - exportedNames.push(name); - return `${asyncPrefix ?? ''}${kind} ${name}`; - }, - ); - - // export { a, b as c } - newContent = newContent.replace(/export\s*\{\s*([^}]+?)\s*\}\s*;?/g, (_match, names: string) => { - for (const raw of names.split(',')) { - const parts = raw.trim().split(/\s+as\s+/); - const exportedAs = (parts[1] ?? parts[0]).trim(); - if (exportedAs) exportedNames.push(exportedAs); - } - return ''; + return `require('${module}')`; }); - // export default -> module.exports = - newContent = newContent.replace(/export\s+default\s+/g, 'module.exports = '); - - if (exportedNames.length > 0) { - const assignments = exportedNames.map(name => `module.exports.${name} = ${name};`).join('\n'); - newContent = `${newContent}\n${assignments}\n`; - } - return newContent; } - -/** - * Rewrites a relative ESM-helper import path from `.mjs` to `.cjs` so that the converted - * CJS scenario can `require()` the matching `.cjs` counterpart emitted by `copyPaths`. - * Non-relative or non-`.mjs` paths are returned unchanged. - */ -function rewriteRelativeMjsToCjs(modulePath: string): string { - if ((modulePath.startsWith('./') || modulePath.startsWith('../')) && modulePath.endsWith('.mjs')) { - return `${modulePath.slice(0, -'.mjs'.length)}.cjs`; - } - return modulePath; -} From b00a4ad8b76fe1cf758c490521190fe9d7e7e1c9 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:44:48 +0200 Subject: [PATCH 15/16] chore: yarn fix Co-Authored-By: Claude Opus 4.7 (1M context) --- .../useOperationNameForRootSpan/test.ts | 69 ++++++-------- .../suites/tracing/postgres/test.ts | 95 +++++++++---------- 2 files changed, 72 insertions(+), 92 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts index 66d34a1fa5a2..3fff2da7ef9a 100644 --- a/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/apollo-graphql/useOperationNameForRootSpan/test.ts @@ -89,20 +89,15 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - createEsmAndCjsTests( - __dirname, - 'scenario-invalid-root-span.mjs', - 'instrument.mjs', - (createTestRunner, test) => { - test('useOperationNameForRootSpan ignores an invalid root span', async () => { - await createTestRunner() - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }); - }, - ); + createEsmAndCjsTests(__dirname, 'scenario-invalid-root-span.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('useOperationNameForRootSpan ignores an invalid root span', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); describe('query without name', () => { @@ -122,20 +117,15 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - createEsmAndCjsTests( - __dirname, - 'scenario-no-operation-name.mjs', - 'instrument.mjs', - (createTestRunner, test) => { - test('useOperationNameForRootSpan works with single query operation without name', async () => { - await createTestRunner() - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }); - }, - ); + createEsmAndCjsTests(__dirname, 'scenario-no-operation-name.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('useOperationNameForRootSpan works with single query operation without name', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); describe('multiple operations', () => { @@ -167,20 +157,15 @@ describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => { ]), }; - createEsmAndCjsTests( - __dirname, - 'scenario-multiple-operations.mjs', - 'instrument.mjs', - (createTestRunner, test) => { - test('useOperationNameForRootSpan works with multiple query operations', async () => { - await createTestRunner() - .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) - .expect({ transaction: EXPECTED_TRANSACTION }) - .start() - .completed(); - }); - }, - ); + createEsmAndCjsTests(__dirname, 'scenario-multiple-operations.mjs', 'instrument.mjs', (createTestRunner, test) => { + test('useOperationNameForRootSpan works with multiple query operations', async () => { + await createTestRunner() + .expect({ transaction: EXPECTED_START_SERVER_TRANSACTION }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start() + .completed(); + }); + }); }); describe('many operations', () => { 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 5d493f94545f..056f3877d545 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts @@ -61,58 +61,53 @@ describe('postgres auto instrumentation', () => { }); describe('ignoreConnectSpans', () => { - createEsmAndCjsTests( - __dirname, - 'scenario.mjs', - 'instrument-ignoreConnect.mjs', - (createTestRunner, test) => { - test("doesn't emit connect spans if ignoreConnectSpans is true", { timeout: 90_000 }, async () => { - await createTestRunner() - .withDockerCompose({ - workingDirectory: [__dirname], - }) - .expect({ - transaction: txn => { - const spanNames = txn.spans?.map(span => span.description); - expect(spanNames?.find(name => name?.includes('connect'))).toBeUndefined(); - expect(txn).toMatchObject({ - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', + createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument-ignoreConnect.mjs', (createTestRunner, test) => { + test("doesn't emit connect spans if ignoreConnectSpans is true", { timeout: 90_000 }, async () => { + await createTestRunner() + .withDockerCompose({ + workingDirectory: [__dirname], + }) + .expect({ + transaction: txn => { + const spanNames = txn.spans?.map(span => span.description); + expect(spanNames?.find(name => name?.includes('connect'))).toBeUndefined(); + expect(txn).toMatchObject({ + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'postgresql', + 'db.name': 'tests', + 'db.statement': 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', + 'sentry.origin': 'auto.db.otel.postgres', + 'sentry.op': 'db', }), - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'postgresql', - 'db.name': 'tests', - 'db.statement': 'SELECT * FROM "User"', - 'sentry.origin': 'auto.db.otel.postgres', - 'sentry.op': 'db', - }), - description: 'SELECT * FROM "User"', - op: 'db', - status: 'ok', - origin: 'auto.db.otel.postgres', + description: 'INSERT INTO "User" ("email", "name") VALUES ($1, $2)', + op: 'db', + status: 'ok', + origin: 'auto.db.otel.postgres', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'postgresql', + 'db.name': 'tests', + 'db.statement': 'SELECT * FROM "User"', + 'sentry.origin': 'auto.db.otel.postgres', + 'sentry.op': 'db', }), - ]), - }); - }, - }) - .start() - .completed(); - }); - }, - ); + description: 'SELECT * FROM "User"', + op: 'db', + status: 'ok', + origin: 'auto.db.otel.postgres', + }), + ]), + }); + }, + }) + .start() + .completed(); + }); + }); }); conditionalTest({ max: 25 })('pg-native', () => { From d34875073f498b30b46f92b2f777467c36646a12 Mon Sep 17 00:00:00 2001 From: Francesco Gringl-Novy Date: Mon, 18 May 2026 10:57:08 +0200 Subject: [PATCH 16/16] add missing cleanup --- .../suites/tracing/postgres/test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 056f3877d545..e9ed24371d8c 100644 --- a/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/postgres/test.ts @@ -1,8 +1,12 @@ -import { describe, expect } from 'vitest'; +import { afterAll, describe, expect } from 'vitest'; import { conditionalTest } from '../../../utils'; -import { createEsmAndCjsTests } from '../../../utils/runner'; +import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner'; describe('postgres auto instrumentation', () => { + afterAll(() => { + cleanupChildProcesses(); + }); + describe('default', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction',