summaryrefslogtreecommitdiffhomepage
path: root/src/adapters/portal.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/adapters/portal.test.ts')
-rw-r--r--src/adapters/portal.test.ts49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/adapters/portal.test.ts b/src/adapters/portal.test.ts
new file mode 100644
index 0000000..a5624d5
--- /dev/null
+++ b/src/adapters/portal.test.ts
@@ -0,0 +1,49 @@
+import { afterEach, describe, expect, it } from "vitest";
+import { portal } from "./portal";
+
+describe("portal action", () => {
+ afterEach(() => {
+ // Strip any leftover teleported nodes between tests.
+ document.querySelectorAll("body > :not(script)").forEach((n) => {
+ if (n instanceof HTMLElement) n.remove();
+ });
+ });
+
+ it("teleports the node to document.body (escaping an ancestor with transform)", () => {
+ // Simulate the sidebar: a transformed ancestor establishes a containing
+ // block for `position: fixed`.
+ const ancestor = document.createElement("div");
+ ancestor.style.transform = "translateX(0)";
+ document.body.appendChild(ancestor);
+
+ const node = document.createElement("div");
+ node.setAttribute("data-testid", "modal");
+ ancestor.appendChild(node);
+ expect(node.parentNode).toBe(ancestor);
+
+ const action = portal(node);
+
+ // After the action, the node is a direct child of <body>, not the ancestor.
+ expect(node.parentNode).toBe(document.body);
+ expect(ancestor.contains(node)).toBe(false);
+
+ action.destroy();
+
+ // On destroy the node is removed from <body>.
+ expect(document.body.contains(node)).toBe(false);
+ });
+
+ it("is a no-op (does not throw) when document is unavailable (SSR guard)", () => {
+ const originalDocument = globalThis.document;
+ // @ts-expect-error — deliberately undefined to exercise the SSR guard.
+ globalThis.document = undefined;
+ try {
+ const stub = {} as HTMLElement;
+ const action = portal(stub);
+ // Must not throw, and returns a destroy that is safe to call.
+ action.destroy();
+ } finally {
+ globalThis.document = originalDocument;
+ }
+ });
+});