// @vitest-environment happy-dom import { act, createElement } from "react"; import { createRoot, type Root } from "react-dom/client"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { SaveStatus } from "./save-status"; let root: Root; let container: HTMLDivElement; const onSave = vi.fn(); beforeEach(() => { vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true); vi.clearAllMocks(); container = document.createElement("div"); document.body.append(container); root = createRoot(container); }); afterEach(async () => { await act(async () => root.unmount()); container.remove(); vi.unstubAllGlobals(); }); async function render(props: Partial[0]> = {}) { await act(async () => root.render(createElement(SaveStatus, { state: "saved", canSave: false, onSave, ...props }))); } describe("floating SaveStatus", () => { it("keeps Save visible when saved and enables it for unsaved changes", async () => { await render(); expect(container.querySelector("button")?.textContent).toContain("บันทึก"); expect(container.querySelector("button")?.disabled).toBe(true); expect(container.querySelector(".fixed")).not.toBeNull(); await render({ state: "unsaved", canSave: true }); await act(async () => container.querySelector("button")!.click()); expect(onSave).toHaveBeenCalledTimes(1); }); it("shows saving feedback and blocks more save requests", async () => { await render({ state: "saving", canSave: false }); expect(container.querySelector("button")?.textContent).toContain("กำลังบันทึก"); await act(async () => container.querySelector("button")!.click()); expect(onSave).not.toHaveBeenCalled(); }); it("shows validation issues while keeping Save disabled", async () => { await render({ state: "incomplete", issues: ["Missing title"] }); const buttons = container.querySelectorAll("button"); expect(buttons[1].disabled).toBe(true); await act(async () => buttons[0].click()); expect(container.textContent).toContain("Missing title"); expect(buttons[0].getAttribute("aria-expanded")).toBe("true"); }); it("keeps conflict actions available and blocks ordinary Save", async () => { const onReloadLatest = vi.fn(); const onOverwrite = vi.fn(); await render({ state: "conflict", conflictVersion: 8, canOverwrite: true, onReloadLatest, onOverwrite }); const buttons = container.querySelectorAll("button"); await act(async () => { buttons[0].click(); buttons[1].click(); }); expect(onReloadLatest).toHaveBeenCalledTimes(1); expect(onOverwrite).toHaveBeenCalledTimes(1); expect(buttons[2].disabled).toBe(true); }); });