aboutsummaryrefslogtreecommitdiff
path: root/test/js/third_party/react-dom/react-dom.test.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'test/js/third_party/react-dom/react-dom.test.tsx')
-rw-r--r--test/js/third_party/react-dom/react-dom.test.tsx285
1 files changed, 285 insertions, 0 deletions
diff --git a/test/js/third_party/react-dom/react-dom.test.tsx b/test/js/third_party/react-dom/react-dom.test.tsx
new file mode 100644
index 000000000..2f1309fb8
--- /dev/null
+++ b/test/js/third_party/react-dom/react-dom.test.tsx
@@ -0,0 +1,285 @@
+import {
+ concatArrayBuffers,
+ readableStreamToArray,
+ readableStreamToArrayBuffer,
+ readableStreamToBlob,
+ readableStreamToText,
+ serve,
+} from "bun";
+import { heapStats } from "bun:jsc";
+import { describe, expect, it } from "bun:test";
+import { renderToReadableStream as renderToReadableStreamBrowser } from "react-dom/server.browser";
+import { gc } from "harness";
+import { renderToReadableStream as renderToReadableStreamBun } from "./react-dom-server.bun.cjs";
+import React from "react";
+
+Object.defineProperty(renderToReadableStreamBrowser, "name", {
+ value: "server.browser",
+});
+Object.defineProperty(renderToReadableStreamBun, "name", {
+ value: "server.bun",
+});
+var port = 8908;
+
+const fixtures = [
+ // Needs at least six variations
+ // - < 8 chars, latin1
+ // - 8+ chars, latin1
+ // - 16+ chars, latin1
+ // - < 8 chars, utf16
+ // - 8+ chars, utf16
+ // - 16+ chars, utf16
+ ["<a>b</a>", <a>b</a>],
+ ["<span>Hello World!</span>", <span>Hello World!</span>],
+ ["<a></a>", <a />],
+ ["<span>πŸ˜‹</span>", <span>πŸ˜‹</span>],
+ ["<a>πŸ˜‹</a>", <a>πŸ˜‹</a>],
+ ["<span>Hello World! πŸ˜‹</span>", <span>Hello World! πŸ˜‹</span>],
+ [
+ "<span>Hello World!</span>πŸ˜‹",
+ <>
+ <span>Hello World!</span>πŸ˜‹
+ </>,
+ ],
+ [
+ "<span>πŸ˜‹Hello World!</span>",
+ <>
+ <span>πŸ˜‹Hello World!</span>
+ </>,
+ ],
+ ["πŸ˜‹", <>πŸ˜‹</>],
+ ["lπŸ˜‹l", <>lπŸ˜‹l</>],
+ ["loπŸ˜‹", <>loπŸ˜‹</>],
+ ["πŸ˜‹lo", <>πŸ˜‹lo</>],
+ [
+ "πŸ˜‹<span>Hello World!</span>",
+ <>
+ πŸ˜‹
+ <span>Hello World!</span>
+ </>,
+ ],
+ [
+ "πŸ˜‹πŸ˜‹πŸ˜‹πŸ˜‹<span>Hello World!</span>",
+ <>
+ πŸ˜‹πŸ˜‹πŸ˜‹πŸ˜‹
+ <span>Hello World!</span>
+ </>,
+ ],
+ ["<span>HelloπŸ˜‹πŸ˜‹πŸ˜‹πŸ˜‹World!</span>", <span>HelloπŸ˜‹πŸ˜‹πŸ˜‹πŸ˜‹World!</span>],
+ [
+ "<span>Hello World!</span>πŸ˜‹πŸ˜‹πŸ˜‹πŸ˜‹",
+ <>
+ <span>Hello World!</span>
+ πŸ˜‹πŸ˜‹πŸ˜‹πŸ˜‹
+ </>,
+ ],
+ [
+ "πŸ˜‹LπŸ˜‹lπŸ˜‹LπŸ˜‹<span>Alternating latin1 &amp; utf16</span>",
+ <>
+ πŸ˜‹LπŸ˜‹lπŸ˜‹LπŸ˜‹<span>Alternating latin1 &amp; utf16</span>
+ </>,
+ ],
+ ["<span>HelloπŸ˜‹LπŸ˜‹lπŸ˜‹LπŸ˜‹World!</span>", <span>HelloπŸ˜‹LπŸ˜‹lπŸ˜‹LπŸ˜‹World!</span>],
+ [
+ "<span>Hello World!</span>πŸ˜‹LπŸ˜‹lπŸ˜‹LπŸ˜‹",
+ <>
+ <span>Hello World!</span>
+ πŸ˜‹LπŸ˜‹lπŸ˜‹LπŸ˜‹
+ </>,
+ ],
+];
+
+describe("React", () => {
+ it("React.createContext works", () => {
+ expect(typeof React.createContext).toBe("function");
+ const pleaseDontThrow = React.createContext({ foo: true });
+ expect((pleaseDontThrow as any).$$typeof.description).toBe("react.context");
+
+ const pleaseDontThrow2 = (React as any).default.createContext({
+ foo: true,
+ });
+ expect(pleaseDontThrow2.$$typeof.description).toBe("react.context");
+ });
+});
+
+describe("ReactDOM", () => {
+ for (let renderToReadableStream of [renderToReadableStreamBun, renderToReadableStreamBrowser]) {
+ for (let [inputString, reactElement] of fixtures) {
+ describe(`${renderToReadableStream.name}(${inputString})`, () => {
+ it("Response.text()", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const response = new Response(stream);
+ gc();
+ try {
+ const text = await response.text();
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ } catch (e: any) {
+ console.log(e.stack);
+ throw e;
+ }
+ });
+ it("Response.arrayBuffer()", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const response = new Response(stream);
+ gc();
+ const text = new TextDecoder().decode(await response.arrayBuffer());
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ });
+ it("Response.blob()", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const response = new Response(stream);
+ gc();
+ const text = await (await response.blob()).text();
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ });
+ it("readableStreamToText(stream)", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const text = await readableStreamToText(stream);
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ });
+ it("readableStreamToBlob(stream)", async () => {
+ try {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const blob = await readableStreamToBlob(stream);
+ const text = await blob.text();
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ } catch (e: any) {
+ console.error(e.message);
+ console.error(e.stack);
+ throw e;
+ }
+ });
+ it("readableStreamToArray(stream)", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const array = await readableStreamToArray(stream);
+ const text =
+ renderToReadableStream === renderToReadableStreamBun
+ ? array.join("")
+ : new TextDecoder().decode(concatArrayBuffers(array as any[]));
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ });
+ it("readableStreamToArrayBuffer(stream)", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const arrayBuffer = await readableStreamToArrayBuffer(stream);
+ const text = new TextDecoder().decode(arrayBuffer);
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ });
+ it("for await (chunk of stream)", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const chunks: any = [];
+ for await (let chunk of stream) {
+ chunks.push(chunk);
+ }
+ const text = await new Response(chunks).text();
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ });
+
+ it("for await (chunk of stream) (arrayBuffer)", async () => {
+ const stream = await renderToReadableStream(reactElement);
+ gc();
+ const chunks: any[] = [];
+ for await (let chunk of stream) {
+ chunks.push(chunk);
+ }
+ const text = new TextDecoder().decode(await new Response(chunks as any).arrayBuffer());
+ gc();
+ expect(text.replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ });
+ });
+ }
+ }
+ for (let renderToReadableStream of [renderToReadableStreamBun, renderToReadableStreamBrowser]) {
+ // there is an event loop bug that causes deadlocks
+ // the bug is with `fetch`, not with the HTTP server
+ for (let [inputString, reactElement] of fixtures) {
+ describe(`${renderToReadableStream.name}(${inputString})`, () => {
+ it("http server, 1 request", async () => {
+ await (async function () {
+ var server;
+ try {
+ server = serve({
+ port: port++,
+ async fetch(req) {
+ return new Response(await renderToReadableStream(reactElement));
+ },
+ });
+ const resp = await fetch("http://localhost:" + server.port + "/");
+ expect((await resp.text()).replaceAll("<!-- -->", "")).toBe(inputString);
+ gc();
+ } catch (e) {
+ throw e;
+ } finally {
+ server?.stop();
+ gc();
+ }
+ })();
+ gc();
+ expect(heapStats().objectTypeCounts.ReadableHTTPResponseSinkController ?? 0).toBe(1);
+ });
+ const count = 4;
+ it(`http server, ${count} requests`, async () => {
+ var remain = count;
+ await (async function () {
+ var server;
+ try {
+ server = serve({
+ port: port++,
+ async fetch(req) {
+ return new Response(await renderToReadableStream(reactElement));
+ },
+ });
+ gc();
+ while (remain--) {
+ var attempt = remain + 1;
+ const response = await fetch("http://localhost:" + server.port + "/");
+ gc();
+ const result = await response.text();
+ try {
+ expect(result.replaceAll("<!-- -->", "")).toBe(inputString);
+ } catch (e: any) {
+ e.message += "\nAttempt: " + attempt;
+ throw e;
+ }
+
+ gc();
+ }
+ } catch (e) {
+ throw e;
+ } finally {
+ server.stop();
+ }
+ })();
+
+ const { ReadableHTTPResponseSinkController = 0 } = heapStats().objectTypeCounts;
+ expect(ReadableHTTPResponseSinkController).toBe(1);
+ expect(remain + 1).toBe(0);
+ });
+ });
+ }
+ }
+});