// @vitest-environment jsdom import { beforeEach, describe, expect, test } from "vitest"; import { promptForFavoriteFolderName } from "../src/content/market/favorite-folder-dialog"; function readDialog(): HTMLElement { const dialog = document.querySelector( '[data-sces-favorite-folder-dialog="root"]' ); if (!(dialog instanceof HTMLElement)) { throw new Error("Expected favorite folder dialog"); } return dialog; } function readInput(): HTMLInputElement { const input = document.querySelector( '[data-sces-favorite-folder-dialog="input"]' ); if (!(input instanceof HTMLInputElement)) { throw new Error("Expected favorite folder name input"); } return input; } function readButton(name: "confirm" | "cancel"): HTMLButtonElement { const button = document.querySelector( `[data-sces-favorite-folder-dialog="${name}"]` ); if (!(button instanceof HTMLButtonElement)) { throw new Error(`Expected ${name} button`); } return button; } describe("favorite-folder-dialog", () => { beforeEach(() => { document.body.innerHTML = ""; }); test("renders the requested title and initial name, then trims a confirmation", async () => { const result = promptForFavoriteFolderName(document, { initialValue: " 重点合作 ", title: "重命名收藏夹" }); expect(readDialog().getAttribute("role")).toBe("dialog"); expect(readDialog().textContent).toContain("重命名收藏夹"); expect(readInput().value).toBe(" 重点合作 "); expect(document.activeElement).toBe(readInput()); readButton("confirm").click(); await expect(result).resolves.toBe("重点合作"); expect( document.querySelector('[data-sces-favorite-folder-dialog="root"]') ).toBeNull(); }); test("keeps an inline error open for blank names and clears it after input", async () => { const result = promptForFavoriteFolderName(document, { title: "新建收藏夹" }); readInput().value = " "; readButton("confirm").click(); expect( document.querySelector('[data-sces-favorite-folder-dialog="error"]')?.textContent ).toBe("请输入收藏夹名称"); expect(readInput().getAttribute("aria-invalid")).toBe("true"); expect(document.activeElement).toBe(readInput()); readInput().value = "重点"; readInput().dispatchEvent(new Event("input", { bubbles: true })); expect( document.querySelector('[data-sces-favorite-folder-dialog="error"]')?.textContent ).toBe(""); readButton("cancel").click(); await expect(result).resolves.toBeNull(); }); test("cancels from its cancel button, overlay click, and Escape", async () => { const fromCancel = promptForFavoriteFolderName(document, { title: "新建收藏夹" }); readButton("cancel").click(); await expect(fromCancel).resolves.toBeNull(); const fromOverlay = promptForFavoriteFolderName(document, { title: "新建收藏夹" }); readDialog().dispatchEvent(new MouseEvent("click", { bubbles: true })); await expect(fromOverlay).resolves.toBeNull(); const fromEscape = promptForFavoriteFolderName(document, { title: "新建收藏夹" }); document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" })); await expect(fromEscape).resolves.toBeNull(); }); test("confirms a valid name with Enter", async () => { const result = promptForFavoriteFolderName(document, { title: "新建收藏夹" }); readInput().value = "待联系"; document.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter" })); await expect(result).resolves.toBe("待联系"); }); test("reuses and focuses one active dialog per document, then allows a new one after close", async () => { const first = promptForFavoriteFolderName(document, { initialValue: "首个值", title: "新建收藏夹" }); const input = readInput(); input.blur(); const reused = promptForFavoriteFolderName(document, { initialValue: "不会替换", title: "重命名收藏夹" }); expect(reused).toBe(first); expect( document.querySelectorAll('[data-sces-favorite-folder-dialog="root"]') ).toHaveLength(1); expect(readInput().value).toBe("首个值"); expect(document.activeElement).toBe(input); readButton("cancel").click(); await expect(first).resolves.toBeNull(); const second = promptForFavoriteFolderName(document, { title: "新建收藏夹" }); expect( document.querySelectorAll('[data-sces-favorite-folder-dialog="root"]') ).toHaveLength(1); readButton("cancel").click(); await expect(second).resolves.toBeNull(); }); test("traps Tab within the dialog and restores the opener focus on close", async () => { const opener = document.createElement("button"); opener.type = "button"; opener.textContent = "打开收藏夹"; document.body.append(opener); opener.focus(); const result = promptForFavoriteFolderName(document, { title: "新建收藏夹" }); readInput().focus(); document.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", shiftKey: true })); expect(document.activeElement).toBe(readButton("confirm")); document.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab" })); expect(document.activeElement).toBe(readInput()); readButton("cancel").click(); await expect(result).resolves.toBeNull(); expect(document.activeElement).toBe(opener); }); });