Node 22 Compatibility Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Fix fake XHR compatibility for supported Node runtimes (>= 22) by separating Blob, FileReader, and FormData detection, updating tests, and aligning CI with the supported Node baseline.
Architecture: The fix should remove the assumption that Blob and FileReader always coexist. Production code should gate behavior on the narrow capability each path actually needs, while tests should use APIs that exist in supported Node versions. CI should reflect the new Node >= 22 support policy directly.
Tech Stack: Node.js, Mocha, jsdom, GitHub Actions, nise fake XHR implementation
Task 1: Reproduce the Node 22 failure mode
Files:
- Modify: lib/fake-xhr/index.test.js
- Test: lib/fake-xhr/index.test.js
Step 1: Add or adjust a failing test that captures the current incorrect assumption
Add a focused test near the existing blob/form-data coverage that proves the current code couples blob behavior to FileReader or uses an outdated capability guard.
it("supports blob responses when Blob exists without requiring FileReader", function () {
this.xhr.responseType = "blob";
this.xhr.open("GET", "/");
this.xhr.send();
this.xhr.respond(
200,
{ "Content-Type": "application/octet-stream" },
"blob body",
);
assert.equals(this.xhr.response.constructor.name, "Blob");
});
Step 2: Run the focused test to verify it fails or exposes the current mismatch
Run: npm test -- --grep "supports blob responses when Blob exists without requiring FileReader"
Expected: FAIL or demonstrate that existing blob tests are gated incorrectly for Node 22.
Step 3: Add a focused test for FormData header handling under supported Node
it("does not set Content-Type for FormData payloads", function () {
this.xhr.open("POST", "/");
var formData = new FormData();
formData.append("username", "biz");
this.xhr.send(formData);
assert.isUndefined(this.xhr.requestHeaders["Content-Type"]);
assert.isUndefined(this.xhr.requestHeaders["content-type"]);
});
Step 4: Run the focused FormData test
Run: npm test -- --grep "does not set Content-Type for FormData payloads"
Expected: PASS if native Node 22 FormData already works, otherwise FAIL with a concrete compatibility error to address.
Step 5: Commit
git add lib/fake-xhr/index.test.js
git commit -m "test: reproduce node 22 xhr compatibility issues"
Task 2: Narrow runtime capability detection in production code
Files:
- Modify: lib/fake-xhr/index.js
- Modify: lib/fake-xhr/blob.js
- Test: lib/fake-xhr/index.test.js
Step 1: Write the failing test for the production guard change
If Task 1 did not already fail at the right seam, add a smaller test around the specific branch that currently uses supportsBlob.
it("creates blob responses when Blob is supported", function () {
this.xhr.responseType = "blob";
this.xhr.open("GET", "/");
this.xhr.send();
this.xhr.respond(200, {}, "data");
assert.equals(this.xhr.response.constructor.name, "Blob");
});
Step 2: Run the targeted test
Run: npm test -- --grep "creates blob responses when Blob is supported"
Expected: FAIL or show the current guard is broader/narrower than intended.
Step 3: Write the minimal implementation
In lib/fake-xhr/index.js:
- keep
supportsFormDataas a directtypeof FormData !== "undefined"check; - keep blob support separate from any
FileReadercheck; - ensure
verifyResponseBodyTypeand blob response creation use the blob-specific capability only.
In lib/fake-xhr/blob.js:
- keep or rename the helper so it answers only one question: can the runtime construct a
Blob?
Example direction:
var supportsFormData = typeof FormData !== "undefined";
var supportsBlob = require("./blob").isSupported;
var supportsFileReader = typeof FileReader !== "undefined";
Use supportsBlob in production blob paths. Only use supportsFileReader in code that directly depends on it.
Step 4: Run the targeted tests
Run: npm test -- --grep "blob"
Expected: targeted blob tests PASS on Node 22.
Step 5: Commit
git add lib/fake-xhr/index.js lib/fake-xhr/blob.js lib/fake-xhr/index.test.js
git commit -m "fix: separate xhr feature detection for node 22"
Task 3: Update blob assertions to avoid a hard FileReader dependency
Files:
- Modify: lib/fake-xhr/index.test.js
- Test: lib/fake-xhr/index.test.js
Step 1: Replace FileReader-based blob assertion helpers with a supported API
Prefer Blob.text() in the shared blob assertion helper.
function assertBlobMatches(actual, expected, done) {
Promise.all([
actual.text(),
expected instanceof Blob ? expected.text() : Promise.resolve(expected),
]).then(function (values) {
assert.same(values[0], values[1]);
done();
}, done);
}
Step 2: Run the focused blob response tests
Run: npm test -- --grep "with Blob support|with Blob and FileReader support|blob"
Expected: PASS on Node 22 without requiring a global FileReader.
Step 3: Clean up test descriptions and guards
- rename outdated describe blocks if they refer to
Blob and FileReader support; - gate only truly
FileReader-specific tests ontypeof FileReader !== "undefined".
Step 4: Re-run the fake XHR test file
Run: npm test -- lib/fake-xhr/index.test.js
Expected: PASS
Step 5: Commit
git add lib/fake-xhr/index.test.js
git commit -m "test: align blob assertions with node 22 APIs"
Task 4: Align CI with supported Node versions
Files:
- Modify: .github/workflows/main.yml
Step 1: Add a failing CI expectation in review notes
Document the intended supported versions before editing:
Supported Node versions for this change: 22 and newer.
Step 2: Update the test matrix
Change the workflow matrix in .github/workflows/main.yml from Node 16-only coverage to supported versions, for example:
strategy:
matrix:
node-version: [22, 24]
Keep the existing dedicated Node 20 coverage job only if the project still wants that separate signal; otherwise align it to the supported baseline too.
Step 3: Validate workflow syntax locally by inspection
Run: sed -n '1,180p' .github/workflows/main.yml
Expected: Node test entries show only supported versions.
Step 4: Commit
git add .github/workflows/main.yml
git commit -m "ci: test supported node versions"
Task 5: Full verification
Files:
- Modify: docs/plans/2026-03-02-node-22-compat.md if commands need correction
- Test: lib/fake-xhr/index.test.js
Step 1: Run the fake XHR test file
Run: npm test -- lib/fake-xhr/index.test.js
Expected: PASS
Step 2: Run the full test suite
Run: npm test
Expected: PASS
Step 3: Run lint if code structure changed materially
Run: npm run lint
Expected: PASS
Step 4: Inspect the final diff
Run: git diff --stat
Expected: only fake XHR code, tests, CI, and plan docs are changed.
Step 5: Commit
git add .github/workflows/main.yml lib/fake-xhr/index.js lib/fake-xhr/blob.js lib/fake-xhr/index.test.js docs/plans/2026-03-02-node-22-compat*.md
git commit -m "fix: restore fake xhr compatibility on node 22"