93 lines
3.2 KiB
TypeScript
93 lines
3.2 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
import {
|
|
clearLegacyTaskColors,
|
|
readLegacyTaskColors,
|
|
TASK_COLORS,
|
|
TASK_COLOR_BAR_CLASS,
|
|
TASK_COLOR_LABEL_KEYS,
|
|
TASK_COLORS_STORAGE_KEY,
|
|
parseSidebarTaskColors,
|
|
} from "./task-colors";
|
|
import { i18n, t } from "@/lib/i18n";
|
|
|
|
describe("legacy task colors migration input", () => {
|
|
beforeEach(() => {
|
|
window.localStorage.clear();
|
|
});
|
|
|
|
it("reads valid legacy colors without treating them as server values", () => {
|
|
window.localStorage.setItem(
|
|
TASK_COLORS_STORAGE_KEY,
|
|
JSON.stringify({
|
|
"task-1": "red",
|
|
"task-cleared": null,
|
|
"task-automatic-gray": "gray",
|
|
"task-2": "blue",
|
|
}),
|
|
);
|
|
expect(readLegacyTaskColors()).toEqual({ "task-1": "red", "task-2": "blue" });
|
|
});
|
|
|
|
it("returns no values for malformed legacy storage", () => {
|
|
window.localStorage.setItem(TASK_COLORS_STORAGE_KEY, "{not json");
|
|
expect(readLegacyTaskColors()).toEqual({});
|
|
});
|
|
|
|
it("removes the legacy key only when migration asks for removal", () => {
|
|
window.localStorage.setItem(TASK_COLORS_STORAGE_KEY, JSON.stringify({ "task-1": "red" }));
|
|
clearLegacyTaskColors();
|
|
expect(window.localStorage.getItem(TASK_COLORS_STORAGE_KEY)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("TASK_COLOR_LABEL_KEYS", () => {
|
|
afterEach(async () => {
|
|
await i18n.changeLanguage("en");
|
|
});
|
|
|
|
it("covers every colour, keyed by the persisted wire value", () => {
|
|
expect(Object.keys(TASK_COLOR_LABEL_KEYS).sort()).toEqual([...TASK_COLORS].sort());
|
|
// The same wire values index the class table, so they are identity.
|
|
expect(Object.keys(TASK_COLOR_BAR_CLASS).sort()).toEqual([...TASK_COLORS].sort());
|
|
});
|
|
|
|
it("holds catalog keys that resolve to English copy", () => {
|
|
expect(TASK_COLOR_LABEL_KEYS.red).toBe("task:colorRed");
|
|
const labels = TASK_COLORS.map((c) => t(TASK_COLOR_LABEL_KEYS[c]));
|
|
expect(labels).toEqual(["Red", "Orange", "Yellow", "Green", "Blue", "Purple", "Pink"]);
|
|
});
|
|
|
|
it("stores keys rather than resolved copy, so a locale switch takes effect", async () => {
|
|
await i18n.changeLanguage("pseudo");
|
|
for (const color of TASK_COLORS) {
|
|
const label = t(TASK_COLOR_LABEL_KEYS[color]);
|
|
// A missing key would resolve to the key itself; frozen copy would stay
|
|
// English. Both are ruled out by an accented, non-key label.
|
|
expect(label).not.toBe(TASK_COLOR_LABEL_KEYS[color]);
|
|
expect(label).toMatch(/[^\p{ASCII}]/u);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("backend manual task-color map parsing", () => {
|
|
it("keeps valid colors and tombstones while dropping malformed entries", () => {
|
|
expect(
|
|
parseSidebarTaskColors({
|
|
"task-red": "red",
|
|
"task-cleared": null,
|
|
"task-automatic-gray": "gray",
|
|
"": "blue",
|
|
"task-object": {},
|
|
}),
|
|
).toEqual({ "task-red": "red", "task-cleared": null });
|
|
});
|
|
|
|
it("caps task IDs by UTF-8 byte length and entry count", () => {
|
|
expect(parseSidebarTaskColors({ ["é".repeat(65)]: "red" })).toEqual({});
|
|
const input = Object.fromEntries(
|
|
Array.from({ length: 10_001 }, (_, index) => [`task-${index}`, "red"]),
|
|
);
|
|
expect(Object.keys(parseSidebarTaskColors(input))).toHaveLength(10_000);
|
|
});
|
|
});
|