commit d426a99c39ef5aa2e23e11d241545413abad1460
parent a915e2d4a2d2400e65d5c1b5aa17277d5b346d29
Author: Noam Rosenthal <nrosenthal@chromium.org>
Date: Thu, 11 Dec 2025 09:28:00 +0000
Bug 2005015 [wpt PR 56604] - Implement streamHTMLUnsafe, a=testonly
Automatic update from web-platform-tests
Implement streamHTMLUnsafe
This is basically streamAppendHTMLUnsafe + RemoveChildren.
Bug: 431374376
Change-Id: Ic6a8a755dbed60889b6870cc624a0719a4976f36
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7242324
Reviewed-by: Philip Jägenstedt <foolip@chromium.org>
Commit-Queue: Noam Rosenthal <nrosenthal@google.com>
Cr-Commit-Position: refs/heads/main@{#1556213}
--
wpt-commits: 350010a8552a7b309772cf241f269d84971e6f67
wpt-pr: 56604
Diffstat:
1 file changed, 172 insertions(+), 0 deletions(-)
diff --git a/testing/web-platform/tests/html/dom/partial-updates/tentative/stream-html-unsafe.html b/testing/web-platform/tests/html/dom/partial-updates/tentative/stream-html-unsafe.html
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8" />
+<title>HTML partial updates - streamHTMLUnsafe</title>
+<link rel=help href="https://github.com/WICG/declarative-partial-updates">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style id="style"></style>
+<p id="target"></p>
+<script>
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "A";
+ const writable = placeholder.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "node.streamHTMLUnsafe() returns a writable stream");
+ const response = new Response("<span>B</span>", {headers: {"Content-Type": "text/html"}});
+ await response.body.pipeThrough(new TextDecoderStream()).pipeTo(writable);
+ assert_equals(placeholder.textContent, "B");
+ assert_true(response.bodyUsed);
+}, "piping a response into streamHTMLUnsafe()");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "<span>A</span>";
+ const writable = placeholder.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "node.streamHTMLUnsafe() returns a writable stream");
+ const writer = writable.getWriter();
+ await writer.write("B");
+ await writer.close();
+ assert_equals(placeholder.textContent, "B");
+}, "writing a string to streamHTMLUnsafe()");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "<span>A</span>";
+ const writable = placeholder.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "node.streamHTMLUnsafe() returns a writable stream");
+ assert_equals(placeholder.textContent, "");
+ const writer = writable.getWriter();
+ await writer.write("B");
+ await writer.close();
+ assert_equals(placeholder.textContent, "B");
+}, "streamHTMLUnsafe() should remove existing content immediately");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "<span>A</span>";
+ const writable = placeholder.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "node.streamHTMLUnsafe() returns a writable stream");
+ const writer = writable.getWriter();
+ await writer.write("<span>B</span>");
+ assert_equals(placeholder.textContent, "B");
+ await writer.close();
+}, "streamHTMLUnsafe() does not buffer until close()");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "Before";
+ const writable = placeholder.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "streamHTMLUnsafe() returns a writable stream");
+ const writer = writable.getWriter();
+ await promise_rejects_js(t, TypeError, writer.write(Symbol("sym")));
+ assert_equals(placeholder.textContent, "");
+}, "writing a Symbol to streamHTMLUnsafe()");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "12";
+ const writable = placeholder.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "node.streamHTMLUnsafe() returns a writable stream");
+ const writer = writable.getWriter();
+ await writer.write(345);
+ await writer.close();
+ assert_equals(placeholder.textContent, "345");
+ assert_equals(placeholder.childNodes.length, 1);
+ assert_equals(placeholder.firstChild.nodeType, Node.TEXT_NODE);
+ assert_equals(placeholder.firstChild.textContent, "345");
+}, "writing numbers to streamHTMLUnsafe()");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "start ";
+ const writable = placeholder.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "node.streamHTMLUnsafe() returns a writable stream");
+ const writer = writable.getWriter();
+ await writer.write(null);
+ await writer.write(" ");
+ await writer.write(undefined);
+ await writer.close();
+ assert_equals(placeholder.textContent, "null undefined");
+}, "writing null or undefined to streamHTMLUnsafe()");
+
+promise_test(async t => {
+ const style = document.querySelector("#style");
+ const writable = style.streamHTMLUnsafe();
+ assert_true(writable instanceof WritableStream, "node.streamHTMLUnsafe() returns a writable stream");
+ const writer = await writable.getWriter();
+ await writer.write("#target { color: rgba(100, 0, 100); }");
+ await writer.close();
+ assert_equals(getComputedStyle(document.querySelector("#target")).color, "rgb(100, 0, 100)");
+}, "streamHTMLUnsafe() can stream into <style>");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "start ";
+ const writable = placeholder.streamHTMLUnsafe();
+ const writer = writable.getWriter();
+ await writer.write("ABC");
+ await writer.abort("abort-reason");
+ await writer.write("DEF").catch(() => {});
+ assert_equals(placeholder.textContent, "ABC");
+}, "Aborting streamHTMLUnsafe()");
+
+promise_test(async t => {
+ const placeholder = document.createElement("div");
+ placeholder.innerHTML = "before";
+ const writer1 = placeholder.streamHTMLUnsafe().getWriter();
+ const writer2 = placeholder.streamHTMLUnsafe().getWriter();
+ await writer1.write("<span>A</span>");
+ await writer2.write("<span>B</span>");
+ await new Promise(resolve => requestAnimationFrame(resolve));
+ await writer1.write("C");
+ await writer1.close();
+ await writer2.close();
+ assert_equals(placeholder.textContent, "ABC");
+}, "Interleaved streamHTMLUnsafe() writes");
+
+promise_test(async t => {
+ const element = document.createElement("div");
+ const shadowRoot = element.attachShadow({mode: "open"});
+ shadowRoot.innerHTML = "before";
+ const writer = shadowRoot.streamHTMLUnsafe().getWriter();
+ await writer.write("<div id=added>A</div>");
+ assert_equals(shadowRoot.getElementById("added").textContent, "A");
+}, "streamHTMLUnsafe into a ShadowRoot");
+
+promise_test(async t => {
+ const element = document.createElement("template");
+ element.innerHTML = "before";
+ const writer = element.streamHTMLUnsafe().getWriter();
+ await writer.write("<div id=added>A</div>");
+ assert_equals(element.content.getElementById("added").textContent, "A");
+}, "streamHTMLUnsafe into a template");
+
+promise_test(async t => {
+ const element = document.createElement("div");
+ document.body.append(element);
+ window.did_eval_script = false;
+ const writer = element.streamHTMLUnsafe().getWriter();
+ assert_false(window.did_eval_script);
+ await writer.write("<script>window.did_eval_script = true;");
+ assert_false(window.did_eval_script);
+ await writer.write("<");
+ assert_false(window.did_eval_script);
+ await writer.write("/script>");
+ assert_true(window.did_eval_script);
+}, "streamHTMLUnsafe should execute scripts when connected");
+
+promise_test(async t => {
+ const element = document.createElement("div");
+ window.did_eval_script = false;
+ const writer = element.streamHTMLUnsafe().getWriter();
+ assert_false(window.did_eval_script);
+ await writer.write("<script>window.did_eval_script = true;");
+ assert_false(window.did_eval_script);
+ await writer.write("<");
+ assert_false(window.did_eval_script);
+ await writer.write("/script>");
+ assert_false(window.did_eval_script);
+}, "streamHTMLUnsafe should not execute scripts when disconnected");
+</script>
+\ No newline at end of file