name: node-compat
description: Run a Node.js compatibility test, diagnose failures, and either fix the implementation, skip, or ignore the test. Use when asked to work on node compat tests.
argument-hint:
allowed-tools: Bash Read Write Edit Glob Grep Agent
Node Compat Test
Work on Node.js compatibility test $ARGUMENTS.
Step 1: Build and run the test
./x build
./x test-compat $ARGUMENTS
If the test passes, report success and ensure test is specified in
tests/node_compat/config.jsonc.
Step 2: Diagnose the failure
Read the test file to understand what it tests:
# Tests live under tests/node_compat/test/
Use Grep and Read to find the test source, then analyze:
- What Node.js API or behavior is being tested?
- What is the actual error or assertion failure?
- Where is the relevant Deno implementation? Check
ext/node/(polyfills, ops, internal bindings),runtime/, orcli/.
Read the corresponding Node.js docs and/or source code to understand the expected behavior.
Step 3: Classify the failure
Determine which category this failure falls into:
A. Fixable bug
The Deno implementation is wrong or incomplete, but can be corrected. This includes:
- Missing method/property on a polyfill
- Wrong return value or error type
- Missing event emission
- Incorrect argument handling
- Hard-to-fix but still fundamentally implementable behaviors
Action: Fix the implementation (Step 4).
B. Inherent incompatibility
The test relies on Node.js internals or architecture that Deno fundamentally cannot or will not support:
internalBinding()calls to Node's C++ layer- Node.js-specific CLI flags (
--inspect,--prof, etc.) - V8 internals exposed through Node-specific APIs
- Node.js-specific build/addon tooling (node-gyp internals)
- Tests for Node.js's own test infrastructure
Action: Ignore the test with a reason (Step 5).
C. Not worth fixing
The test exercises an edge case or behavior that is technically possible but provides negligible value:
- Extremely obscure error message wording differences
- Node.js-specific deprecation warnings
- Behavior that no real-world code depends on
Action: Ignore or skip the test with a reason (Step 5).
Step 4: Fix the implementation
If the failure is fixable:
- Locate the relevant code in
ext/node/(or elsewhere). - Implement the fix. Match Node.js behavior - check Node.js docs and/or source code, not just what "seems right."
- Use lazy-loaded imports where possible.
- Use primordials for internal JS code to avoid prototype pollution.
- Rebuild the source code with
./x build- this is paramount, changes won't take effect until you do. - Re-run the test to verify the fix:
./x test-compat $ARGUMENTS
- Once the test passes, make sure the test is listed in
tests/node_compat/config.jsoncwith an empty config:
"category/test-name.js": {}
The entries in config.jsonc are sorted alphabetically within their category.
Place the new entry in the correct position.
Step 5: Skip or ignore the test
If the test cannot or should not be fixed, update
tests/node_compat/config.jsonc.
Ignore (test should never run — inherent incompatibility)
"category/test-name.js": {
"ignore": true,
"reason": "Brief, specific explanation of why this can't work in Deno"
}
"reason" must be specified otherwise the lint step will fail!
Platform-specific skip
If the test only fails on certain platforms:
"category/test-name.js": {
"windows": false
}
Expected failure (test runs but fails with known output)
If you want the test to run but expect a specific failure:
"category/test-name.js": {
"exitCode": 1,
"output": "[WILDCARD]specific error message[WILDCARD]",
"reason": "Brief explanation of why this fails"
}
This is a good middle ground for tests that are generally compatible but have a specific known issue. If a fix is ever done this assertion will notify the implementer to update the config.
Writing good reasons
Reasons should be specific and actionable. Good examples:
- "Tests Node.js internal C++ binding (internalBinding('zlib').Zlib) which is not implemented in Deno"
- "requires
deno --interactiveflag (not yet implemented)" - "URL.createObjectURL does not throw ERR_INVALID_ARG_TYPE for non-Blob arguments"
Bad examples:
- "Not supported" (too vague)
- "Doesn't work" (says nothing)
- "Node-specific" (which part?)
Step 6: Verify
Re-run the test one final time to confirm the outcome matches expectations:
./x test-compat $ARGUMENTS
Config reference
The full schema for config.jsonc entries is in
tests/node_compat/schema.json.
PR title conventions
When opening a PR for node-compat work, use the appropriate prefix:
test:— when the PR only updatestests/node_compat/config.jsoncto skip, ignore, or otherwise reclassify tests without changing implementation code.fix(ext/node):— when the PR actually fixes the implementation so a previously failing test now passes (typically changes underext/node/plus enabling the test inconfig.jsonc).