Files
template-app/modules/crm/__tests__/i18n.test.ts
T
2026-11-14 09:56:45 +00:00

77 lines
3.1 KiB
TypeScript

// Every string a page of the module shows is a message in English and in Lithuanian, the Lithuanian
// plural forms are real ones, and no component of the module carries a string of its own.
import { readdirSync, readFileSync } from "node:fs"
import { join } from "node:path"
import { buildRegistry } from "@conusai-kit/core"
import { createI18n, lintUiStrings } from "@conusai-kit/i18n"
import { tenancyModule } from "@conusai-kit/tenancy"
import { describe, expect, it } from "vitest"
import { crmModule } from "../module.js"
import { contactFormLabels, contactsLabels, partyFormLabels, partyListLabels } from "../ui/labels.js"
// The messages as an app that turned the module on has them: from the manifest, flattened by the kit.
const catalogues = buildRegistry([tenancyModule, crmModule]).catalogues
const en = catalogues.en?.crm ?? {}
const lt = catalogues.lt?.crm ?? {}
function keysUsed(): string[] {
const asked: string[] = []
const t = (key: string) => {
asked.push(key)
return key
}
partyFormLabels(t, {})
partyListLabels(t)
contactsLabels(t, 2)
contactFormLabels(t, {})
return asked
}
describe("the crm catalogues", () => {
it("hold the same keys in English and in Lithuanian, none empty", () => {
expect(Object.keys(lt).sort()).toEqual(Object.keys(en).sort())
for (const [key, text] of [...Object.entries(en), ...Object.entries(lt)]) expect(text.trim(), key).not.toBe("")
})
it("hold every message the labels ask for, and none that nothing asks for", () => {
const asked = keysUsed()
for (const key of asked) {
expect(en[key as keyof typeof en], `en is missing crm.${key}`).toBeTruthy()
expect(lt[key as keyof typeof lt], `lt is missing crm.${key}`).toBeTruthy()
}
// The page and the navigation ask for these directly.
const direct = new Set(["title", "intro", "party.back", "party.linked"])
expect(Object.keys(en).filter((key) => !asked.includes(key) && !direct.has(key))).toEqual([])
})
it("answer the navigation label the manifest names", () => {
expect(crmModule.ui?.nav?.map((item) => item.label)).toEqual(["crm.title"])
})
it("count contact points with the Lithuanian one, few and other forms", () => {
const count = (locale: "en" | "lt", n: number) =>
createI18n(locale, { en: { crm: en }, lt: { crm: lt } }).message("crm.contacts.count", { count: n })
expect(count("lt", 1)).toBe("1 kontaktas")
expect(count("lt", 2)).toBe("2 kontaktai")
expect(count("lt", 10)).toBe("10 kontaktų")
expect(count("lt", 21)).toBe("21 kontaktas")
expect(count("en", 2)).toBe("2 contact points")
})
})
describe("the components", () => {
const dir = new URL("../ui/", import.meta.url).pathname
const sources = readdirSync(dir)
.filter((name) => name.endsWith(".tsx"))
.map((name) => ({ name, text: readFileSync(join(dir, name), "utf8") }))
it("carry no hard-coded user-facing string and no colour literal", () => {
expect(sources.length).toBeGreaterThanOrEqual(5)
for (const { name, text } of sources) {
expect(lintUiStrings(text, name), name).toEqual([])
expect(text, name).not.toMatch(/#[0-9a-fA-F]{3,8}\b|\brgb\(|\bhsl\(|\boklch\(/)
}
})
})