Issue 243 Text Encoder Dependency Removal Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Remove @sinonjs/text-encoding from fake XHR response handling by replacing its lone TextEncoder usage with a small dependency-free UTF-8 helper, while preserving current arraybuffer and blob behavior.
Architecture: Keep the change local to the fake XHR response conversion path in lib/fake-xhr/index.js. String response bodies should always be encoded as UTF-8, ArrayBuffer inputs should still pass through unchanged, and tests should assert exact byte output without depending on the deprecated polyfill.
Tech Stack: Node.js, Mocha, referee, browserify, nise fake XHR implementation
Task 1: Reproduce and pin the current string-to-buffer behavior
Files:
- Modify: lib/fake-xhr/index.test.js
- Test: lib/fake-xhr/index.test.js
Step 1: Add a focused failing test for UTF-8 arraybuffer conversion
Add a test near the existing responseType === "arraybuffer" coverage that asserts exact UTF-8 bytes for a non-ASCII string without using TextEncoder.
it("encodes string responses as utf-8 arraybuffers", function () {
this.xhr.responseType = "arraybuffer";
this.xhr.open("GET", "/");
this.xhr.send();
this.xhr.respond(
200,
{ "Content-Type": "application/octet-stream" },
"\xFF",
);
assertArrayBufferMatches(
this.xhr.response,
new Uint8Array([0xc3, 0xbf]).buffer,
);
});
Step 2: Run the focused test to verify it passes before refactoring
Run: npm test -- --grep "encodes string responses as utf-8 arraybuffers"
Expected: PASS on the current branch, proving the existing behavior is already UTF-8.
Step 3: Add a narrow regression test for ASCII strings if the current suite is not explicit enough
it("encodes ascii string responses as identical byte values", function () {
this.xhr.responseType = "arraybuffer";
this.xhr.open("GET", "/");
this.xhr.send();
this.xhr.respond(
200,
{ "Content-Type": "application/octet-stream" },
"a test buffer",
);
assertArrayBufferMatches(
this.xhr.response,
new Uint8Array([
97, 32, 116, 101, 115, 116, 32, 98, 117, 102, 102, 101, 114,
]).buffer,
);
});
Step 4: Run the focused ASCII test
Run: npm test -- --grep "encodes ascii string responses as identical byte values"
Expected: PASS
Step 5: Commit
git add lib/fake-xhr/index.test.js
git commit -m "test: pin utf8 arraybuffer response behavior"
Task 2: Replace the deprecated TextEncoder dependency with a local helper
Files:
- Modify: lib/fake-xhr/index.js
- Test: lib/fake-xhr/index.test.js
Step 1: Write a failing unit-level regression around the old dependency seam
If Task 1 does not already give enough protection, add a test that exercises a code path which previously used GlobalTextEncoder indirectly through respond(..., "string body").
it("does not require an external text-encoding polyfill for string bodies", function () {
this.xhr.responseType = "arraybuffer";
this.xhr.open("GET", "/");
this.xhr.send();
this.xhr.respond(200, {}, "hola");
assertArrayBufferMatches(
this.xhr.response,
new Uint8Array([104, 111, 108, 97]).buffer,
);
});
Step 2: Implement a narrow UTF-8 helper in lib/fake-xhr/index.js
Remove the top-level GlobalTextEncoder fallback and replace it with a local helper. Keep it intentionally UTF-8-only.
Example direction:
function stringToUtf8ArrayBuffer(input) {
return Uint8Array.from(Buffer.from(input, "utf8")).buffer;
}
If Buffer is not acceptable for browser-facing code paths, use a small pure-JS UTF-8 encoder instead. In either case, the helper should not accept an encoding parameter.
Step 3: Simplify convertToArrayBuffer
Change it from:
function convertToArrayBuffer(body, encoding) {
if (body instanceof ArrayBuffer) {
return body;
}
return new GlobalTextEncoder(encoding || "utf-8").encode(body).buffer;
}
to logic equivalent to:
function convertToArrayBuffer(body) {
if (body instanceof ArrayBuffer) {
return body;
}
return stringToUtf8ArrayBuffer(body);
}
Do not preserve the unused encoding parameter.
Step 4: Run the focused arraybuffer tests
Run: npm test -- --grep "arraybuffer|utf-8|utf8"
Expected: PASS
Step 5: Commit
git add lib/fake-xhr/index.js lib/fake-xhr/index.test.js
git commit -m "fix: replace deprecated text encoder dependency"
Task 3: Remove the package dependency and update generated artifacts
Files:
- Modify: package.json
- Modify: package-lock.json
- Modify: nise.js
Step 1: Remove @sinonjs/text-encoding from runtime dependencies
Delete the dependency entry from package.json.
Step 2: Refresh the lockfile
Run: npm install
Expected: package-lock.json no longer contains @sinonjs/text-encoding.
Step 3: Rebuild the browser bundle
Run: npm run bundle
Expected: nise.js rebuilds successfully without references to the removed dependency.
Step 4: Verify the dependency is fully gone
Run: rg -n "@sinonjs/text-encoding|GlobalTextEncoder|new TextEncoder\\(" .
Expected: no remaining production references; only historical mention may remain in the plan docs.
Step 5: Commit
git add package.json package-lock.json nise.js
git commit -m "build: remove text-encoding dependency"
Task 4: Verify blob and binary regressions
Files:
- Test: lib/fake-xhr/index.test.js
Step 1: Run the full 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 headless browser tests because the removed dependency affected bundled code
Run: npm run test-headless
Expected: PASS
Step 4: Run lint if helper code changed control flow or globals
Run: npm run lint
Expected: PASS
Step 5: Inspect the final diff
Run: git diff --stat
Expected: changes limited to lib/fake-xhr/index.js, lib/fake-xhr/index.test.js, package.json, package-lock.json, nise.js, and the plan docs.
Task 5: Final review and merge readiness
Files:
- Modify: docs/plans/2026-03-03-issue-243-text-encoder-design.md
- Modify: docs/plans/2026-03-03-issue-243-text-encoder.md
Step 1: Review the implementation against issue #243 comments
Confirm the finished patch satisfies the useful parts of the issue discussion:
- deprecated dependency removed;
- no new runtime dependency introduced;
- UTF-8-only behavior made explicit;
- no unnecessary
TextDecoderwork added.
Step 2: Summarize any intentional non-goals in the PR description
Include a short note that the fix does not add non-UTF-8 support because the old implementation never truly supported it either.
Step 3: Prepare a concise verification summary
Capture the exact commands and results:
npm test
npm run test-headless
npm run lint
npm run bundle
Step 4: Commit the plan docs if they changed during execution notes
git add docs/plans/2026-03-03-issue-243-text-encoder-design.md docs/plans/2026-03-03-issue-243-text-encoder.md
git commit -m "docs: add issue 243 implementation plan"