mymusics

retro MySpace-style music player
Log | Files | Refs | README

embedTheme.test.ts (3928B)


      1 import { describe, expect, it } from "vitest";
      2 import { buildEmbedSearchParams, parseEmbedParams } from "./embedParams";
      3 import {
      4   mergeThemeOverrides,
      5   parseEmbedFont,
      6   parseEmbedPreset,
      7   parseEmbedRadius,
      8   parseHexColor,
      9   parseThemePayload,
     10   resolveEmbedTheme,
     11 } from "./embedTheme";
     12 
     13 describe("parseHexColor", () => {
     14   it("accepts 6-digit hex with or without hash", () => {
     15     expect(parseHexColor("fbc02d")).toBe("#FBC02D");
     16     expect(parseHexColor("#fbc02d")).toBe("#FBC02D");
     17     expect(parseHexColor("%23fbc02d")).toBe("#FBC02D");
     18   });
     19 
     20   it("expands 3-digit shorthand", () => {
     21     expect(parseHexColor("f00")).toBe("#FF0000");
     22     expect(parseHexColor("#abc")).toBe("#AABBCC");
     23   });
     24 
     25   it("rejects invalid values", () => {
     26     expect(parseHexColor("")).toBeNull();
     27     expect(parseHexColor("gggggg")).toBeNull();
     28     expect(parseHexColor("12345")).toBeNull();
     29     expect(parseHexColor("not-a-color")).toBeNull();
     30   });
     31 });
     32 
     33 describe("parseEmbedRadius", () => {
     34   it("clamps radius between 0 and 24", () => {
     35     expect(parseEmbedRadius("12")).toBe(12);
     36     expect(parseEmbedRadius("0")).toBe(0);
     37     expect(parseEmbedRadius("24")).toBe(24);
     38     expect(parseEmbedRadius("99")).toBe(24);
     39     expect(parseEmbedRadius("-5")).toBe(0);
     40   });
     41 
     42   it("returns null for empty or invalid", () => {
     43     expect(parseEmbedRadius("")).toBeNull();
     44     expect(parseEmbedRadius("abc")).toBeNull();
     45   });
     46 });
     47 
     48 describe("resolveEmbedTheme", () => {
     49   it("merges preset with overrides", () => {
     50     const tokens = resolveEmbedTheme({ preset: "light", accent: "#112233" });
     51     expect(tokens.bg).toBe("#f1f5f9");
     52     expect(tokens.accent).toBe("#112233");
     53   });
     54 
     55   it("applies custom radius in px", () => {
     56     const tokens = resolveEmbedTheme({ preset: "minimal", radius: 16 });
     57     expect(tokens.radius).toBe("16px");
     58   });
     59 });
     60 
     61 describe("parseThemePayload", () => {
     62   it("parses postMessage theme object", () => {
     63     expect(parseThemePayload({ preset: "dark", accent: "e64a19" })).toEqual({
     64       preset: "dark",
     65       accent: "#E64A19",
     66     });
     67   });
     68 
     69   it("returns null when no valid keys", () => {
     70     expect(parseThemePayload({})).toBeNull();
     71     expect(parseThemePayload(null)).toBeNull();
     72     expect(parseThemePayload({ preset: "invalid" })).toBeNull();
     73   });
     74 
     75   it("accepts fgMuted alias textMuted", () => {
     76     expect(parseThemePayload({ fgMuted: "94a3b8" })?.fgMuted).toBe("#94A3B8");
     77     expect(parseThemePayload({ textMuted: "64748b" })?.fgMuted).toBe("#64748B");
     78   });
     79 });
     80 
     81 describe("mergeThemeOverrides", () => {
     82   it("patch wins over base", () => {
     83     expect(
     84       mergeThemeOverrides({ preset: "light", accent: "#111111" }, { accent: "#222222" }),
     85     ).toEqual({ preset: "light", accent: "#222222" });
     86   });
     87 });
     88 
     89 describe("parseEmbedPreset and parseEmbedFont", () => {
     90   it("accepts known preset ids", () => {
     91     expect(parseEmbedPreset("midnight")).toBe("midnight");
     92     expect(parseEmbedPreset("unknown")).toBeNull();
     93   });
     94 
     95   it("accepts known font ids", () => {
     96     expect(parseEmbedFont("serif")).toBe("serif");
     97     expect(parseEmbedFont("comic")).toBeNull();
     98   });
     99 });
    100 
    101 describe("buildEmbedSearchParams round-trip", () => {
    102   it("preserves theme params in parseEmbedParams", () => {
    103     const qs = buildEmbedSearchParams({
    104       preset: "minimal",
    105       accent: "#e64a19",
    106       bg: "0f172a",
    107       panel: "1e293b",
    108       text: "f8fafc",
    109       fgMuted: "94a3b8",
    110       radius: 10,
    111       font: "serif",
    112       theme: "compact",
    113       showBrand: false,
    114       startMuted: true,
    115     });
    116     const parsed = parseEmbedParams(qs);
    117     expect(parsed.theme).toBe("compact");
    118     expect(parsed.showBrand).toBe(false);
    119     expect(parsed.startMuted).toBe(true);
    120     expect(parsed.themeOverrides).toMatchObject({
    121       preset: "minimal",
    122       accent: "#E64A19",
    123       bg: "#0F172A",
    124       panel: "#1E293B",
    125       text: "#F8FAFC",
    126       fgMuted: "#94A3B8",
    127       radius: 10,
    128       font: "serif",
    129     });
    130   });
    131 });