BlueSky & more on desktop lazurite.stormlightlabs.org/
tauri rust typescript bluesky appview atproto solid
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 105 lines 3.6 kB view raw
1import { ThemeController } from "$/components/theme/ThemeController"; 2import type { AppSettings } from "$/lib/types"; 3import { AppTestProviders } from "$/test/providers"; 4import { render, waitFor } from "@solidjs/testing-library"; 5import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; 6 7type ThemeChangeHandler = (event: { payload: "light" | "dark" }) => void; 8const noopUnlisten = () => {}; 9 10const tauriThemeMock = vi.hoisted(() => vi.fn(async () => null as "light" | "dark" | null)); 11const onThemeChangedMock = vi.hoisted(() => vi.fn(async (_handler: ThemeChangeHandler) => noopUnlisten)); 12 13vi.mock( 14 "@tauri-apps/api/window", 15 () => ({ getCurrentWindow: () => ({ label: "main", onThemeChanged: onThemeChangedMock, theme: tauriThemeMock }) }), 16); 17 18function installMatchMedia(initialDark: boolean) { 19 const listeners = new Set<(event: MediaQueryListEvent) => void>(); 20 const media = { 21 matches: initialDark, 22 media: "(prefers-color-scheme: dark)", 23 onchange: null, 24 addEventListener: (_type: string, listener: (event: MediaQueryListEvent) => void) => { 25 listeners.add(listener); 26 }, 27 removeEventListener: (_type: string, listener: (event: MediaQueryListEvent) => void) => { 28 listeners.delete(listener); 29 }, 30 addListener: (listener: (event: MediaQueryListEvent) => void) => { 31 listeners.add(listener); 32 }, 33 removeListener: (listener: (event: MediaQueryListEvent) => void) => { 34 listeners.delete(listener); 35 }, 36 dispatch(nextDark: boolean) { 37 media.matches = nextDark; 38 const event = { matches: nextDark } as MediaQueryListEvent; 39 for (const listener of listeners) { 40 listener(event); 41 } 42 }, 43 }; 44 45 Object.defineProperty(globalThis, "matchMedia", { configurable: true, writable: true, value: vi.fn(() => media) }); 46 47 return media; 48} 49 50describe("ThemeController", () => { 51 const baseSettings: AppSettings = { 52 theme: "auto", 53 timelineRefreshSecs: 60, 54 notificationsDesktop: true, 55 notificationsBadge: true, 56 notificationsSound: false, 57 embeddingsEnabled: false, 58 constellationUrl: "https://constellation.microcosm.blue", 59 spacedustUrl: "https://spacedust.microcosm.blue", 60 spacedustInstant: false, 61 spacedustEnabled: false, 62 globalShortcut: "Ctrl+Shift+N", 63 downloadDirectory: "/Users/test/Downloads", 64 }; 65 66 beforeEach(() => { 67 tauriThemeMock.mockReset(); 68 tauriThemeMock.mockResolvedValue(null); 69 onThemeChangedMock.mockReset(); 70 onThemeChangedMock.mockResolvedValue(noopUnlisten); 71 }); 72 73 afterEach(() => { 74 delete document.documentElement.dataset.theme; 75 document.documentElement.style.colorScheme = ""; 76 }); 77 78 it("applies explicit light theme", async () => { 79 installMatchMedia(true); 80 81 render(() => ( 82 <AppTestProviders preferences={{ settings: { ...baseSettings, theme: "light" } }}> 83 <ThemeController /> 84 </AppTestProviders> 85 )); 86 87 await waitFor(() => expect(document.documentElement.dataset.theme).toBe("light")); 88 expect(document.documentElement.style.colorScheme).toBe("light"); 89 }); 90 91 it("follows system theme changes when setting is auto", async () => { 92 const media = installMatchMedia(true); 93 94 render(() => ( 95 <AppTestProviders preferences={{ settings: { ...baseSettings, theme: "auto" } }}> 96 <ThemeController /> 97 </AppTestProviders> 98 )); 99 100 await waitFor(() => expect(document.documentElement.dataset.theme).toBe("dark")); 101 102 media.dispatch(false); 103 await waitFor(() => expect(document.documentElement.dataset.theme).toBe("light")); 104 }); 105});