import { afterAll, describe, expect, test } from "bun:test";
import { GlobalRegistrator } from "@happy-dom/global-registrator";
import { act, useState } from "react";
import type { Root } from "react-dom/client";
// Radix picks its layout-effect hook when it is first imported, so the DOM
// has to exist before the sheet's modules load; otherwise portals never mount.
GlobalRegistrator.register();
(globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT =
true;
const { createRoot } = await import("react-dom/client");
const { renderToStaticMarkup } = await import("react-dom/server");
const {
DetailBody,
DetailFooterConfirm,
DetailHeader,
DetailSheet,
DetailSheetContent,
DetailSheetPreview,
} = await import("./detail-sheet");
afterAll(() => {
GlobalRegistrator.unregister();
});
async function mount(node: React.ReactNode): Promise<{ container: HTMLElement; root: Root }> {
const container = document.createElement("div");
document.body.append(container);
const root = createRoot(container);
await act(async () => {
root.render(node);
});
return { container, root };
}
function RowOpensSheet() {
const [open, setOpen] = useState(false);
return (
<>
Variables
>
);
}
describe("DetailSheet", () => {
test("opened from a row without a trigger, it lands on the sheet and gives focus back on close", async () => {
const { container, root } = await mount();
const row = container.querySelector('[data-testid="row"]')!;
row.focus();
await act(async () => row.click());
const sheet = document.querySelector('[data-slot="detail-sheet"]');
expect(sheet).not.toBeNull();
expect(document.activeElement).toBe(sheet);
await act(async () => {
document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }));
});
await act(async () => new Promise((resolve) => setTimeout(resolve, 10)));
expect(document.querySelector('[data-slot="detail-sheet"]')).toBeNull();
expect(document.activeElement).toBe(row);
await act(async () => root.unmount());
container.remove();
});
test("the footer confirm names the object and ties the consequence to the question", () => {
const html = renderToStaticMarkup(
,
);
const container = document.createElement("div");
container.innerHTML = html;
const group = container.querySelector('[role="group"]')!;
const title = container.querySelector(`[id="${group.getAttribute("aria-labelledby")}"]`);
const description = container.querySelector(`[id="${group.getAttribute("aria-describedby")}"]`);
expect(title?.textContent).toBe("Disconnect ops@acme.dev?");
expect(description?.textContent).toBe("New work moves to research@acme.dev.");
const buttons = [...container.querySelectorAll("button")].map((button) => button.textContent);
expect(buttons).toEqual(["Cancel", "Disconnect"]);
// Previews never steal focus from the page.
expect(html).not.toContain("autofocus");
});
});