// @vitest-environment jsdom // // Contract of the fixed-width count pill. Uses the REAL i18n instance (not a key-passthrough) so the // plural selection (itemCount_one/_other) and the "1M+" overflow interpolation are actually exercised — // those are the two branches worth guarding. English is forced so the singular/plural strings are stable. import { describe, it, expect, beforeAll, afterEach } from "vitest"; import { render, screen, cleanup } from "@testing-library/react"; import "../../i18n"; // side-effect: initialise the shared i18next instance import i18n from "i18next"; import ItemCount from "./ItemCount"; import { formatNumber } from "../../lib/format"; beforeAll(async () => { await i18n.changeLanguage("en"); }); afterEach(async () => { cleanup(); await i18n.changeLanguage("en"); // a case that switches language must not leak it to the next }); const text = () => screen.getByTestId("item-count").textContent; describe("ItemCount", () => { it("uses the singular string at 1 and the plural above it", () => { render(); expect(text()).toBe("1 item"); }); it("pluralises and thousands-separates a normal count", () => { render(); // Separators come from the shared formatNumber — compare against it, not a fixed en-US string, // so the test asserts ItemCount's formatting path rather than the CI locale. expect(text()).toBe(`${formatNumber(192045)} items`); }); // The pill used `count.toLocaleString()`, which groups in the BROWSER's locale: a Hungarian UI on // an English browser showed "192,045" instead of "192 045". The title carries the pure number (no // plural string), and both languages are asserted — comparing against the runtime's own default // would pass under the old bug on a machine whose locale happens to match the UI language. it("groups in the UI language, not the browser's", async () => { const title = () => screen.getByTestId("item-count").getAttribute("title"); render(); const asEnglish = title(); cleanup(); await i18n.changeLanguage("hu"); render(); expect(asEnglish).toBe(new Intl.NumberFormat("en").format(192045)); expect(title()).toBe(new Intl.NumberFormat("hu").format(192045)); expect(title()).not.toBe(asEnglish); }); it("collapses a count of a million or more to 1M+, with the exact figure in the tooltip", () => { render(); expect(text()).toBe("1M+ items"); // the "1M+" collapse is locale-independent expect(screen.getByTestId("item-count").getAttribute("title")).toBe(formatNumber(1_000_000)); }); it("shows the icon-only fixed box (empty label) while the count is undefined", () => { render(); expect(text()).toBe(""); // the Layers icon carries no text expect(screen.getByTestId("item-count").getAttribute("title")).toBeNull(); }); });