Issue 194 HTML Document Support Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Fix FakeXMLHttpRequest so responseType = "document" supports Content-Type: text/html when a native DOMParser is present, while preserving the existing XML-only fallback behavior when no parser is available.
Architecture: Keep the change inside the fake XHR response-conversion path. XML content types should continue to use FakeXMLHttpRequest.parseXML, and text/html should take a separate native-parser branch that returns null if DOMParser is unavailable. Tests should exercise both the HTML success case and the no-parser null case without introducing new dependencies.
Tech Stack: Node.js, Mocha, jsdom, proxyquire, nise fake XHR implementation
Task 1: Reproduce the missing HTML document behavior
Files:
- Modify: lib/fake-xhr/index.test.js
- Test: lib/fake-xhr/index.test.js
Step 1: Add a focused failing test for HTML document responses
Add a test near the existing .response or .responseXML coverage:
it("parses HTML for responseType document when Content-Type is text/html", function () {
this.xhr.responseType = "document";
this.xhr.open("GET", "/");
this.xhr.send();
this.xhr.respond(
200,
{ "Content-Type": "text/html" },
"<!doctype html><html><body><main><h1>Hola!</h1></main></body></html>",
);
var doc = this.xhr.response;
assert.equals(doc.documentElement.tagName, "HTML");
assert.equals(doc.getElementsByTagName("h1")[0].textContent, "Hola!");
});
Step 2: Run the focused test to verify it fails
Run: npm test -- --grep "parses HTML for responseType document when Content-Type is text/html"
Expected: FAIL because the current document branch returns null for text/html.
Step 3: Add a no-parser expectation test
Add a second focused test:
it("returns null for HTML document responses when DOMParser is unavailable", function () {
this.xhr.responseType = "document";
this.xhr.open("GET", "/");
this.xhr.send();
delete global.DOMParser;
this.xhr.respond(
200,
{ "Content-Type": "text/html" },
"<!doctype html><html><body><h1>Hola!</h1></body></html>",
);
assert.isNull(this.xhr.response);
});
Restore global.DOMParser inside the test or in a try/finally block so later tests are unaffected.
Step 4: Run the focused no-parser test
Run: npm test -- --grep "returns null for HTML document responses when DOMParser is unavailable"
Expected: PASS after the test is written, because the current implementation already returns null for non-XML content.
Step 5: Commit
git add lib/fake-xhr/index.test.js
git commit -m "test: reproduce missing html document response support"
Task 2: Implement native HTML document parsing
Files:
- Modify: lib/fake-xhr/index.js
- Test: lib/fake-xhr/index.test.js
Step 1: Add a narrow content-type helper if it improves readability
If needed, add a helper like:
function isHtmlContentType(contentType) {
return /text\/html/i.test(contentType || "");
}
Keep it specific to text/html. Do not broaden to all HTML-like MIME types unless the browser behavior is verified and intentionally in scope.
Step 2: Add a native HTML parsing helper or inline branch
Use one of these minimal shapes:
function parseHTML(text) {
if (text === "" || typeof DOMParser === "undefined") {
return null;
}
return new DOMParser().parseFromString(text, "text/html");
}
or inline the same logic directly inside convertResponseBody.
Step 3: Update convertResponseBody for responseType === "document"
Change the existing branch from:
} else if (responseType === "document") {
if (isXmlContentType(contentType)) {
return FakeXMLHttpRequest.parseXML(body);
}
return null;
}
to logic equivalent to:
} else if (responseType === "document") {
if (isXmlContentType(contentType)) {
return FakeXMLHttpRequest.parseXML(body);
}
if (isHtmlContentType(contentType)) {
return parseHTML(body);
}
return null;
}
Keep XML precedence unchanged.
Step 4: Run the focused HTML tests
Run: npm test -- --grep "HTML document responses|responseType document when Content-Type is text/html"
Expected: both focused HTML tests PASS.
Step 5: Commit
git add lib/fake-xhr/index.js lib/fake-xhr/index.test.js
git commit -m "fix: support html documents for fake xhr responseType"
Task 3: Add regression coverage around existing document behavior
Files:
- Modify: lib/fake-xhr/index.test.js
- Test: lib/fake-xhr/index.test.js
Step 1: Verify the new tests live with the existing document coverage
Place the HTML tests near the current .response and .responseXML cases so future changes to document parsing are reviewed together.
Step 2: Add one assertion that XML behavior is still routed to XML parsing
If current coverage is not explicit enough for the responseType = "document" path, add:
it("still parses XML for responseType document with application/xml", function () {
this.xhr.responseType = "document";
this.xhr.open("GET", "/");
this.xhr.send();
this.xhr.respond(
200,
{ "Content-Type": "application/xml" },
"<root><item>Hola!</item></root>",
);
assert.equals(
this.xhr.response.getElementsByTagName("item")[0].textContent,
"Hola!",
);
});
Add this only if the existing tests do not already pin the responseType = "document" XML case tightly enough.
Step 3: Run the document-focused subset
Run: npm test -- --grep "responseXML|responseType document"
Expected: PASS
Step 4: Commit
git add lib/fake-xhr/index.test.js
git commit -m "test: cover fake xhr document response parsing"
Task 4: Verify the full fake XHR suite
Files:
- 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 control flow or helpers changed
Run: npm run lint
Expected: PASS
Step 4: Inspect the final diff
Run: git diff --stat
Expected: only lib/fake-xhr/index.js, lib/fake-xhr/index.test.js, and the plan docs changed.
Step 5: Commit
git add lib/fake-xhr/index.js lib/fake-xhr/index.test.js docs/plans/2026-03-03-issue-194-html-document-support*.md
git commit -m "fix: add html document support to fake xhr"