Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"express": "^5.1.0",
"fix-path": "5.0.0",
"ghostty-web": "^0.4.0-next.7.g03ead6e",
"happy-dom": "^20.0.10",
"happy-dom": "20.0.11",
"ignore": "^7.0.5",
"json-schema-to-typescript": "^15.0.4",
"jsonc-parser": "^3.3.1",
Expand Down
29 changes: 29 additions & 0 deletions src/browser/happyDomMutationObserver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { expect, test } from "bun:test";
import { Window } from "happy-dom";

/**
* happy-dom 20.0.11 holds each MutationObserver's report callback only through a WeakRef, so after
* a garbage collection the observer stops reporting without an error (a cause of the #5989
* flake). patches/happy-dom@20.0.11.patch holds it strongly. bun applies that patch only while
* the installed version matches its key, and says nothing when it does not (#6348), so this
* test fails loudly if happy-dom moves to an unpatched version. An upgrade to a version that
* holds the callback upstream (20.11.15 or later) passes without the patch.
*/
test("a happy-dom MutationObserver keeps reporting after a garbage collection", async () => {
const window = new Window();
const target = window.document.createElement("div");
const batches: number[] = [];
const observer = new window.MutationObserver((records) => batches.push(records.length));
observer.observe(target, { childList: true });
try {
// A WeakRef keeps its target alive until the current job ends, so collect after this one.
await new Promise((resolve) => setTimeout(resolve, 0));
Bun.gc(true);
target.appendChild(window.document.createElement("span"));
await new Promise((resolve) => setTimeout(resolve, 10));
expect(batches).toEqual([1]);
} finally {
observer.disconnect();
await window.happyDOM.close();
}
});
Loading