From 64937b1d8992e661b8ca194e927946ac36f73793 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Mon, 1 Jun 2026 16:00:27 +0200 Subject: [PATCH] fix(core): add editor cleanup in BlockNoteEditor.test.ts to prevent unhandled DOMObserver errors Tests that mount editors were not calling unmount() afterward, leaving ProseMirror's DOMObserver timers active. When prosemirror-view is updated to newer versions (e.g. 1.41.8 via fresh dep resolution), a dangling setTimeout in DOMObserver.flush() fires after jsdom teardown, causing 'document is not defined' ReferenceError. Add afterEach cleanup following the same pattern as transformPasted.test.ts. --- .../core/src/editor/BlockNoteEditor.test.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/core/src/editor/BlockNoteEditor.test.ts b/packages/core/src/editor/BlockNoteEditor.test.ts index 6a4f5f023e..a6ca022e03 100644 --- a/packages/core/src/editor/BlockNoteEditor.test.ts +++ b/packages/core/src/editor/BlockNoteEditor.test.ts @@ -1,4 +1,4 @@ -import { expect, it } from "vitest"; +import { afterEach, expect, it } from "vitest"; import * as Y from "yjs"; import { @@ -11,8 +11,19 @@ import { BlocksChanged } from "../api/getBlocksChangedByTransaction.js"; /** * @vitest-environment jsdom */ + +const editorsToCleanup: BlockNoteEditor[] = []; + +afterEach(() => { + for (const editor of editorsToCleanup) { + editor.unmount(); + } + editorsToCleanup.length = 0; +}); + it("creates an editor", () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); const posInfo = editor.transact((tr) => getNearestBlockPos(tr.doc, 2)); const info = getBlockInfo(posInfo); expect(info.blockNoteType).toEqual("paragraph"); @@ -20,6 +31,7 @@ it("creates an editor", () => { it("immediately replaces doc", async () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); const blocks = await editor.tryParseMarkdownToBlocks( "This is a normal text\n\n# And this is a large heading", ); @@ -70,6 +82,7 @@ it("adds id attribute when requested", async () => { const editor = BlockNoteEditor.create({ setIdAttribute: true, }); + editorsToCleanup.push(editor); const blocks = await editor.tryParseMarkdownToBlocks( "This is a normal text\n\n# And this is a large heading", ); @@ -81,6 +94,7 @@ it("adds id attribute when requested", async () => { it("updates block", () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); editor.updateBlock(editor.document[0], { content: "hello", }); @@ -89,6 +103,7 @@ it("updates block", () => { it("block prop types", () => { // this test checks whether the block props are correctly typed in typescript const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); const block = editor.document[0]; if (block.type === "paragraph") { // @ts-expect-error @@ -108,6 +123,7 @@ it("block prop types", () => { it("onMount and onUnmount", async () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); let mounted = false; let unmounted = false; editor.onMount(() => { @@ -143,6 +159,7 @@ it("sets an initial block id when using Y.js", async () => { }, }, }); + editorsToCleanup.push(editor); editor.mount(document.createElement("div")); @@ -193,6 +210,7 @@ it("sets an initial block id when using Y.js", async () => { it("onBeforeChange", () => { const editor = BlockNoteEditor.create(); + editorsToCleanup.push(editor); let beforeChangeCalled = false; let changes: BlocksChanged = []; editor.onBeforeChange(({ getChanges }) => {