feat: enhance CI workflow and update webapp styles
Some checks failed
CI / lint-and-test (push) Failing after 45s
Some checks failed
CI / lint-and-test (push) Failing after 45s
- Added Node.js setup and webapp testing steps to the CI workflow for improved integration. - Updated HTML to link multiple CSS files for better modularity and organization of styles. - Removed deprecated `style.css` and introduced new CSS files for base styles, calendar, day detail, hints, markers, states, and duty list to enhance maintainability and readability. - Implemented new styles for improved presentation of duty information and user interactions. - Added unit tests for new API functions and contact link rendering to ensure functionality and reliability.
This commit is contained in:
152
webapp/js/theme.test.js
Normal file
152
webapp/js/theme.test.js
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Unit tests for theme: getTheme, applyThemeParamsToCss, applyTheme, initTheme.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
|
||||
|
||||
describe("theme", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("getTheme", () => {
|
||||
it("returns Telegram.WebApp.colorScheme when set", async () => {
|
||||
globalThis.window.Telegram = { WebApp: { colorScheme: "light" } };
|
||||
vi.spyOn(document.documentElement.style, "getPropertyValue").mockReturnValue("");
|
||||
const { getTheme } = await import("./theme.js");
|
||||
expect(getTheme()).toBe("light");
|
||||
});
|
||||
|
||||
it("falls back to --tg-color-scheme CSS when TWA has no colorScheme", async () => {
|
||||
globalThis.window.Telegram = { WebApp: {} };
|
||||
vi.spyOn(globalThis, "getComputedStyle").mockReturnValue({
|
||||
getPropertyValue: vi.fn().mockReturnValue("dark"),
|
||||
});
|
||||
const { getTheme } = await import("./theme.js");
|
||||
expect(getTheme()).toBe("dark");
|
||||
});
|
||||
|
||||
it("falls back to matchMedia prefers-color-scheme dark", async () => {
|
||||
globalThis.window.Telegram = { WebApp: {} };
|
||||
vi.spyOn(globalThis, "getComputedStyle").mockReturnValue({
|
||||
getPropertyValue: vi.fn().mockReturnValue(""),
|
||||
});
|
||||
vi.spyOn(globalThis, "matchMedia").mockReturnValue({
|
||||
matches: true,
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
});
|
||||
const { getTheme } = await import("./theme.js");
|
||||
expect(getTheme()).toBe("dark");
|
||||
});
|
||||
|
||||
it("returns light when matchMedia prefers light", async () => {
|
||||
globalThis.window.Telegram = { WebApp: {} };
|
||||
vi.spyOn(globalThis, "getComputedStyle").mockReturnValue({
|
||||
getPropertyValue: vi.fn().mockReturnValue(""),
|
||||
});
|
||||
vi.spyOn(globalThis, "matchMedia").mockReturnValue({
|
||||
matches: false,
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
});
|
||||
const { getTheme } = await import("./theme.js");
|
||||
expect(getTheme()).toBe("light");
|
||||
});
|
||||
|
||||
it("falls back to matchMedia when getComputedStyle throws", async () => {
|
||||
globalThis.window.Telegram = { WebApp: {} };
|
||||
vi.spyOn(globalThis, "getComputedStyle").mockImplementation(() => {
|
||||
throw new Error("getComputedStyle not available");
|
||||
});
|
||||
vi.spyOn(globalThis, "matchMedia").mockReturnValue({
|
||||
matches: true,
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
});
|
||||
const { getTheme } = await import("./theme.js");
|
||||
expect(getTheme()).toBe("dark");
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyThemeParamsToCss", () => {
|
||||
it("does nothing when Telegram.WebApp or themeParams missing", async () => {
|
||||
globalThis.window.Telegram = undefined;
|
||||
const setProperty = vi.fn();
|
||||
document.documentElement.style.setProperty = setProperty;
|
||||
const { applyThemeParamsToCss } = await import("./theme.js");
|
||||
applyThemeParamsToCss();
|
||||
expect(setProperty).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sets --tg-theme-* CSS variables from themeParams", async () => {
|
||||
globalThis.window.Telegram = {
|
||||
WebApp: {
|
||||
themeParams: {
|
||||
bg_color: "#ffffff",
|
||||
text_color: "#000000",
|
||||
hint_color: "#888888",
|
||||
},
|
||||
},
|
||||
};
|
||||
const setProperty = vi.fn();
|
||||
document.documentElement.style.setProperty = setProperty;
|
||||
const { applyThemeParamsToCss } = await import("./theme.js");
|
||||
applyThemeParamsToCss();
|
||||
expect(setProperty).toHaveBeenCalledWith("--tg-theme-bg-color", "#ffffff");
|
||||
expect(setProperty).toHaveBeenCalledWith("--tg-theme-text-color", "#000000");
|
||||
expect(setProperty).toHaveBeenCalledWith("--tg-theme-hint-color", "#888888");
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyTheme", () => {
|
||||
beforeEach(() => {
|
||||
document.documentElement.dataset.theme = "";
|
||||
});
|
||||
|
||||
it("sets data-theme on documentElement from getTheme", async () => {
|
||||
const theme = await import("./theme.js");
|
||||
vi.spyOn(theme, "getTheme").mockReturnValue("light");
|
||||
theme.applyTheme();
|
||||
expect(document.documentElement.dataset.theme).toBe("light");
|
||||
});
|
||||
|
||||
it("calls setBackgroundColor and setHeaderColor when TWA present", async () => {
|
||||
const setBackgroundColor = vi.fn();
|
||||
const setHeaderColor = vi.fn();
|
||||
globalThis.window.Telegram = {
|
||||
WebApp: {
|
||||
setBackgroundColor: setBackgroundColor,
|
||||
setHeaderColor: setHeaderColor,
|
||||
themeParams: null,
|
||||
},
|
||||
};
|
||||
const { applyTheme } = await import("./theme.js");
|
||||
applyTheme();
|
||||
expect(setBackgroundColor).toHaveBeenCalledWith("bg_color");
|
||||
expect(setHeaderColor).toHaveBeenCalledWith("bg_color");
|
||||
});
|
||||
});
|
||||
|
||||
describe("initTheme", () => {
|
||||
it("runs without throwing when TWA present", async () => {
|
||||
globalThis.window.Telegram = { WebApp: {} };
|
||||
const { initTheme } = await import("./theme.js");
|
||||
expect(() => initTheme()).not.toThrow();
|
||||
});
|
||||
|
||||
it("adds matchMedia change listener when no TWA", async () => {
|
||||
globalThis.window.Telegram = undefined;
|
||||
const addEventListener = vi.fn();
|
||||
vi.spyOn(globalThis, "matchMedia").mockReturnValue({
|
||||
matches: false,
|
||||
addEventListener,
|
||||
removeEventListener: vi.fn(),
|
||||
});
|
||||
const { initTheme } = await import("./theme.js");
|
||||
initTheme();
|
||||
expect(addEventListener).toHaveBeenCalledWith("change", expect.any(Function));
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user