Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

85 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { readFileSync } from "node:fs";
3import { test } from "node:test";
4
5// The shared tokens every site draws from (packages/theme/tokens.css).
6const css = readFileSync(new URL("../../../../packages/theme/tokens.css", import.meta.url), "utf8");
7
8function token(name: string): string {
9 const found = css.match(new RegExp(`--g1t-${name}:\\s*(#[0-9a-f]{6});`, "i"));
10 assert.ok(found, `--g1t-${name} is a six-digit hex colour`);
11 return found[1].toLowerCase();
12}
13
14function luminance(hex: string): number {
15 const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255).map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4));
16 return 0.2126 * r + 0.7152 * g + 0.0722 * b;
17}
18
19function contrast(a: string, b: string): number {
20 const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
21 return (hi + 0.05) / (lo + 0.05);
22}
23
24test("the accent is the logo's lavender, and mint means success", () => {
25 assert.equal(token("accent"), "#b6a8ff");
26 assert.equal(token("success"), "#86efc4");
27});
28
29test("merged reads apart from the accent", () => {
30 assert.notEqual(token("merged"), token("accent"));
31 assert.notEqual(token("merged"), token("success"));
32});
33
34test("text colours meet WCAG AA on every surface", () => {
35 for (const surface of ["bg", "surface", "raised"]) {
36 for (const ink of ["fg", "muted", "accent", "success", "merged", "info", "warn", "danger"]) {
37 const ratio = contrast(token(ink), token(surface));
38 assert.ok(ratio >= 4.5, `--g1t-${ink} on --g1t-${surface} is ${ratio.toFixed(2)}:1`);
39 }
40 }
41});
42
43test("the dark base reads on an accent or success button", () => {
44 for (const fill of ["accent", "accent-hover", "success"]) {
45 const ratio = contrast(token("bg"), token(fill));
46 assert.ok(ratio >= 4.5, `--g1t-bg on --g1t-${fill} is ${ratio.toFixed(2)}:1`);
47 }
48});
49
50test("focus borders in the dim accent stand out from the page", () => {
51 assert.ok(contrast(token("accent-dim"), token("bg")) >= 3);
52});
53
54// The light palette (Appearance, lib/theme.ts): the same names after `light-`.
55
56test("the light accent is a deeper lavender, and light success is green", () => {
57 assert.equal(token("light-accent"), "#6b52c8");
58 assert.equal(token("light-success"), "#0d7a52");
59});
60
61test("every dark token has a light one", () => {
62 const dark = [...css.matchAll(/--g1t-(?!light-|font-)([a-z-]+):/g)].map((match) => match[1]);
63 assert.ok(dark.length > 10);
64 for (const name of dark) token(`light-${name}`);
65});
66
67test("light text colours meet WCAG AA on every light surface", () => {
68 for (const surface of ["bg", "surface", "raised"]) {
69 for (const ink of ["fg", "fg-soft", "muted", "faint", "accent", "accent-hover", "success", "merged", "info", "warn", "danger"]) {
70 const ratio = contrast(token(`light-${ink}`), token(`light-${surface}`));
71 assert.ok(ratio >= 4.5, `--g1t-light-${ink} on --g1t-light-${surface} is ${ratio.toFixed(2)}:1`);
72 }
73 }
74});
75
76test("the light page reads on an accent or success button", () => {
77 for (const fill of ["accent", "accent-hover", "success"]) {
78 const ratio = contrast(token("light-bg"), token(`light-${fill}`));
79 assert.ok(ratio >= 4.5, `--g1t-light-bg on --g1t-light-${fill} is ${ratio.toFixed(2)}:1`);
80 }
81});
82
83test("light focus borders in the dim accent stand out from the page", () => {
84 assert.ok(contrast(token("light-accent-dim"), token("light-bg")) >= 3);
85});