- Updated CSS to utilize viewport variables for safe area insets and stable height, improving layout consistency across devices. - Introduced haptic feedback triggers in various components to enhance user interaction, mimicking native Telegram behavior. - Added functionality to detect Android performance class, minimizing animations on low-performance devices for better user experience. - Refactored components to incorporate new CSS classes for content safety and improved responsiveness.
142 lines
4.5 KiB
TypeScript
142 lines
4.5 KiB
TypeScript
/**
|
|
* Unit tests for useTelegramTheme, getFallbackScheme, and applyTheme.
|
|
* Ported from webapp/js/theme.test.js (getTheme, applyTheme).
|
|
*/
|
|
|
|
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
import { renderHook } from "@testing-library/react";
|
|
import {
|
|
useTelegramTheme,
|
|
getFallbackScheme,
|
|
applyTheme,
|
|
} from "./use-telegram-theme";
|
|
|
|
vi.mock("@telegram-apps/sdk-react", () => ({
|
|
useSignal: vi.fn(() => undefined),
|
|
isThemeParamsDark: vi.fn(),
|
|
setMiniAppBackgroundColor: { isAvailable: vi.fn(() => false) },
|
|
setMiniAppHeaderColor: { isAvailable: vi.fn(() => false) },
|
|
setMiniAppBottomBarColor: { isAvailable: vi.fn(() => false) },
|
|
}));
|
|
|
|
describe("getFallbackScheme", () => {
|
|
const originalMatchMedia = window.matchMedia;
|
|
const originalGetComputedStyle = window.getComputedStyle;
|
|
|
|
afterEach(() => {
|
|
window.matchMedia = originalMatchMedia;
|
|
window.getComputedStyle = originalGetComputedStyle;
|
|
document.documentElement.removeAttribute("data-theme");
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("returns dark when prefers-color-scheme is dark", () => {
|
|
window.matchMedia = vi.fn((query: string) => ({
|
|
matches: query === "(prefers-color-scheme: dark)",
|
|
media: query,
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
onchange: null,
|
|
})) as unknown as typeof window.matchMedia;
|
|
expect(getFallbackScheme()).toBe("dark");
|
|
});
|
|
|
|
it("returns light when prefers-color-scheme is light", () => {
|
|
window.matchMedia = vi.fn((query: string) => ({
|
|
matches: query === "(prefers-color-scheme: light)",
|
|
media: query,
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
onchange: null,
|
|
})) as unknown as typeof window.matchMedia;
|
|
expect(getFallbackScheme()).toBe("light");
|
|
});
|
|
|
|
it("uses --tg-color-scheme when set on document", () => {
|
|
window.getComputedStyle = vi.fn(() =>
|
|
Object.assign(
|
|
{},
|
|
{
|
|
getPropertyValue: (prop: string) =>
|
|
prop === "--tg-color-scheme" ? " light " : "",
|
|
}
|
|
)
|
|
) as unknown as typeof window.getComputedStyle;
|
|
expect(getFallbackScheme()).toBe("light");
|
|
});
|
|
|
|
it("uses --tg-color-scheme dark when set", () => {
|
|
window.getComputedStyle = vi.fn(() =>
|
|
Object.assign(
|
|
{},
|
|
{
|
|
getPropertyValue: (prop: string) =>
|
|
prop === "--tg-color-scheme" ? "dark" : "",
|
|
}
|
|
)
|
|
) as unknown as typeof window.getComputedStyle;
|
|
expect(getFallbackScheme()).toBe("dark");
|
|
});
|
|
});
|
|
|
|
describe("applyTheme", () => {
|
|
afterEach(() => {
|
|
document.documentElement.removeAttribute("data-theme");
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("sets data-theme to given scheme", () => {
|
|
applyTheme("light");
|
|
expect(document.documentElement.getAttribute("data-theme")).toBe("light");
|
|
applyTheme("dark");
|
|
expect(document.documentElement.getAttribute("data-theme")).toBe("dark");
|
|
});
|
|
|
|
it("resolves scheme via getFallbackScheme when no argument", () => {
|
|
window.matchMedia = vi.fn((query: string) => ({
|
|
matches: query === "(prefers-color-scheme: dark)",
|
|
media: query,
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
onchange: null,
|
|
})) as unknown as typeof window.matchMedia;
|
|
applyTheme();
|
|
expect(document.documentElement.getAttribute("data-theme")).toBe("dark");
|
|
});
|
|
});
|
|
|
|
describe("useTelegramTheme", () => {
|
|
const originalMatchMedia = window.matchMedia;
|
|
const originalGetComputedStyle = window.getComputedStyle;
|
|
|
|
afterEach(() => {
|
|
window.matchMedia = originalMatchMedia;
|
|
window.getComputedStyle = originalGetComputedStyle;
|
|
document.documentElement.removeAttribute("data-theme");
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("sets data-theme to dark when useSignal returns true", async () => {
|
|
const { useSignal } = await import("@telegram-apps/sdk-react");
|
|
vi.mocked(useSignal).mockReturnValue(true);
|
|
renderHook(() => useTelegramTheme());
|
|
expect(document.documentElement.getAttribute("data-theme")).toBe("dark");
|
|
});
|
|
|
|
it("sets data-theme to light when useSignal returns false", async () => {
|
|
const { useSignal } = await import("@telegram-apps/sdk-react");
|
|
vi.mocked(useSignal).mockReturnValue(false);
|
|
renderHook(() => useTelegramTheme());
|
|
expect(document.documentElement.getAttribute("data-theme")).toBe("light");
|
|
});
|
|
});
|