This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
// The branding module's messages: both languages, the same keys, every key asked for, and no string
|
||||
// or colour literal in its components.
|
||||
|
||||
import { readdirSync, readFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { buildRegistry } from "@conusai-kit/core"
|
||||
import { lintUiStrings } from "@conusai-kit/i18n"
|
||||
import { describe, expect, it } from "vitest"
|
||||
import { appModules } from "../../index.js"
|
||||
import { brandFormLabels } from "../ui/labels.js"
|
||||
|
||||
// The messages as the app has them: from the manifest, flattened and merged by the kit.
|
||||
const catalogues = buildRegistry([...appModules]).catalogues
|
||||
const en = catalogues.en?.branding ?? {}
|
||||
const lt = catalogues.lt?.branding ?? {}
|
||||
|
||||
function keysUsed(): string[] {
|
||||
const asked: string[] = []
|
||||
brandFormLabels((key) => {
|
||||
asked.push(key)
|
||||
return key
|
||||
}, "failed")
|
||||
return asked
|
||||
}
|
||||
|
||||
describe("the branding catalogues", () => {
|
||||
it("hold the same keys in English and in Lithuanian", () => {
|
||||
expect(Object.keys(lt).sort()).toEqual(Object.keys(en).sort())
|
||||
})
|
||||
|
||||
it("hold every key the form asks for, and nothing it does not (the page asks for title and intro itself)", () => {
|
||||
const asked = new Set([...keysUsed(), "title", "intro"])
|
||||
for (const key of asked) {
|
||||
expect(en[key as keyof typeof en], `en ${key}`).toBeTruthy()
|
||||
expect(lt[key as keyof typeof lt], `lt ${key}`).toBeTruthy()
|
||||
}
|
||||
expect(Object.keys(en).filter((key) => !asked.has(key))).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
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(3)
|
||||
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\(/)
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,66 @@
|
||||
// Which logo a theme shows when an organization has uploaded one, both, or none: the one rule the
|
||||
// layout, the settings page, the share image and the email all read (contract/logo.ts).
|
||||
|
||||
import { describe, expect, it } from "vitest"
|
||||
import { logoUrl, resolveLogo, tenantLogo } from "../contract/logo.js"
|
||||
|
||||
const light = "/acme/brand/logo/light?v=aaaaaaaaaaaaaaaa"
|
||||
const dark = "/acme/brand/logo/dark?v=bbbbbbbbbbbbbbbb"
|
||||
const app = { light: "/app-light.svg", dark: "/app-dark.svg" }
|
||||
|
||||
describe("the logo an organization shows on a theme", () => {
|
||||
it("is its own when it has one for that theme", () => {
|
||||
const both = { logoLight: light, logoDark: dark }
|
||||
expect(tenantLogo(both, "light")).toEqual({ source: "tenant", variant: "light", path: light })
|
||||
expect(tenantLogo(both, "dark")).toEqual({ source: "tenant", variant: "dark", path: dark })
|
||||
})
|
||||
|
||||
it("is the only one it has, on both themes", () => {
|
||||
expect(tenantLogo({ logoLight: light, logoDark: null }, "dark")).toEqual({
|
||||
source: "tenant",
|
||||
variant: "light",
|
||||
path: light,
|
||||
})
|
||||
expect(tenantLogo({ logoLight: null, logoDark: dark }, "light")).toEqual({
|
||||
source: "tenant",
|
||||
variant: "dark",
|
||||
path: dark,
|
||||
})
|
||||
expect(tenantLogo({ logoLight: light, logoDark: null }, "light")?.variant).toBe("light")
|
||||
})
|
||||
|
||||
it("is none when it has none", () => {
|
||||
expect(tenantLogo({ logoLight: null, logoDark: null }, "dark")).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe("the logo a share image or an email shows", () => {
|
||||
it("is the organization's, with the same fallback between its two", () => {
|
||||
expect(resolveLogo({ logoLight: light, logoDark: null }, app, "dark")).toEqual({
|
||||
source: "tenant",
|
||||
variant: "light",
|
||||
path: light,
|
||||
})
|
||||
expect(resolveLogo({ logoLight: light, logoDark: dark }, app, "dark")).toEqual({
|
||||
source: "tenant",
|
||||
variant: "dark",
|
||||
path: dark,
|
||||
})
|
||||
})
|
||||
|
||||
it("is the app brand's own for that theme when the organization has none, or there is no organization", () => {
|
||||
expect(resolveLogo({ logoLight: null, logoDark: null }, app, "dark")).toEqual({
|
||||
source: "app",
|
||||
variant: "dark",
|
||||
path: "/app-dark.svg",
|
||||
})
|
||||
expect(resolveLogo(null, app, "light")).toEqual({ source: "app", variant: "light", path: "/app-light.svg" })
|
||||
})
|
||||
})
|
||||
|
||||
describe("the address of a stored size", () => {
|
||||
it("adds the size after the content tag", () => {
|
||||
expect(logoUrl(light, "1x")).toBe(`${light}&s=1x`)
|
||||
expect(logoUrl("/acme/brand/logo/light", "2x")).toBe("/acme/brand/logo/light?s=2x")
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user