From e5ec622c75aaf8e97417ca471e4c5a1949619539 Mon Sep 17 00:00:00 2001 From: RulaKhaled Date: Tue, 25 Aug 2026 20:02:18 +0200 Subject: [PATCH] test(node-integration-tests): Wait for inspector before LocalVariables out-of-app assertions These scenarios threw after a fixed 500ms, which can beat the debugger worker on loaded CI and drop vars from the event. Co-Authored-By: Cursor Grok 4.6 --- .../local-variables-out-of-app-default.js | 10 +++++-- .../local-variables-out-of-app.js | 10 +++++-- .../suites/public-api/LocalVariables/test.ts | 16 ++++++++--- .../wait-for-local-variables.js | 27 +++++++++++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/public-api/LocalVariables/wait-for-local-variables.js diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app-default.js b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app-default.js index 04c3e3e2142e..a63632c4213a 100644 --- a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app-default.js +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app-default.js @@ -1,5 +1,6 @@ const Sentry = require('@sentry/node'); const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +const { waitForLocalVariablesCapture } = require('./wait-for-local-variables'); const externalFunctionFile = require.resolve('./node_modules/out-of-app-function.js'); @@ -17,11 +18,16 @@ Sentry.init({ includeLocalVariables: true, }); -setTimeout(async () => { +(async () => { + await waitForLocalVariablesCapture(); + try { in_app_function(); } catch (e) { Sentry.captureException(e); await Sentry.flush(); } -}, 500); +})().catch(error => { + process.stderr.write(`${error}\n`); + process.exit(1); +}); diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app.js b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app.js index 66fd4d80e2d6..adb23f9a9a82 100644 --- a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app.js +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-out-of-app.js @@ -1,5 +1,6 @@ const Sentry = require('@sentry/node'); const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +const { waitForLocalVariablesCapture } = require('./wait-for-local-variables'); const externalFunctionFile = require.resolve('./node_modules/out-of-app-function.js'); @@ -22,11 +23,16 @@ function in_app_function() { out_of_app_function(`${inAppVar} modified value`); } -setTimeout(async () => { +(async () => { + await waitForLocalVariablesCapture(); + try { in_app_function(); } catch (e) { Sentry.captureException(e); await Sentry.flush(); } -}, 500); +})().catch(error => { + process.stderr.write(`${error}\n`); + process.exit(1); +}); diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts index fcb1c9dcfe72..3b7eef8466ce 100644 --- a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts @@ -7,6 +7,10 @@ import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; // So we increase the timeout here // vi.setTimeout(45_000); +function findFrameByFunctionName(frames: Array<{ function?: string }>, functionName: string) { + return frames.find(frame => frame.function === functionName || frame.function === `Object.${functionName}`); +} + const EXPECTED_LOCAL_VARIABLES_EVENT = { exception: { values: [ @@ -187,12 +191,14 @@ module.exports = { out_of_app_function };`, event: event => { const frames = event.exception?.values?.[0]?.stacktrace?.frames || []; - const inAppFrame = frames.find(frame => frame.function === 'in_app_function'); - const outOfAppFrame = frames.find(frame => frame.function === 'out_of_app_function'); + const inAppFrame = findFrameByFunctionName(frames, 'in_app_function'); + const outOfAppFrame = findFrameByFunctionName(frames, 'out_of_app_function'); + expect(inAppFrame).toBeDefined(); expect(inAppFrame?.vars).toEqual({ inAppVar: 'in app value' }); expect(inAppFrame?.in_app).toEqual(true); + expect(outOfAppFrame).toBeDefined(); expect(outOfAppFrame?.vars).toEqual({ outOfAppVar: 'out of app value modified value', passedArg: 'in app value modified value', @@ -210,12 +216,14 @@ module.exports = { out_of_app_function };`, event: event => { const frames = event.exception?.values?.[0]?.stacktrace?.frames || []; - const inAppFrame = frames.find(frame => frame.function === 'in_app_function'); - const outOfAppFrame = frames.find(frame => frame.function === 'out_of_app_function'); + const inAppFrame = findFrameByFunctionName(frames, 'in_app_function'); + const outOfAppFrame = findFrameByFunctionName(frames, 'out_of_app_function'); + expect(inAppFrame).toBeDefined(); expect(inAppFrame?.vars).toEqual({ inAppVar: 'in app value' }); expect(inAppFrame?.in_app).toEqual(true); + expect(outOfAppFrame).toBeDefined(); expect(outOfAppFrame?.vars).toBeUndefined(); expect(outOfAppFrame?.in_app).toEqual(false); }, diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/wait-for-local-variables.js b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/wait-for-local-variables.js new file mode 100644 index 000000000000..35c5b1ca2956 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/wait-for-local-variables.js @@ -0,0 +1,27 @@ +const inspector = require('node:inspector'); + +function delay(ms) { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +/** + * LocalVariables captures vars on a worker that attaches after `inspector.open()`. + * Throwing before that worker has enabled pause-on-exceptions produces events without `vars`. + */ +async function waitForLocalVariablesCapture() { + const deadline = Date.now() + 8_000; + + while (!inspector.url()) { + if (Date.now() >= deadline) { + throw new Error('Timed out waiting for the Node inspector used by LocalVariables'); + } + await delay(25); + } + + // Worker startup + Debugger.setPauseOnExceptions still happens after inspector.open(). + await delay(1_000); +} + +module.exports = { waitForLocalVariablesCapture };