From daba2c2c0d511fa604fc848e44d6f100144f1c0c Mon Sep 17 00:00:00 2001 From: Archkon <180910180+Archkon@users.noreply.github.com> Date: Sun, 5 Jul 2026 15:55:56 +0800 Subject: [PATCH] test: defer pause to avoid pause forever Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com> --- lib/internal/debugger/inspect_probe.js | 26 ++++++++++++++++--- .../test-debugger-probe-startup-pause.js | 4 +-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/internal/debugger/inspect_probe.js b/lib/internal/debugger/inspect_probe.js index e7abc2e48cd365..41f429a468114a 100644 --- a/lib/internal/debugger/inspect_probe.js +++ b/lib/internal/debugger/inspect_probe.js @@ -474,6 +474,8 @@ class ProbeInspectorSession { this.inFlight = null; // Most recently completed probe, used for `error.probe` when a non-evaluate CDP call rejects. this.lastProbeIndex = null; + this.deferredStartupPause = null; + this.handledPauseAfterStart = false; const { promise, resolve } = PromiseWithResolvers(); this.completionPromise = promise; this.resolveCompletion = resolve; @@ -624,10 +626,17 @@ class ProbeInspectorSession { async handlePaused(params) { if (this.finished) { return; } - // Ignore pauses that arrive before breakpoint setup is complete. Once + // Defer pauses that arrive before breakpoint setup is complete. Once // startup is marked complete, `Runtime.runIfWaitingForDebugger` may surface - // the initial --inspect-brk pause, which the normal resume path handles. - if (!this.started) { return; } + // the initial --inspect-brk pause, which the normal resume path handles. If + // it was already surfaced while binding breakpoints, replay it after startup + // so the target is not left paused forever. + if (!this.started) { + this.deferredStartupPause = params; + return; + } + + this.handledPauseAfterStart = true; const hitBreakpoints = params.hitBreakpoints; if (hitBreakpoints === undefined || hitBreakpoints.length === 0) { @@ -676,6 +685,16 @@ class ProbeInspectorSession { await this.resume(); } + async handleDeferredStartupPause() { + if (this.deferredStartupPause === null || this.handledPauseAfterStart) { + return; + } + + const params = this.deferredStartupPause; + this.deferredStartupPause = null; + await this.handlePaused(params); + } + async evaluateProbe(callFrameId, probeIndex, location) { if (this.finished) { return; } const probe = this.probes[probeIndex]; @@ -998,6 +1017,7 @@ class ProbeInspectorSession { this.started = true; this.startTimeout(); await this.callCdp('Runtime.runIfWaitingForDebugger'); + await this.handleDeferredStartupPause(); } catch (err) { if (err !== kInspectorFailedSentinel) { throw err; } } diff --git a/test/parallel/test-debugger-probe-startup-pause.js b/test/parallel/test-debugger-probe-startup-pause.js index 917026bf13fe0f..d1f8c22d840549 100644 --- a/test/parallel/test-debugger-probe-startup-pause.js +++ b/test/parallel/test-debugger-probe-startup-pause.js @@ -1,5 +1,5 @@ // Flags: --expose-internals -// This tests that probe mode ignores pauses until startup has finished binding +// This tests that probe mode defers pauses until startup has finished binding // breakpoints. 'use strict'; @@ -25,7 +25,7 @@ async function testStartupPauseHandling() { assert.deepStrictEqual(cdpCalls, []); session.started = true; - await session.handlePaused({}); + await session.handleDeferredStartupPause(); assert.deepStrictEqual(cdpCalls, ['Debugger.resume']); }