test: cover favorites drawer lifecycle
This commit is contained in:
@@ -146,6 +146,33 @@ describe("favorite-folder-dialog", () => {
|
||||
await expect(second).resolves.toBeNull();
|
||||
});
|
||||
|
||||
test("removes a closed dialog keydown listener before a fresh dialog opens", async () => {
|
||||
let firstSettlementCount = 0;
|
||||
const first = promptForFavoriteFolderName(document, {
|
||||
title: "新建收藏夹"
|
||||
});
|
||||
void first.then(() => {
|
||||
firstSettlementCount += 1;
|
||||
});
|
||||
|
||||
readButton("cancel").click();
|
||||
await expect(first).resolves.toBeNull();
|
||||
await Promise.resolve();
|
||||
expect(firstSettlementCount).toBe(1);
|
||||
|
||||
const current = promptForFavoriteFolderName(document, {
|
||||
title: "重命名收藏夹"
|
||||
});
|
||||
document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
|
||||
|
||||
await expect(current).resolves.toBeNull();
|
||||
await Promise.resolve();
|
||||
expect(firstSettlementCount).toBe(1);
|
||||
expect(
|
||||
document.querySelector('[data-sces-favorite-folder-dialog="root"]')
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test("traps Tab within the dialog and restores the opener focus on close", async () => {
|
||||
const opener = document.createElement("button");
|
||||
opener.type = "button";
|
||||
|
||||
@@ -120,12 +120,21 @@ describe("favorites-drawer", () => {
|
||||
expect(readTab().textContent).toContain("收藏夹");
|
||||
expect(readTab().style.position).toBe("fixed");
|
||||
expect(readTab().style.right).toBe("56px");
|
||||
expect(readTab().style.writingMode).toBe("vertical-rl");
|
||||
expect(readTab().getAttribute("aria-controls")).toBe(readDrawer().id);
|
||||
expect(readTab().getAttribute("aria-expanded")).toBe("false");
|
||||
expect(readTab().querySelector("[data-sces-favorites-unread]")).toBeNull();
|
||||
expect(readTab().querySelector("[data-sces-favorites-badge]")).toBeNull();
|
||||
expect(readTab().dataset.scesFavoritesUnread).toBeUndefined();
|
||||
expect(readTab().dataset.scesFavoritesCount).toBeUndefined();
|
||||
expect(readTab().textContent).not.toMatch(/\d/);
|
||||
expect(readTab().style.color).not.toMatch(/b42318|dc2626|ef4444|red/i);
|
||||
expect(readDrawer().hidden).toBe(true);
|
||||
expect(readDrawer().style.position).toBe("fixed");
|
||||
expect(readDrawer().style.right).toBe("56px");
|
||||
expect(readDrawer().style.width).toBe("380px");
|
||||
expect(readDrawer().getAttribute("role")).toBe("dialog");
|
||||
expect(readDrawer().getAttribute("aria-label")).toBe("收藏夹");
|
||||
});
|
||||
|
||||
test("opens, closes, and restores focus through the trigger, close control, and Escape", () => {
|
||||
@@ -263,6 +272,40 @@ describe("favorites-drawer", () => {
|
||||
expect(onRemoveCreatorFromFolder).toHaveBeenCalledWith("author-1", firstFolder.id);
|
||||
});
|
||||
|
||||
test("prunes selected creators that are outside the active folder before importing", async () => {
|
||||
const onImportSelected = vi.fn(async (_authorIds: string[]) => {});
|
||||
const { controller } = createHarness({ handlers: { onImportSelected } });
|
||||
controller.render(
|
||||
createState({
|
||||
creators: [createCreator("111", "Alpha"), createCreator("222", "Beta")],
|
||||
memberships: [
|
||||
createMembership("111", firstFolder.id),
|
||||
createMembership("222", secondFolder.id)
|
||||
]
|
||||
})
|
||||
);
|
||||
readTab().click();
|
||||
|
||||
const firstSelection = document.querySelector(
|
||||
'[data-sces-favorites-select-author-id="111"]'
|
||||
) as HTMLInputElement;
|
||||
firstSelection.checked = true;
|
||||
firstSelection.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
const secondSelection = document.querySelector(
|
||||
'[data-sces-favorites-select-author-id="222"]'
|
||||
) as HTMLInputElement;
|
||||
secondSelection.checked = true;
|
||||
secondSelection.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
expect(readDrawer().textContent).toContain("导入已选 2 位达人");
|
||||
|
||||
click(`[data-sces-favorites-folder-id="${firstFolder.id}"]`);
|
||||
expect(readDrawer().textContent).toContain("导入已选 1 位达人");
|
||||
click('[data-sces-favorites-drawer="import-selected"]');
|
||||
await flush();
|
||||
|
||||
expect(onImportSelected).toHaveBeenCalledWith(["111"]);
|
||||
});
|
||||
|
||||
test("calls create, rename, and delete handlers with the matching folder id", async () => {
|
||||
const onCreateFolder = vi.fn(async () => {});
|
||||
const onRenameFolder = vi.fn(async (_folderId: string) => {});
|
||||
@@ -351,8 +394,9 @@ describe("favorites-drawer", () => {
|
||||
expect(readDrawer().hidden).toBe(true);
|
||||
});
|
||||
|
||||
test("renders errors and removes its DOM and document behavior on disposal", () => {
|
||||
const { controller } = createHarness();
|
||||
test("renders errors and removes DOM and event behavior on disposal", async () => {
|
||||
const onCreateFolder = vi.fn(async () => {});
|
||||
const { controller } = createHarness({ handlers: { onCreateFolder } });
|
||||
controller.render(createState());
|
||||
readTab().click();
|
||||
controller.setError("保存失败");
|
||||
@@ -360,10 +404,28 @@ describe("favorites-drawer", () => {
|
||||
document.querySelector('[data-sces-favorites-drawer="error"]')?.textContent
|
||||
).toBe("保存失败");
|
||||
|
||||
const staleCreateButton = document.querySelector(
|
||||
'[data-sces-favorites-drawer="create-folder"]'
|
||||
) as HTMLButtonElement;
|
||||
const removeEventListener = vi.spyOn(document, "removeEventListener");
|
||||
controller.dispose();
|
||||
controller.dispose();
|
||||
expect(document.querySelector('[data-sces-favorites-tab="button"]')).toBeNull();
|
||||
expect(document.querySelector('[data-sces-favorites-drawer="root"]')).toBeNull();
|
||||
document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape" }));
|
||||
expect(removeEventListener).toHaveBeenCalledWith("keydown", expect.any(Function));
|
||||
|
||||
const unrelatedButton = document.createElement("button");
|
||||
unrelatedButton.type = "button";
|
||||
document.body.append(unrelatedButton);
|
||||
unrelatedButton.focus();
|
||||
const escape = new KeyboardEvent("keydown", { cancelable: true, key: "Escape" });
|
||||
document.dispatchEvent(escape);
|
||||
staleCreateButton.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
await flush();
|
||||
|
||||
expect(escape.defaultPrevented).toBe(false);
|
||||
expect(document.activeElement).toBe(unrelatedButton);
|
||||
expect(onCreateFolder).not.toHaveBeenCalled();
|
||||
removeEventListener.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user