Ctrl K
ComunidadGuías…

shared/utils/color.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import {
  blendColors,
  ensureContrast,
  hasSufficientContrast,
  palette,
  stringToColor,
  toColorFormats,
  validateColorHex,
} from "./color";

describe("stringToColor", () => {
  it("returns a stable palette color for the input", () => {
    expect(stringToColor("pdf")).toBe(palette[2]);
    expect(stringToColor("a@b.com")).toBe(palette[8]);
    expect(stringToColor("Ünïcødé 😀")).toBe(palette[2]);
    expect(stringToColor("3f2504e0-4f89-41d3-9a0c-0305e82c3301")).toBe(
      palette[12]
    );
  });
});

describe("validateColorHex", () => {
  it("accepts 3-digit hex", () => {
    expect(validateColorHex("#fff")).toBe(true);
    expect(validateColorHex("#ABC")).toBe(true);
    expect(validateColorHex("#000")).toBe(true);
  });

  it("accepts 4-digit hex with alpha", () => {
    expect(validateColorHex("#fff8")).toBe(true);
    expect(validateColorHex("#ABCD")).toBe(true);
  });

  it("accepts 6-digit hex", () => {
    expect(validateColorHex("#FDEA9B")).toBe(true);
    expect(validateColorHex("#ffffff")).toBe(true);
  });

  it("accepts 8-digit hex with alpha", () => {
    expect(validateColorHex("#FDEA9BB3")).toBe(true);
    expect(validateColorHex("#00000080")).toBe(true);
  });

  it("rejects strings missing the leading #", () => {
    expect(validateColorHex("ffffff")).toBe(false);
    expect(validateColorHex("fff")).toBe(false);
  });

  it("rejects hex strings of unsupported lengths", () => {
    expect(validateColorHex("#")).toBe(false);
    expect(validateColorHex("#f")).toBe(false);
    expect(validateColorHex("#ff")).toBe(false);
    expect(validateColorHex("#fffff")).toBe(false);
    expect(validateColorHex("#fffffff")).toBe(false);
    expect(validateColorHex("#fffffffff")).toBe(false);
  });

  it("rejects strings containing non-hex characters", () => {
    expect(validateColorHex("#fffz")).toBe(false);
    expect(validateColorHex("#xyz")).toBe(false);
    expect(validateColorHex("#GGG")).toBe(false);
  });

  it("rejects color names and CSS values", () => {
    expect(validateColorHex("red")).toBe(false);
    expect(validateColorHex("rgb(0, 0, 0)")).toBe(false);
  });

  it("rejects strings with CSS injection payloads", () => {
    expect(
      validateColorHex("#fff; background-image: url(https://evil.example)")
    ).toBe(false);
    expect(validateColorHex("#fff;")).toBe(false);
  });
});

describe("toColorFormats", () => {
  it("translates hex into rgb and hsl", () => {
    expect(toColorFormats("#ff0000")).toEqual({
      hex: "#FF0000",
      rgb: "rgb(255, 0, 0)",
      hsl: "hsl(0, 100%, 50%)",
    });
  });

  it("returns shorthand hex without expanding it", () => {
    expect(toColorFormats("#fff")).toEqual({
      hex: "#FFF",
      rgb: "rgb(255, 255, 255)",
      hsl: "hsl(0, 0%, 100%)",
    });
  });

  it("returns the input notation unchanged", () => {
    expect(toColorFormats("hsl(68, 69%, 45%)").hsl).toBe("hsl(68, 69%, 45%)");
    expect(toColorFormats("rgba(0,0,0,.25)").rgb).toBe("rgba(0,0,0,.25)");
    expect(toColorFormats("hsla(0, 0%, 0%, 0.253)").hsl).toBe(
      "hsla(0, 0%, 0%, 0.253)"
    );
  });

  it("preserves alpha across notations", () => {
    expect(toColorFormats("#ff000080")).toEqual({
      hex: "#FF000080",
      rgb: "rgba(255, 0, 0, 0.5)",
      hsl: "hsla(0, 100%, 50%, 0.5)",
    });
  });

  it("accepts rgb and hsl input", () => {
    expect(toColorFormats("rgb(0, 0, 255)").hex).toBe("#0000FF");
    expect(toColorFormats("hsl(120, 100%, 50%)").hex).toBe("#00FF00");
    expect(toColorFormats("rgba(0, 0, 0, 0.25)").hsl).toBe(
      "hsla(0, 0%, 0%, 0.25)"
    );
  });

  it("throws for values that are not colors", () => {
    expect(() => toColorFormats("rgb(foo)")).toThrow();
  });
});

describe("ensureContrast", () => {
  it("returns the color when it is visible", () => {
    expect(ensureContrast("#0366D6", true)).toBe("#0366D6");
    expect(ensureContrast("#0366D6", false)).toBe("#0366D6");
  });

  it("returns the fallback for very dark colors in the dark theme", () => {
    expect(ensureContrast("#000000", true)).toBe("currentColor");
    expect(ensureContrast("#000000", false)).toBe("#000000");
  });

  it("returns the fallback for very light colors in the light theme", () => {
    expect(ensureContrast("#FFFFFF", false)).toBe("currentColor");
    expect(ensureContrast("#FFFFFF", true)).toBe("#FFFFFF");
  });

  it("returns the fallback when there is no color", () => {
    expect(ensureContrast(null, true, "#111")).toBe("#111");
    expect(ensureContrast(undefined, false)).toBe("currentColor");
  });

  it("returns currentColor unchanged", () => {
    expect(ensureContrast("currentColor", true, "#111")).toBe("currentColor");
  });
});

describe("hasSufficientContrast", () => {
  it("accepts colors with enough contrast", () => {
    expect(hasSufficientContrast("#000", "#fff")).toBe(true);
    expect(hasSufficientContrast("#fff", "#0366d6")).toBe(true);
  });

  it("rejects colors with low contrast", () => {
    expect(hasSufficientContrast("#fff", "#fdea9b")).toBe(false);
    expect(hasSufficientContrast("#111319", "#000")).toBe(false);
  });

  it("uses the given minimum ratio", () => {
    expect(hasSufficientContrast("#0366d6", "#111319", 3)).toBe(true);
    expect(hasSufficientContrast("#0366d6", "#111319", 4.5)).toBe(false);
  });

  it("does not reject colors that cannot be parsed", () => {
    expect(hasSufficientContrast("#12", "#fff")).toBe(true);
  });
});

describe("blendColors", () => {
  it("multiplies a color onto the backdrop", () => {
    expect(blendColors("#ffffff", "#336699", "multiply")).toBe("#336699");
    expect(blendColors("#000000", "#336699", "multiply")).toBe("#000000");
    expect(blendColors("#808080", "#ff0000", "multiply")).toBe("#800000");
  });

  it("screens a color onto the backdrop", () => {
    expect(blendColors("#000000", "#336699", "screen")).toBe("#336699");
    expect(blendColors("#ffffff", "#336699", "screen")).toBe("#ffffff");
    expect(blendColors("#808080", "#000000", "screen")).toBe("#808080");
  });

  it("applies the alpha of the color", () => {
    expect(blendColors("rgba(0, 0, 0, 0.5)", "#ffffff", "multiply")).toBe(
      "#808080"
    );
    expect(blendColors("rgba(255, 255, 255, 0)", "#336699", "screen")).toBe(
      "#336699"
    );
  });
});