88 lines
4.2 KiB
TypeScript
88 lines
4.2 KiB
TypeScript
// @vitest-environment happy-dom
|
|
import { act, createElement, type ReactNode } from "react";
|
|
import { createRoot, type Root } from "react-dom/client";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mocks = vi.hoisted(() => ({ save: vi.fn() }));
|
|
vi.mock("@/app/admin/stygian/actions", () => ({ saveStygianRecommendationsAction: mocks.save }));
|
|
vi.mock("@/components/admin/stygian-sync-button", () => ({ StygianSyncButton: () => null }));
|
|
vi.mock("@/components/ui/resilient-image", () => ({ default: () => null }));
|
|
vi.mock("@/components/stygian/stygian-boss-display", () => ({
|
|
StygianBossCard: ({ children }: { children: ReactNode }) => createElement("section", {}, children),
|
|
StygianBossTab: ({ boss }: { boss?: { name: string } }) => createElement("span", {}, boss?.name),
|
|
}));
|
|
vi.mock("@/components/admin/ui/catalog-select", () => ({
|
|
CharacterSelect: ({ onValueChange }: { onValueChange: (key: string) => void }) =>
|
|
createElement("button", { type: "button", onClick: () => onValueChange("test-character") }, "Choose test character"),
|
|
ArtifactSelect: () => null,
|
|
CatalogDropdown: () => null,
|
|
WeaponSelect: () => null,
|
|
}));
|
|
import { StygianEditor } from "./stygian-editor";
|
|
|
|
let root: Root;
|
|
let container: HTMLDivElement;
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
vi.clearAllMocks();
|
|
mocks.save.mockImplementation(async (_scheduleId, input) => ({ status: "saved", version: input.expectedVersion + 1 }));
|
|
container = document.createElement("div");
|
|
document.body.append(container);
|
|
root = createRoot(container);
|
|
});
|
|
afterEach(async () => {
|
|
await act(async () => root.unmount());
|
|
container.remove();
|
|
vi.useRealTimers();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
function activePanel() {
|
|
return Array.from(container.querySelectorAll<HTMLElement>('[role="tabpanel"]')).find((panel) =>
|
|
!panel.closest('[hidden], [inert]') && panel.querySelector(":scope > section"),
|
|
)!;
|
|
}
|
|
async function clickButton(label: string, within: HTMLElement = activePanel()) {
|
|
const button = Array.from(within.querySelectorAll<HTMLButtonElement>("button")).find((button) => button.textContent === label)!;
|
|
expect(button).toBeDefined();
|
|
await act(async () => button.click());
|
|
}
|
|
async function selectBoss(position: number) {
|
|
const tabs = Array.from(container.querySelectorAll<HTMLButtonElement>('[role="tab"]')).filter((tab) =>
|
|
tab.getAttribute("title")?.startsWith("Test boss") && !tab.closest('[hidden]'),
|
|
);
|
|
await act(async () => tabs[position].click());
|
|
await act(async () => { await vi.advanceTimersByTimeAsync(0); });
|
|
}
|
|
|
|
describe("Stygian manual saving", () => {
|
|
it("keeps drafts across boss tabs and saves only the active tab on a click", async () => {
|
|
const bosses = [0, 1, 2].map((position) => ({
|
|
level: 105, position, name: `Test boss ${position}`, imageUrl: "/test.png", hp: 1,
|
|
description: "", mechanics: [], recommendedMechanics: [], recommendedMechanicTypes: [],
|
|
}));
|
|
await act(async () => root.render(createElement(StygianEditor, {
|
|
schedule: { scheduleId: 1, challengeName: "Test", version: 1 }, schedules: [], bosses,
|
|
recommendations: [], characters: [], weapons: [], artifacts: [],
|
|
})));
|
|
expect(container.querySelectorAll("section")).toHaveLength(1);
|
|
await clickButton("Add team");
|
|
await clickButton("Choose test character");
|
|
await act(async () => { await vi.advanceTimersByTimeAsync(10_000); });
|
|
expect(mocks.save).not.toHaveBeenCalled();
|
|
await selectBoss(1);
|
|
await clickButton("Add team");
|
|
await clickButton("Choose test character");
|
|
expect(container.querySelectorAll(".fixed")).toHaveLength(1);
|
|
await clickButton("บันทึก");
|
|
expect(mocks.save).toHaveBeenCalledTimes(1);
|
|
expect(mocks.save.mock.calls[0][1]).toMatchObject({ level: 105, bossPosition: 1, expectedVersion: 1 });
|
|
await selectBoss(0);
|
|
expect(activePanel().querySelector(".fixed button")?.hasAttribute("disabled")).toBe(false);
|
|
await clickButton("บันทึก");
|
|
expect(mocks.save).toHaveBeenCalledTimes(2);
|
|
expect(mocks.save.mock.calls[1][1]).toMatchObject({ level: 105, bossPosition: 0, expectedVersion: 2 });
|
|
expect(mocks.save.mock.calls[1][1].teams[0][0].catalogKey).toBe("test-character");
|
|
});
|
|
});
|