From 6d8af54765b8d2b0468574a6e91e5aa06b6909a8 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Sat, 3 Oct 2026 13:05:18 +0200 Subject: [PATCH 1/2] test(node): port filesystem integration tests to span streaming Co-Authored-By: GPT-6 --- .../instrument-record-errors-only.mjs | 1 - .../instrument-record-paths-only.mjs | 1 - .../suites/fs-instrumentation/instrument.mjs | 1 - .../suites/fs-instrumentation/test.ts | 552 +++++++++--------- 4 files changed, 291 insertions(+), 264 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-errors-only.mjs b/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-errors-only.mjs index 7043bf763c1b..eff54f5b1ba7 100644 --- a/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-errors-only.mjs +++ b/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-errors-only.mjs @@ -2,7 +2,6 @@ import * as Sentry from '@sentry/node'; import { loggingTransport } from '@sentry-internal/node-integration-tests'; Sentry.init({ - traceLifecycle: 'static', dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', transport: loggingTransport, diff --git a/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-paths-only.mjs b/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-paths-only.mjs index 018477190488..05beff418e87 100644 --- a/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-paths-only.mjs +++ b/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument-record-paths-only.mjs @@ -2,7 +2,6 @@ import * as Sentry from '@sentry/node'; import { loggingTransport } from '@sentry-internal/node-integration-tests'; Sentry.init({ - traceLifecycle: 'static', dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', transport: loggingTransport, diff --git a/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument.mjs b/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument.mjs index bc31198a2137..f17a1e3bd449 100644 --- a/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument.mjs +++ b/dev-packages/node-integration-tests/suites/fs-instrumentation/instrument.mjs @@ -2,7 +2,6 @@ import * as Sentry from '@sentry/node'; import { loggingTransport } from '@sentry-internal/node-integration-tests'; Sentry.init({ - traceLifecycle: 'static', dsn: 'https://public@dsn.ingest.sentry.io/1337', release: '1.0', transport: loggingTransport, diff --git a/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts b/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts index 53d79a85a603..b23ad21d9423 100644 --- a/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts +++ b/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts @@ -1,8 +1,43 @@ +import type { SerializedStreamedSpanContainer } from '@sentry/core'; import { SENTRY_OP } from '@sentry/conventions/attributes'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/node'; import { afterAll, describe, expect } from 'vitest'; import { cleanupChildProcesses, createCjsTests } from '../../utils/runner'; +type FileSpan = Pick; + +function expectFileSpans( + segmentName: string, + expected: FileSpan[], +): (container: SerializedStreamedSpanContainer) => void { + const spans: SerializedStreamedSpanContainer['items'] = []; + + return container => { + spans.push(...container.items); + const segment = spans.find(span => span.is_segment && span.name === segmentName); + expect(segment).toBeDefined(); + + const fileSpans = spans.filter( + span => span.attributes[SENTRY_OP]?.value === 'file' && span.trace_id === segment!.trace_id, + ); + expect( + fileSpans.map(({ name, status, attributes }) => ({ + name, + status, + attributes: Object.fromEntries( + Object.entries(attributes).filter( + ([key]) => + key.endsWith('_argument') || + key === 'error.type' || + key === SENTRY_OP || + key === SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + ), + ), + })), + ).toEqual(expect.arrayContaining(expected)); + }; +} + describe('fs instrumentation', () => { afterAll(() => { cleanupChildProcesses(); @@ -16,23 +51,23 @@ describe('fs instrumentation', () => { (createRunner, test) => { test('should create spans for fs operations that take target argument', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /readFile-error', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.readFile', - op: 'file', - status: 'internal_error', - data: { - 'error.type': 'ENOENT', - path_argument: expect.stringMatching('/fixtures/some-file-that-doesnt-exist.txt'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + span: expectFileSpans('GET /readFile-error', [ + { + name: 'fs.readFile', + status: 'error', + attributes: { + 'error.type': { type: 'string', value: 'ENOENT' }, + path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-that-doesnt-exist.txt'), }, - }), - ]), - }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -43,42 +78,40 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take one path', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /readFile', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.readFile', - op: 'file', - status: 'ok', - data: { - path_argument: expect.stringMatching('/fixtures/some-file.txt'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - expect.objectContaining({ - description: 'fs.readFile', - op: 'file', - status: 'ok', - data: { - path_argument: expect.stringMatching('/fixtures/some-file-promises.txt'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + span: expectFileSpans('GET /readFile', [ + { + name: 'fs.readFile', + status: 'ok', + attributes: { + path_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file.txt') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.readFile', + status: 'ok', + attributes: { + path_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file-promises.txt') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.readFile', + status: 'ok', + attributes: { + path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt'), }, - }), - expect.objectContaining({ - description: 'fs.readFile', - op: 'file', - status: 'ok', - data: { - path_argument: expect.stringMatching('/fixtures/some-file-promisify.txt'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - ]), - }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -89,45 +122,46 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take src and dest arguments', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /copyFile', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.copyFile', - op: 'file', - status: 'ok', - data: { - src_argument: expect.stringMatching('/fixtures/some-file.txt'), - dest_argument: expect.stringMatching('/fixtures/some-file.txt.copy'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - expect.objectContaining({ - description: 'fs.copyFile', - op: 'file', - status: 'ok', - data: { - src_argument: expect.stringMatching('/fixtures/some-file-promises.txt'), - dest_argument: expect.stringMatching('/fixtures/some-file-promises.txt.copy'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + span: expectFileSpans('GET /copyFile', [ + { + name: 'fs.copyFile', + status: 'ok', + attributes: { + src_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file.txt') }, + dest_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file.txt.copy') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.copyFile', + status: 'ok', + attributes: { + src_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file-promises.txt') }, + dest_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promises.txt.copy'), }, - }), - expect.objectContaining({ - description: 'fs.copyFile', - op: 'file', - status: 'ok', - data: { - src_argument: expect.stringMatching('/fixtures/some-file-promisify.txt'), - dest_argument: expect.stringMatching('/fixtures/some-file-promisify.txt.copy'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.copyFile', + status: 'ok', + attributes: { + src_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file-promisify.txt') }, + dest_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt.copy'), }, - }), - ]), - }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -138,45 +172,46 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take existing path and new path arguments', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /link', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.link', - op: 'file', - status: 'ok', - data: { - existing_path_argument: expect.stringMatching('/fixtures/some-file.txt'), - new_path_argument: expect.stringMatching('/fixtures/some-file.txt.link'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + span: expectFileSpans('GET /link', [ + { + name: 'fs.link', + status: 'ok', + attributes: { + existing_path_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file.txt') }, + new_path_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file.txt.link') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.link', + status: 'ok', + attributes: { + existing_path_argument: { type: 'string', value: expect.stringMatching('/some-file-promises.txt') }, + new_path_argument: { type: 'string', value: expect.stringMatching('/some-file-promises.txt.link') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.link', + status: 'ok', + attributes: { + existing_path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt'), }, - }), - expect.objectContaining({ - description: 'fs.link', - op: 'file', - status: 'ok', - data: { - existing_path_argument: expect.stringMatching('/some-file-promises.txt'), - new_path_argument: expect.stringMatching('/some-file-promises.txt.link'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + new_path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt.link'), }, - }), - expect.objectContaining({ - description: 'fs.link', - op: 'file', - status: 'ok', - data: { - existing_path_argument: expect.stringMatching('/fixtures/some-file-promisify.txt'), - new_path_argument: expect.stringMatching('/fixtures/some-file-promisify.txt.link'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - ]), - }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -187,42 +222,37 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take prefix argument', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /mkdtemp', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.mkdtemp', - op: 'file', - status: 'ok', - data: { - prefix_argument: expect.stringMatching('/foo-'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - expect.objectContaining({ - description: 'fs.mkdtemp', - op: 'file', - status: 'ok', - data: { - prefix_argument: expect.stringMatching('/foo-'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - expect.objectContaining({ - description: 'fs.mkdtemp', - op: 'file', - status: 'ok', - data: { - prefix_argument: expect.stringMatching('/foo-'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - ]), - }, + span: expectFileSpans('GET /mkdtemp', [ + { + name: 'fs.mkdtemp', + status: 'ok', + attributes: { + prefix_argument: { type: 'string', value: expect.stringMatching('/foo-') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.mkdtemp', + status: 'ok', + attributes: { + prefix_argument: { type: 'string', value: expect.stringMatching('/foo-') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.mkdtemp', + status: 'ok', + attributes: { + prefix_argument: { type: 'string', value: expect.stringMatching('/foo-') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -233,45 +263,52 @@ describe('fs instrumentation', () => { test('should create spans for fs symlink operations that take target argument', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /symlink', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.symlink', - op: 'file', - status: 'ok', - data: { - target_argument: expect.stringMatching('/some-file-promisify.txt'), - path_argument: expect.stringMatching('/some-file-promisify.txt.symlink'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + span: expectFileSpans('GET /symlink', [ + { + name: 'fs.symlink', + status: 'ok', + attributes: { + target_argument: { type: 'string', value: expect.stringMatching('/some-file-promisify.txt') }, + path_argument: { type: 'string', value: expect.stringMatching('/some-file-promisify.txt.symlink') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.symlink', + status: 'ok', + attributes: { + target_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt'), }, - }), - expect.objectContaining({ - description: 'fs.symlink', - op: 'file', - status: 'ok', - data: { - target_argument: expect.stringMatching('/fixtures/some-file-promisify.txt'), - path_argument: expect.stringMatching('/fixtures/some-file-promisify.txt.symlink'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt.symlink'), }, - }), - expect.objectContaining({ - description: 'fs.symlink', - op: 'file', - status: 'ok', - data: { - target_argument: expect.stringMatching('/fixtures/some-file-promisify.txt'), - path_argument: expect.stringMatching('/fixtures/some-file-promisify.txt.symlink'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.symlink', + status: 'ok', + attributes: { + target_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt'), }, - }), - ]), - }, + path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt.symlink'), + }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -282,32 +319,31 @@ describe('fs instrumentation', () => { test('should create spans for fs.exists callback and promisified versions', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /exists', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.exists', - op: 'file', - status: 'ok', - data: { - path_argument: expect.stringMatching('/fixtures/some-file.txt'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - expect.objectContaining({ - description: 'fs.exists', - op: 'file', - status: 'ok', - data: { - path_argument: expect.stringMatching('/fixtures/some-file-promisify.txt'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + span: expectFileSpans('GET /exists', [ + { + name: 'fs.exists', + status: 'ok', + attributes: { + path_argument: { type: 'string', value: expect.stringMatching('/fixtures/some-file.txt') }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + { + name: 'fs.exists', + status: 'ok', + attributes: { + path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-promisify.txt'), }, - }), - ]), - }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -328,23 +364,23 @@ describe('fs instrumentation', () => { (createRunner, test) => { test('records file path but not error messages when only `recordFilePaths` is enabled', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /readFile-error', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.readFile', - op: 'file', - status: 'internal_error', - // `path_argument` is recorded, but `error.type` is NOT, since `recordErrorMessagesAsSpanAttributes` is off - data: { - path_argument: expect.stringMatching('/fixtures/some-file-that-doesnt-exist.txt'), - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', + span: expectFileSpans('GET /readFile-error', [ + { + name: 'fs.readFile', + status: 'error', + // `path_argument` is recorded, but `error.type` is NOT, since `recordErrorMessagesAsSpanAttributes` is off + attributes: { + path_argument: { + type: 'string', + value: expect.stringMatching('/fixtures/some-file-that-doesnt-exist.txt'), }, - }), - ]), - }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -365,23 +401,20 @@ describe('fs instrumentation', () => { (createRunner, test) => { test('records error messages but not file paths when only `recordErrorMessagesAsSpanAttributes` is enabled', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /readFile-error', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.readFile', - op: 'file', - status: 'internal_error', - // `error.type` is recorded, but `path_argument` is NOT, since `recordFilePaths` is off - data: { - 'error.type': 'ENOENT', - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - ]), - }, + span: expectFileSpans('GET /readFile-error', [ + { + name: 'fs.readFile', + status: 'error', + // `error.type` is recorded, but `path_argument` is NOT, since `recordFilePaths` is off + attributes: { + 'error.type': { type: 'string', value: 'ENOENT' }, + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); @@ -392,22 +425,19 @@ describe('fs instrumentation', () => { test('does not record file paths on successful operations when only `recordErrorMessagesAsSpanAttributes` is enabled', async () => { const runner = createRunner() + .unordered() .expect({ - transaction: { - transaction: 'GET /readFile', - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'fs.readFile', - op: 'file', - status: 'ok', - // Neither `path_argument` nor `error.type` are recorded - data: { - [SENTRY_OP]: 'file', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.file.fs', - }, - }), - ]), - }, + span: expectFileSpans('GET /readFile', [ + { + name: 'fs.readFile', + status: 'ok', + // Neither `path_argument` nor `error.type` are recorded + attributes: { + [SENTRY_OP]: { type: 'string', value: 'file' }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { type: 'string', value: 'auto.file.fs' }, + }, + }, + ]), }) .start(); From a43afb6a265c04c1bc0fc775666105cfe732a6c5 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Mon, 5 Oct 2026 11:39:30 +0200 Subject: [PATCH 2/2] test(node): Remove unnecessary unordered filesystem expectations Co-Authored-By: GPT-6 --- .../suites/fs-instrumentation/test.ts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts b/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts index b23ad21d9423..644a8c886e5e 100644 --- a/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts +++ b/dev-packages/node-integration-tests/suites/fs-instrumentation/test.ts @@ -10,10 +10,8 @@ function expectFileSpans( segmentName: string, expected: FileSpan[], ): (container: SerializedStreamedSpanContainer) => void { - const spans: SerializedStreamedSpanContainer['items'] = []; - return container => { - spans.push(...container.items); + const spans = container.items; const segment = spans.find(span => span.is_segment && span.name === segmentName); expect(segment).toBeDefined(); @@ -51,7 +49,6 @@ describe('fs instrumentation', () => { (createRunner, test) => { test('should create spans for fs operations that take target argument', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /readFile-error', [ { @@ -78,7 +75,6 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take one path', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /readFile', [ { @@ -122,7 +118,6 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take src and dest arguments', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /copyFile', [ { @@ -172,7 +167,6 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take existing path and new path arguments', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /link', [ { @@ -222,7 +216,6 @@ describe('fs instrumentation', () => { test('should create spans for fs operations that take prefix argument', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /mkdtemp', [ { @@ -263,7 +256,6 @@ describe('fs instrumentation', () => { test('should create spans for fs symlink operations that take target argument', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /symlink', [ { @@ -319,7 +311,6 @@ describe('fs instrumentation', () => { test('should create spans for fs.exists callback and promisified versions', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /exists', [ { @@ -364,7 +355,6 @@ describe('fs instrumentation', () => { (createRunner, test) => { test('records file path but not error messages when only `recordFilePaths` is enabled', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /readFile-error', [ { @@ -401,7 +391,6 @@ describe('fs instrumentation', () => { (createRunner, test) => { test('records error messages but not file paths when only `recordErrorMessagesAsSpanAttributes` is enabled', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /readFile-error', [ { @@ -425,7 +414,6 @@ describe('fs instrumentation', () => { test('does not record file paths on successful operations when only `recordErrorMessagesAsSpanAttributes` is enabled', async () => { const runner = createRunner() - .unordered() .expect({ span: expectFileSpans('GET /readFile', [ {