Files
buzz-sheet/lib/guides/export-text.test.tsx
T
gunshiz e0794822b1
CI / Verify (push) Successful in 1m18s
CI / Build immutable images and deploy (push) Successful in 1m57s
feat(i18n) : add personal languages and compact weapon exports
2026-09-14 16:44:44 +07:00

66 lines
3.7 KiB
TypeScript
Raw 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("เงื่อนไข 2");
});
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 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("disables both modes when an export selection is empty", () => {
const html = renderToStaticMarkup(<GuideImageExport 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);
});
});