// @vitest-environment happy-dom
import { act, cleanup, fireEvent, render } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { CLOSE_DRAWER_EVENT, OPEN_SPAWN_EVENT, SPAWN_SIMILAR_EVENT } from "../../uiEvents.js";
import { TOGGLE_DRAWER_EVENT } from "../../uiEvents.js";
import { Drawer } from "./Drawer.js";
/** Force the mobile media query on, whatever happy-dom's viewport says
* (mirrors ../layout/MultiView's own `forceMobile` in multiview.test.ts). */
function forceMobile(matches: boolean): void {
vi.spyOn(window, "matchMedia").mockImplementation(
(query: string) =>
({
matches: query.includes("859") && matches,
media: query,
onchange: null,
addEventListener() {},
removeEventListener() {},
addListener() {},
removeListener() {},
dispatchEvent: () => false,
}) as unknown as MediaQueryList,
);
}
function shell(): HTMLElement {
return document.querySelector(".app-shell") as HTMLElement;
}
function touch(type: "touchstart" | "touchend", x: number, y: number): void {
const touches = [{ clientX: x, clientY: y }];
const event = new Event(type, { bubbles: true }) as unknown as {
touches: typeof touches;
changedTouches: typeof touches;
};
event.touches = touches;
event.changedTouches = touches;
act(() => {
document.dispatchEvent(event as unknown as Event);
});
}
beforeEach(() => forceMobile(true));
afterEach(() => {
cleanup();
vi.restoreAllMocks();
});
function openViaToggle(): void {
act(() => {
document.dispatchEvent(new CustomEvent(TOGGLE_DRAWER_EVENT));
});
}
describe("Drawer (#35)", () => {
it("toggles open on the toggle event, off on desktop by class alone", () => {
render(
row}>
content
,
);
expect(shell().classList.contains("drawer-open")).toBe(false);
openViaToggle();
expect(shell().classList.contains("drawer-open")).toBe(true);
});
it("closes when a session row is tapped", () => {
render(
row}>
content
,
);
openViaToggle();
fireEvent.click(document.querySelector(".tree-leaf") as HTMLElement);
expect(shell().classList.contains("drawer-open")).toBe(false);
});
it("closes when a spawn is requested", () => {
render(
row}>
content
,
);
openViaToggle();
act(() => {
document.dispatchEvent(new CustomEvent(OPEN_SPAWN_EVENT));
});
expect(shell().classList.contains("drawer-open")).toBe(false);
});
it("closes when spawn similar is requested", () => {
render(
row}>
content
,
);
openViaToggle();
act(() => {
document.dispatchEvent(new CustomEvent(SPAWN_SIMILAR_EVENT, { detail: {} }));
});
expect(shell().classList.contains("drawer-open")).toBe(false);
});
it("closes on the close-drawer event (after spawn lands)", () => {
render(
row}>
content
,
);
openViaToggle();
act(() => {
document.dispatchEvent(new CustomEvent(CLOSE_DRAWER_EVENT));
});
expect(shell().classList.contains("drawer-open")).toBe(false);
});
it("closes on a backdrop click", () => {
render(
row}>
content
,
);
openViaToggle();
fireEvent.click(document.querySelector(".mv-backdrop") as HTMLElement);
expect(shell().classList.contains("drawer-open")).toBe(false);
});
it("opens on a rightward swipe and closes on a leftward one, only on mobile", () => {
render(
row}>
content
,
);
touch("touchstart", 0, 100);
touch("touchend", 100, 100);
expect(shell().classList.contains("drawer-open")).toBe(true);
touch("touchstart", 100, 100);
touch("touchend", 0, 100);
expect(shell().classList.contains("drawer-open")).toBe(false);
});
it("ignores swipes on desktop", () => {
forceMobile(false);
render(
row}>
content
,
);
touch("touchstart", 0, 100);
touch("touchend", 100, 100);
expect(shell().classList.contains("drawer-open")).toBe(false);
});
it("ignores a mostly-vertical or too-short gesture", () => {
render(
row}>
content
,
);
touch("touchstart", 0, 0);
touch("touchend", 10, 100);
expect(shell().classList.contains("drawer-open")).toBe(false);
});
});