Files
buzz-sheet/lib/guides/export-text.test.tsx
2026-09-14 18:02:18 +07:00

82 lines
4.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { LocaleBoundary } from "@/components/i18n/locale-provider";
import { GuideImageExport } from "@/components/public/guide-image-export";
import { ConstellationImage } from "@/components/public/constellation-image";
import type { PublicGuide } from "@/lib/guides/queries";
import { exportMessages, exportStatLabel, exportText, withoutNotesFileName, type ExportMessageKey } from "@/lib/guides/export-text";
describe("export translations", () => {
it("keeps matching keys and named placeholders in both languages", () => {
expect(Object.keys(exportMessages.th).sort()).toEqual(Object.keys(exportMessages.en).sort());
for (const key of Object.keys(exportMessages.en) as ExportMessageKey[]) {
const placeholders = (text: string) => [...text.matchAll(/\{(\w+)\}/gu)].map((match) => match[1]).sort();
expect(placeholders(exportMessages.th[key]), key).toEqual(placeholders(exportMessages.en[key]));
expect(exportMessages.en[key], key).not.toMatch(/[\u0e00-\u0e7f]/u);
}
});
it("defaults to English and interpolates names without interpreting their contents", () => {
expect(exportText("weaponTitle", { name: "Raiden" })).toBe("Raiden Weapons");
expect(exportText("rotation", { seconds: "20.5" })).toBe("Rotation duration: 20.5 seconds");
expect(exportText("weaponTitle", { name: "{seconds}" })).toBe("{seconds} Weapons");
expect(exportText("condition", { index: 2 }, "th")).toBe("Condition 2");
});
it("keeps technical labels in English while localising export controls", () => {
for (const key of ["materials", "materialLevel", "weaponTitle", "talents", "mainStats", "teamDamage"] as const) {
expect(exportText(key, { name: "Raiden", level: 90 }, "th")).toBe(exportText(key, { name: "Raiden", level: 90 }, "en"));
}
expect(exportText("materials", {}, "th")).toBe("MATERIALS");
expect(exportText("materialLevel", { level: 90 }, "th")).toBe("LV.90");
expect(exportText("exportImage", {}, "th")).toBe("ส่งออกภาพ");
});
it("uses English stat names for exports while retaining Thai page labels and custom values", () => {
expect(exportStatLabel("EM")).toBe("Elemental Mastery");
expect(exportStatLabel("CRIT DAMAGE")).toBe("CRIT DMG");
expect(exportStatLabel("EM", "th")).toBe("ความชำนาญธาตุ");
expect(exportStatLabel("Pyro DMG%")).toBe("Pyro DMG%");
expect(exportStatLabel("Custom value")).toBe("Custom value");
});
it("distinguishes no-note downloads while preserving the image extension", () => {
expect(withoutNotesFileName("guide.png")).toBe("guide-without-notes.png");
expect(withoutNotesFileName("guide.v2.webp")).toBe("guide.v2-without-notes.webp");
expect(withoutNotesFileName("guide")).toBe("guide-without-notes");
});
});
describe("image export controls", () => {
it("always offers both export modes even without notes", () => {
const html = renderToStaticMarkup(<LocaleBoundary locale="en"><GuideImageExport allowWithoutNote fileName="guide.png">No notes</GuideImageExport></LocaleBoundary>);
expect(html).toContain("Export image");
expect(html).toContain("Export without note");
expect(html.match(/<button\b/gu)).toHaveLength(2);
});
it("only offers normal export unless note omission is enabled", () => {
const html = renderToStaticMarkup(<LocaleBoundary locale="en"><GuideImageExport fileName="overview.png">Overview</GuideImageExport></LocaleBoundary>);
expect(html.match(/<button\b/gu)).toHaveLength(1);
expect(html).toContain("Export image");
expect(html).not.toContain("Export without note");
});
it("disables both modes when an export selection is empty", () => {
const html = renderToStaticMarkup(<GuideImageExport allowWithoutNote fileName="guide.png" disabled>No sections</GuideImageExport>);
expect(html.match(/\sdisabled=""/gu)).toHaveLength(2);
});
it.each(["English note", "โน้ตภาษาไทย"])("marks constellation notes for omission regardless of language: %s", (note) => {
const guide = { character: { name: "Raiden", splashImageUrl: "/splash.png" }, coverUrl: "/cover.png" } as PublicGuide;
const group = { rows: [], note } as unknown as PublicGuide["constellationGroups"][number];
const html = renderToStaticMarkup(<LocaleBoundary locale="en">{createElement(ConstellationImage, { guide, group })}</LocaleBoundary>);
expect(html).toContain("Raiden’s Constellations");
expect(html).toContain("Team Damage");
expect(html).toContain('data-export-note="true"');
expect(html).toContain(note);
});
});