Files
OwnCord/Client/tauri-client/tests/unit/os-motion.test.ts
T
jevb b4f7ce9098 fix: settings tab bug fixes, expanded tests, and coverage improvements
Fix multiple bugs across settings tabs (AppearanceTab theme restoration,
AdvancedTab testability, LogsTab refresh, VoiceAudioTab device listing),
harden embeds/media/attachments with cache validation, add logPersistence
rotation logic, and add 8 new test files with expanded test cases for
existing tests. Brings client test coverage from ~68% to ~72%.
2026-03-30 12:42:31 +02:00

131 lines
4.6 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { syncOsMotionListener } from "../../src/lib/os-motion";
describe("syncOsMotionListener", () => {
let matchMediaListeners: Map<string, Function>;
let matchMediaMatches: boolean;
beforeEach(() => {
matchMediaListeners = new Map();
matchMediaMatches = false;
// Mock matchMedia to return a controllable MediaQueryList
vi.spyOn(window, "matchMedia").mockImplementation((_query: string) => {
const mql = {
matches: matchMediaMatches,
media: _query,
onchange: null,
addListener: vi.fn(),
removeListener: vi.fn(),
addEventListener: vi.fn((type: string, handler: Function, _opts?: any) => {
matchMediaListeners.set(type, handler);
}),
removeEventListener: vi.fn(),
dispatchEvent: vi.fn(() => true),
} as unknown as MediaQueryList;
return mql;
});
// Clean up any leftover class/storage from previous tests
document.documentElement.classList.remove("reduced-motion");
localStorage.clear();
});
afterEach(() => {
// Disable the listener to clean up internal state
syncOsMotionListener(false);
document.documentElement.classList.remove("reduced-motion");
});
it("adds reduced-motion class when OS prefers reduced motion", () => {
matchMediaMatches = true;
syncOsMotionListener(true);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(true);
});
it("does not add reduced-motion class when OS has no preference", () => {
matchMediaMatches = false;
syncOsMotionListener(true);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(false);
});
it("restores manual preference when sync is disabled", () => {
// User manually set reducedMotion=false
localStorage.setItem("owncord:settings:reducedMotion", "false");
// OS says reduce motion → sync adds the class
matchMediaMatches = true;
syncOsMotionListener(true);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(true);
// Turn off sync → should restore manual preference (false)
syncOsMotionListener(false);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(false);
});
it("restores manual reduced-motion=true when sync is disabled", () => {
// User manually set reducedMotion=true
localStorage.setItem("owncord:settings:reducedMotion", "true");
// OS says NO reduce motion → sync removes the class
matchMediaMatches = false;
syncOsMotionListener(true);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(false);
// Turn off sync → should restore manual preference (true)
syncOsMotionListener(false);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(true);
});
it("responds to media query change events", () => {
matchMediaMatches = false;
syncOsMotionListener(true);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(false);
// Simulate OS preference change
const changeHandler = matchMediaListeners.get("change");
expect(changeHandler).toBeDefined();
changeHandler!({ matches: true } as MediaQueryListEvent);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(true);
// Simulate changing back
changeHandler!({ matches: false } as MediaQueryListEvent);
expect(document.documentElement.classList.contains("reduced-motion")).toBe(false);
});
it("is safe to call multiple times (re-registration)", () => {
matchMediaMatches = true;
syncOsMotionListener(true);
syncOsMotionListener(true);
// Should still work correctly — no duplicate listeners
expect(document.documentElement.classList.contains("reduced-motion")).toBe(true);
expect(window.matchMedia).toHaveBeenCalledWith("(prefers-reduced-motion: reduce)");
});
it("is safe to disable when never enabled", () => {
// Should not throw
expect(() => syncOsMotionListener(false)).not.toThrow();
});
it("tears down previous listener when re-enabling", () => {
matchMediaMatches = false;
syncOsMotionListener(true);
const firstChangeHandler = matchMediaListeners.get("change");
// Re-enable — should create a new listener
syncOsMotionListener(true);
const secondChangeHandler = matchMediaListeners.get("change");
// The handlers come from different matchMedia calls
// Both are defined (the map just holds the latest)
expect(firstChangeHandler).toBeDefined();
expect(secondChangeHandler).toBeDefined();
});
});