| 1 | package tokens |
| 2 | |
| 3 | import ( |
| 4 | "strings" |
| 5 | "testing" |
| 6 | |
| 7 | "amadan.net/rastrillo/fiesta" |
| 8 | ) |
| 9 | |
| 10 | // A shadow is the interesting negative. It CONTAINS a colour and is not |
| 11 | // one, it gets a different preview (a card wearing it rather than a |
| 12 | // chip painted with it), and a pattern loose enough to match one would |
| 13 | // silently reclassify all four depth tokens. |
| 14 | func TestColourValueRecognisesADerivedColour(t *testing.T) { |
| 15 | for _, v := range []string{ |
| 16 | "#fff", |
| 17 | "#ffffff", |
| 18 | "rgb(0, 0, 0)", |
| 19 | "rgba(0, 0, 0, 0.45)", |
| 20 | "var(--rst-line)", |
| 21 | "color-mix(in oklab, var(--rst-accent) 18%, var(--rst-line))", |
| 22 | "color-mix(in oklab, var(--rst-accent) 45%, var(--rst-line))", |
| 23 | // day's accent derivations: a hue taken from the accent, a mix |
| 24 | // whose source carries a fallback, and a bare var() with a |
| 25 | // light-dark() fallback. |
| 26 | "oklch(from var(--rst-accent, #1f56d6) 0.513 0.21 h)", |
| 27 | "color-mix(in srgb, var(--rst-accent, #1f56d6) 4.5%, var(--rst-surface))", |
| 28 | "var(--rst-accent, light-dark(#1f56d6, #7aa2ff))", |
| 29 | } { |
| 30 | if !colourValue.MatchString(v) { |
| 31 | t.Errorf("colourValue does not match %q, so the Tokens page would draw its row with no swatch", v) |
| 32 | } |
| 33 | } |
| 34 | for _, v := range []string{ |
| 35 | "0 8px 24px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.5))", |
| 36 | "0 1px 2px rgba(0, 0, 0, 0.3)", |
| 37 | "8px", |
| 38 | "system-ui, -apple-system, sans-serif", |
| 39 | "999px", |
| 40 | } { |
| 41 | if colourValue.MatchString(v) { |
| 42 | t.Errorf("colourValue matches %q, which is not a colour on its own; a chip painted with it would preview nothing and a shadow would lose the preview it has", v) |
| 43 | } |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | // lightHalf takes the first half of a whole-value light-dark() and |
| 48 | // leaves everything else alone, a shadow carrying one inside it |
| 49 | // included. |
| 50 | func TestLightHalfSplitsOnlyAWholeValue(t *testing.T) { |
| 51 | for in, want := range map[string]string{ |
| 52 | "light-dark(#fff, #000)": "#fff", |
| 53 | "light-dark(rgba(0, 0, 0, 0.12), rgba(255, 255, 255, 0.5))": "rgba(0, 0, 0, 0.12)", |
| 54 | "light-dark(color-mix(in oklab, #fff 10%, #000), #000)": "color-mix(in oklab, #fff 10%, #000)", |
| 55 | "0 8px 24px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.5))": "0 8px 24px light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.5))", |
| 56 | "#1f56d6": "#1f56d6", |
| 57 | "light-dark(#fff": "light-dark(#fff", |
| 58 | } { |
| 59 | if got := lightHalf(in); got != want { |
| 60 | t.Errorf("lightHalf(%q) = %q, want %q", in, got, want) |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | // Every theme yields the groups the page draws, every colour row in |
| 66 | // them a chip, and nothing lands in "other": a token that does is a |
| 67 | // token nobody filed under a heading. |
| 68 | func TestEveryThemeHasAPaletteAndNothingIsOther(t *testing.T) { |
| 69 | structure, err := Structural() |
| 70 | if err != nil { |
| 71 | t.Fatal(err) |
| 72 | } |
| 73 | keys := map[string]int{} |
| 74 | for _, g := range structure { |
| 75 | keys[g.Key] = len(g.Rows) |
| 76 | } |
| 77 | if keys["type-scale"] == 0 || keys["spacing"] == 0 { |
| 78 | t.Errorf("Structural: type-scale has %d rows and spacing %d; tokens.css's :root block holds both scales", keys["type-scale"], keys["spacing"]) |
| 79 | } |
| 80 | |
| 81 | for _, theme := range fiesta.ThemeNames() { |
| 82 | groups, err := Palette(theme) |
| 83 | if err != nil { |
| 84 | t.Fatalf("%s: %v", theme, err) |
| 85 | } |
| 86 | seen := map[string]bool{} |
| 87 | for _, g := range groups { |
| 88 | if seen[g.Key] { |
| 89 | t.Errorf("%s: the %s group appears twice", theme, g.Key) |
| 90 | } |
| 91 | seen[g.Key] = true |
| 92 | if len(g.Rows) == 0 { |
| 93 | t.Errorf("%s: the %s group has no rows", theme, g.Key) |
| 94 | } |
| 95 | for _, r := range g.Rows { |
| 96 | if r.Colour && r.Preview == "" { |
| 97 | t.Errorf("%s: %s is a colour with no preview", theme, r.Name) |
| 98 | } |
| 99 | if strings.HasPrefix(r.Value, "light-dark(") && g.Kind == "colour" { |
| 100 | t.Errorf("%s: %s still reads %q; the palette shows the light half", theme, r.Name, r.Value) |
| 101 | } |
| 102 | } |
| 103 | if g.Key == "other" { |
| 104 | var names []string |
| 105 | for _, r := range g.Rows { |
| 106 | names = append(names, r.Name) |
| 107 | } |
| 108 | t.Errorf("%s: %d tokens fell through to \"other\": %v", theme, len(g.Rows), names) |
| 109 | } |
| 110 | } |
| 111 | for _, want := range []string{"surfaces-and-lines", "text", "accent", "status-tones", "depth", "controls", "radius", "type-family"} { |
| 112 | if !seen[want] { |
| 113 | t.Errorf("%s: no %s group", theme, want) |
| 114 | } |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |