// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 // The app brand (plan item AT2.6). A customer replaces the ConusAI defaults in config/src/brand.ts with // `defineBrand`, and what they give it has to be safe to write into a stylesheet and a page. The // legibility of their colours is @conusai-kit/brand's own test: this file checks what the app does with them. import { appBrand, brandContrast, brandTokenStyle, defineBrand } from "@app/config" import { describe, expect, it } from "vitest" const base = { name: "Acme Review", shortName: "Acme" } describe("defineBrand", () => { it("returns the brand, frozen, with its colours as a style", () => { const brand = defineBrand({ ...base, primary: "#1a1a8c" }) expect(brand.name).toBe("Acme Review") expect(Object.isFrozen(brand)).toBe(true) expect(brand.attribution).toBe(false) expect(brandTokenStyle(brand)["--brand-accent"]).toBe("#1a1a8c") }) it("reports the contrast its colours have on each theme", () => { const report = brandContrast(defineBrand({ ...base, primary: "#1a1a8c" })) expect(report.dark?.inkContrast).toBeGreaterThanOrEqual(4.5) expect(report.light?.inkContrast).toBeGreaterThanOrEqual(4.5) expect(brandContrast(defineBrand(base))).toEqual({}) }) it("refuses a colour that is not hex, naming the field and not the value", () => { expect(() => defineBrand({ ...base, primary: "red" })).toThrow(/primary/) expect(() => defineBrand({ ...base, primary: "secret-colour" })).not.toThrow(/secret-colour/) expect(() => defineBrand({ ...base, accent: "#12" })).toThrow(/accent/) }) it("refuses a name that is empty, too long or carries a control character", () => { for (const name of ["", " ", "x".repeat(61), "bad\u0007name"]) { expect(() => defineBrand({ name, shortName: "x" })).toThrow(/name/) } }) it("refuses a logo that is not a path on this app's own origin", () => { for (const logo of [ "https://cdn.example.test/logo.svg", "//cdn.example.test/logo.svg", "javascript:alert(1)", "data:image/svg+xml,", "logo.svg", ]) { expect(() => defineBrand({ ...base, logo: { light: logo, dark: "/a.svg", favicon: "/a.svg" } }), logo).toThrow( /logo/, ) } expect(defineBrand({ ...base, logo: { light: "/l.svg", dark: "/d.svg", favicon: "/f.svg" } }).logo.dark).toBe( "/d.svg", ) }) it("refuses a token that could break out of a style attribute", () => { for (const value of ["red; background: url(//evil)", "#fff}", "url(//evil)", "expression(1)", "a\\b", ""]) { expect(() => defineBrand({ ...base, tokens: { "--brand-accent": value } }), value).toThrow(/token/) } expect(() => defineBrand({ ...base, tokens: { "not a name": "#fff" } })).toThrow(/token/) expect(brandTokenStyle(defineBrand({ ...base, tokens: { "radius-panel": "0.5rem" } }))).toEqual({ "--brand-radius-panel": "0.5rem", }) }) it("is what the app ships: a neutral name, no ConusAI wording, no attribution", () => { expect(JSON.stringify(appBrand).toLowerCase()).not.toContain("conusai") expect(appBrand.attribution).toBe(false) }) })