LearnNewsExamplesServices
Frontmatter
id8896
titleRefactor Node.js Unhandled Rejection Handling to process.emit Interception
stateClosed
labels
testingarchitecturecore
assigneestobiu
createdAtJan 27, 2026, 4:13 PM
updatedAtJan 27, 2026, 4:15 PM
githubUrlhttps://github.com/neomjs/neo/issues/8896
authortobiu
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJan 27, 2026, 4:15 PM

Refactor Node.js Unhandled Rejection Handling to process.emit Interception

Closed v11.24.0/archive-v11-24-0-chunk-1 testingarchitecturecore
tobiu
tobiu commented on Jan 27, 2026, 4:13 PM

Context

Neo.mjs components use a "Trap Pattern" (promiseUpdate, trap, timeout) to reject pending promises with Neo.isDestroyed when a component is destroyed. This prevents execution from continuing on dead objects. However, in Node.js environments (like Playwright unit tests or Server-Side Generation), these rejections often bubble up as "Unhandled Rejections," causing test runners to fail or processes to crash.

Problem

The existing mechanism in src/Neo.mjs used process.on('unhandledRejection') to suppress these specific errors. However, this approach is fragile because test runners (like Playwright) attach their own listeners that may execute before the suppression logic or simply count the event emission itself as a failure.

Solution

Refactor src/Neo.mjs to intercept the unhandledRejection event at the source by patching process.emit.

Implementation

  1. Intercept process.emit: Wrap the native emit function.
  2. Check Condition: If the event is 'unhandledRejection' AND the reason is Neo.isDestroyed, return true immediately. This swallows the event, preventing it from reaching any listeners.
  3. Fallback: For all other events, delegate to the original process.emit.

Intent

This change transforms Neo.isDestroyed from an "error to be caught" into a "control flow signal to be ignored" at the infrastructure level. It ensures robustness across all Node.js-based environments (Tests, Scripts, SSG) without requiring repetitive try/catch blocks in application or test code.

tobiu
tobiu Jan 27, 2026, 4:15 PM

Input from Gemini 3 Pro:

✦ I have refactored the unhandled rejection handling in src/Neo.mjs to intercept process.emit directly. This robustly suppresses Neo.isDestroyed rejections across all Node.js environments, including test runners like Playwright that might otherwise preempt or ignore standard process.on listeners.

I verified this fix by running the full unit test suite, confirming that all tests pass without unhandled rejection failures.

I also cleaned up test/playwright/setup.mjs to remove the temporary local patch, ensuring the core framework handles this concern globally.

  • 2026-08-30T22:26:06Z @neo-opus-vega cross-referenced by #17894