Files
buzz-sheet/components/admin/editors/weapon-editor.test.tsx
T

86 lines
3.7 KiB
TypeScript

// @vitest-environment happy-dom
import { act, createElement, type ComponentProps } from "react";
import { createRoot, type Root } from "react-dom/client";
import { renderToStaticMarkup } from "react-dom/server";
import { WeaponComparisonCard } from "@/components/weapon-comparison-card";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useManualSave } from "@/hooks/use-manual-save";
import { WeaponEditor } from "./weapon-editor";
vi.mock("@/app/admin/actions", () => ({ saveWeaponSection: vi.fn() }));
vi.mock("@/hooks/use-manual-save", () => ({
useManualSave: vi.fn(() => ({ state: "saved", canSave: false })),
}));
let root: Root;
let container: HTMLDivElement;
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(value: string) {
const props = {
guide: { id: "guide", characterKey: "character", version: 1 },
characters: [{ key: "character", weaponType: "sword" }],
weapons: [{ key: "weapon", name: "Weapon", weaponType: "sword", rarity: 5, imageUrl: "/weapon.png" }],
initial: { sectionNote: null, weaponGroups: [{
id: "condition", name: null, note: null, rows: [{
id: "row", weaponKey: "weapon", refinement: "1", overallPercent: value, personalPercent: null, note: null,
}],
}] },
} as unknown as ComponentProps<typeof WeaponEditor>;
await act(async () => root.render(createElement(WeaponEditor, props)));
return container.querySelector<HTMLInputElement>("#weapon-overall-row")!;
}
describe("weapon damage editing", () => {
it("uses the public curve and damage typography with more room for inputs", async () => {
const input = await render("120.00");
const publicCard = document.createElement("div");
publicCard.innerHTML = renderToStaticMarkup(createElement(WeaponComparisonCard, {
weapon: { key: "weapon", name: "Weapon", rarity: 5, imageUrl: "/weapon.png" },
rank: 1, refinement: "1", note: null, overallPercent: "120.00", personalPercent: null,
weaponHref: "https://lunaris.moe/weapon/weapon",
}));
const publicContent = publicCard.querySelector('[data-slot="card-content"]')!;
const adminContent = input.closest('[data-slot="card-content"]')!;
expect(adminContent.className.replace(/md:grid-cols-\S+/u, ""))
.toBe(publicContent.className.replace(/md:grid-cols-\S+/u, ""));
expect(adminContent.className).toContain("md:grid-cols-[minmax(0,5fr)_minmax(0,2fr)]");
expect(adminContent.firstElementChild!.className.replace(" relative", ""))
.toBe(publicContent.firstElementChild!.className);
const publicValue = publicContent.lastElementChild!.querySelector("p")!;
expect(input.parentElement!.className).toBe(publicValue.className);
expect(input.value).toBe(publicValue.textContent);
expect(adminContent.lastElementChild!.className).toBe(publicContent.lastElementChild!.className);
});
it.each([
["0.00", "-"],
["120.00", "120%"],
["120.125", "120.13%"],
["", ""],
])("displays %s as %s while preserving its raw draft value", async (raw, display) => {
const input = await render(raw);
expect(input.value).toBe(display);
await act(async () => input.focus());
expect(input.value).toBe(raw);
await act(async () => input.blur());
expect(input.value).toBe(display);
const options = vi.mocked(useManualSave).mock.lastCall![0];
expect(options.value).toMatchObject({ groups: [{ rows: [{ overallPercent: raw === "" ? null : Number(raw) }] }] });
});
});