90 lines
3.5 KiB
TypeScript
90 lines
3.5 KiB
TypeScript
/**
|
|
* system-theme.test.ts — dark/light mode detection for the "system" theme.
|
|
*
|
|
* Covers the pure luminance helper `detectModeFromBackground` and the
|
|
* `generateSystemTheme` defaults when the terminal cannot answer OSC queries
|
|
* (empty palette): the fallback background/foreground must follow the detected
|
|
* mode (dark → white-on-black, light → black-on-white) instead of always
|
|
* assuming a dark terminal.
|
|
*/
|
|
import { test, expect } from "bun:test";
|
|
import { RGBA, type TerminalColors } from "@opentui/core";
|
|
import {
|
|
detectModeFromBackground,
|
|
generateSystemTheme,
|
|
} from "../src/utils/system-theme";
|
|
|
|
/** A TerminalColors with no real values — simulates a terminal that can't
|
|
* answer OSC palette/background queries (e.g. tmux without forwarding). */
|
|
const EMPTY: TerminalColors = {
|
|
palette: Array.from({ length: 16 }, () => null),
|
|
defaultForeground: null,
|
|
defaultBackground: null,
|
|
cursorColor: null,
|
|
mouseForeground: null,
|
|
mouseBackground: null,
|
|
tekForeground: null,
|
|
tekBackground: null,
|
|
highlightBackground: null,
|
|
highlightForeground: null,
|
|
};
|
|
|
|
test("detectModeFromBackground maps dark backgrounds to dark", () => {
|
|
expect(detectModeFromBackground("#181825")).toBe("dark");
|
|
expect(detectModeFromBackground("#000000")).toBe("dark");
|
|
});
|
|
|
|
test("detectModeFromBackground maps light backgrounds to light", () => {
|
|
expect(detectModeFromBackground("#ffffff")).toBe("light");
|
|
expect(detectModeFromBackground("#f0f0f0")).toBe("light");
|
|
expect(detectModeFromBackground("#c8c8c8")).toBe("light");
|
|
});
|
|
|
|
test("detectModeFromBackground returns null without a background", () => {
|
|
expect(detectModeFromBackground(null)).toBeNull();
|
|
expect(detectModeFromBackground(undefined)).toBeNull();
|
|
expect(detectModeFromBackground("")).toBeNull();
|
|
});
|
|
|
|
test("empty palette in dark mode falls back to light-on-dark text", () => {
|
|
const theme = generateSystemTheme(EMPTY, "dark").theme;
|
|
// fg defaults to #ffffff; r/g/b are 0..1 floats
|
|
expect((theme.text as RGBA).r).toBeGreaterThan(0.9);
|
|
expect((theme.text as RGBA).g).toBeGreaterThan(0.9);
|
|
expect((theme.text as RGBA).b).toBeGreaterThan(0.9);
|
|
});
|
|
|
|
test("system theme declares a transparent background", () => {
|
|
const theme = generateSystemTheme(EMPTY, "dark").theme;
|
|
// The system theme lets the terminal's own background show through.
|
|
expect(theme.transparent).toBe(true);
|
|
expect((theme.background as RGBA).a).toBe(0);
|
|
});
|
|
|
|
test("empty palette in light mode falls back to dark-on-light text", () => {
|
|
const theme = generateSystemTheme(EMPTY, "light").theme;
|
|
// fg defaults to #000000
|
|
expect((theme.text as RGBA).r).toBeLessThan(0.1);
|
|
expect((theme.text as RGBA).g).toBeLessThan(0.1);
|
|
expect((theme.text as RGBA).b).toBeLessThan(0.1);
|
|
});
|
|
|
|
test("empty palette in light mode uses a light background, not black", () => {
|
|
const theme = generateSystemTheme(EMPTY, "light").theme;
|
|
// bg defaults to #ffffff; the diff/panel grays derive from it, so the
|
|
// backgroundPanel must be light (high luminance), not near-black.
|
|
expect((theme.backgroundPanel as RGBA).r).toBeGreaterThan(0.5);
|
|
});
|
|
|
|
test("a real light background yields a light theme regardless of mode arg", () => {
|
|
const colors: TerminalColors = {
|
|
...EMPTY,
|
|
defaultBackground: "#f5f5f5",
|
|
defaultForeground: "#111111",
|
|
};
|
|
const theme = generateSystemTheme(colors, "dark").theme;
|
|
// The actual terminal background wins over the mode default.
|
|
expect(detectModeFromBackground(colors.defaultBackground)).toBe("light");
|
|
expect((theme.backgroundPanel as RGBA).r).toBeGreaterThan(0.5);
|
|
});
|