返回 DeepSeek-Reasonix
theme-auto-background.test.ts
根目录 / desktop / frontend / src / __tests__ / theme-auto-background.test.ts
1 // Run: tsx src/__tests__/theme-auto-background.test.ts
2
3 import { readFileSync } from "node:fs";
4 import { dirname, resolve } from "node:path";
5 import { fileURLToPath } from "node:url";
6
7 const testDir = dirname(fileURLToPath(import.meta.url));
8 const themeSource = readFileSync(resolve(testDir, "../lib/theme.ts"), "utf8");
9 const stylesSource = readFileSync(resolve(testDir, "../styles.css"), "utf8");
10 const chatTranscriptSource = readFileSync(resolve(testDir, "../components/ChatTranscript.css"), "utf8");
11
12 let passed = 0;
13 let failed = 0;
14
15 function ok(value: boolean, label: string) {
16 if (value) {
17 process.stdout.write(` PASS ${label}\n`);
18 passed += 1;
19 } else {
20 process.stdout.write(` FAIL ${label}\n`);
21 failed += 1;
22 }
23 }
24
25 function blockAfter(source: string, needle: string, after = 0): string {
26 const selectorIndex = source.indexOf(needle, after);
27 if (selectorIndex < 0) return "";
28 const open = source.indexOf("{", selectorIndex);
29 if (open < 0) return "";
30
31 let depth = 0;
32 for (let index = open; index < source.length; index += 1) {
33 const char = source[index];
34 if (char === "{") depth += 1;
35 else if (char === "}") {
36 depth -= 1;
37 if (depth === 0) return source.slice(open + 1, index);
38 }
39 }
40 return "";
41 }
42
43 console.log("\ntheme auto native background contract");
44
45 ok(
46 themeSource.includes('const AUTO_THEME_MEDIA_QUERY = "(prefers-color-scheme: light)";'),
47 "auto theme uses one shared light color-scheme media query",
48 );
49 ok(
50 themeSource.includes("window.matchMedia?.(AUTO_THEME_MEDIA_QUERY).matches"),
51 "resolved auto theme reads the shared color-scheme query",
52 );
53 ok(
54 themeSource.includes("syncAutoThemeBackgroundListener(theme);"),
55 "applyTheme updates the native auto-theme listener",
56 );
57 ok(
58 themeSource.includes('autoThemeMediaQuery.addEventListener("change", syncAutoThemeBackground)'),
59 "auto mode listens for color-scheme changes",
60 );
61 ok(
62 themeSource.includes('autoThemeMediaQuery.removeEventListener("change", syncAutoThemeBackground)'),
63 "explicit modes remove the color-scheme listener",
64 );
65 ok(
66 themeSource.includes('if (theme !== "auto")') && themeSource.includes("clearAutoThemeBackgroundListener();"),
67 "non-auto themes clear the auto listener",
68 );
69 ok(
70 themeSource.includes('if (currentTheme === "auto"') && themeSource.includes('syncNativeWindowBackground("auto")'),
71 "color-scheme changes only sync native background while auto is active",
72 );
73 ok(
74 themeSource.includes("if (autoThemeMediaQuery || typeof window"),
75 "reapplying auto does not register duplicate listeners",
76 );
77
78 const workbenchRefreshIndex = stylesSource.indexOf("Native Workbench refresh");
79 const workbenchSource = workbenchRefreshIndex >= 0 ? stylesSource.slice(workbenchRefreshIndex) : "";
80 const workbenchLightBlock = blockAfter(workbenchSource, ':root[data-theme="light"]');
81 const workbenchAutoLightMediaIndex = workbenchSource.indexOf("@media (prefers-color-scheme: light)");
82 const workbenchAutoLightBlock = blockAfter(workbenchSource, ":root:not([data-theme])", workbenchAutoLightMediaIndex);
83
84 ok(workbenchRefreshIndex >= 0, "styles include the native workbench theme refresh section");
85 ok(workbenchAutoLightMediaIndex >= 0, "workbench refresh has an auto-mode light media override");
86 ok(
87 workbenchLightBlock.includes("--bg: #e9edf3;") && workbenchAutoLightBlock.includes("--bg: #e9edf3;"),
88 "auto light mode keeps the workbench light background after late root overrides",
89 );
90 ok(
91 workbenchLightBlock.includes("--fg: #121722;") && workbenchAutoLightBlock.includes("--fg: #121722;"),
92 "auto light mode keeps the workbench light foreground after late root overrides",
93 );
94 ok(
95 workbenchLightBlock.includes("--workspace-files-bg: #f1f4f8;") &&
96 workbenchAutoLightBlock.includes("--workspace-files-bg: #f1f4f8;"),
97 "auto light mode keeps workbench panel surfaces aligned with forced light mode",
98 );
99
100 const transcriptBlock = blockAfter(chatTranscriptSource, ".chat-transcript");
101 const assistantBlock = blockAfter(chatTranscriptSource, '.chat-node[data-chat-kind="assistant"]');
102 ok(transcriptBlock.includes("color: var(--fg)"), "new transcript inherits the active theme foreground token");
103 ok(assistantBlock.includes("color: var(--fg)"), "assistant nodes use the active theme foreground token");
104 ok(!chatTranscriptSource.includes("color-mix(in srgb, var(--fg) 90%, var(--bg))"),
105 "assistant text no longer needs a creation-mode light-theme override");
106
107 console.log(`\n${passed} passed, ${failed} failed, ${passed + failed} total`);
108 if (failed > 0) process.exit(1);
109
109 lines TYPESCRIPT