This commit is contained in:
2026-09-12 13:59:12 +08:00
commit 941ce4baab
71 changed files with 13037 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
'use strict';
/**
* 「跟随系统」开 / 关 时主题显示一致性的接线测试。
*
* 历史问题theme:get / applyThemeChange 旧实现返回的是 appConfig.themeraw
* 渲染端拿到后直接设 data-theme ——「跟随系统」开着的状态下,初次打开设置窗口
* 显示的是 raw 主题(比如 midnight只有等到系统主题切换广播来才换。
* settings 窗口根本收不到那条广播(没切换),于是永远显示错的。
*
* 修法main.js 返回 effectiveTheme带 rawTheme 字段兜底),渲染端按
* effectiveTheme 设 DOM。theme-boot 也读 effectiveTheme 以避免冷启动闪。
*
* 这里钉住三件事,避免后续改动把 effective 字段删了回退到 raw
* 1. main.js 的 theme:get / applyThemeChange / broadcastTheme 三个出口
* 都给 effectiveTheme 字段;
* 2. 渲染端renderer + settings优先用 effectiveTheme 设置 data-theme
* 3. theme-boot.js 在缓存命中时也用 effectiveTheme。
*/
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');
const root = path.join(__dirname, '..');
const read = (p) => fs.readFileSync(path.join(root, p), 'utf8');
const mainSrc = read('main.js');
const rendererSrc = read('renderer/renderer.js');
const settingsSrc = read('renderer/settings.js');
const themeBootSrc = read('renderer/theme-boot.js');
let passed = 0;
function check(name, fn) {
try { fn(); console.log(' ok -', name); passed++; }
catch (e) { console.error(' FAIL -', name, e.message); process.exitCode = 1; }
}
// ---------- 主进程:所有主题出口都带 effectiveTheme ----------
check('config.effectiveTheme 存在并被 main.js 引用', () => {
assert.match(mainSrc, /configMod\.effectiveTheme\s*\(/,
'main.js 没用 configMod.effectiveTheme —— 跟随系统仍可能在 IPC 出口回退到 raw theme');
});
check('broadcastTheme 广播 effectiveTheme 字段', () => {
const fn = mainSrc.match(/function\s+broadcastTheme\s*\([\s\S]*?\n\}/);
assert.ok(fn, '找不到 broadcastTheme');
assert.match(fn[0], /effectiveTheme\s*:/,
'broadcastTheme 没带 effectiveTheme 字段,订阅的窗口拿不到跟随系统状态');
});
check('applyThemeChange 返回值带 effectiveTheme', () => {
const fn = mainSrc.match(/function\s+applyThemeChange\s*\([\s\S]*?\n\}/);
assert.ok(fn, '找不到 applyThemeChange');
assert.match(fn[0], /effectiveTheme\s*:/,
'applyThemeChange 返回值没带 effectiveTheme —— settings.js 收到 raw theme 会盖掉刚广播的 effective');
});
check('theme:get 处理器返回 effectiveTheme', () => {
const handler = mainSrc.match(/ipcMain\.handle\(\s*'theme:get'[\s\S]*?\n\s{2}\}\s*\)\s*;/);
assert.ok(handler, '找不到 theme:get 处理器');
assert.match(handler[0], /effectiveTheme/,
'theme:get 返回值没带 effectiveTheme —— 启动时设置窗口 / 主窗口会显示 raw 主题');
});
// ---------- 渲染端:用 effectiveTheme 设 data-theme ----------
check('renderer.js 的 applyTheme 用 effectiveTheme 设 data-theme', () => {
const fn = rendererSrc.match(/async\s+function\s+applyTheme\s*\([\s\S]*?\n\}/);
assert.ok(fn, '找不到 applyTheme');
// 必须显式读 cfg.effectiveTheme 而不是 cfg.theme
assert.match(fn[0], /cfg\.effectiveTheme\s*\|\|\s*cfg\.theme/,
'applyTheme 没读 effectiveTheme ——「跟随系统」开时 data-theme 是 raw 主题');
});
check('renderer.js 的 applyTheme 在 localStorage 里同时缓存 raw 和 effective', () => {
// theme-boot 启动读 cache需要 effectiveTheme 才能避免冷启动闪
const fn = rendererSrc.match(/async\s+function\s+applyTheme\s*\([\s\S]*?\n\}/);
assert.ok(fn, '找不到 applyTheme');
assert.match(fn[0], /rawTheme[\s\S]*?effectiveTheme/,
'applyTheme 没把 raw 和 effective 同时写 localStorage —— 启动会有闪');
});
check('renderer.js 的 onSystemChanged 不再写 localStorage避免覆盖 raw', () => {
const fn = rendererSrc.match(/onSystemChanged\(\s*\(payload\)\s*=>\s*\{[\s\S]*?\}\s*\)/);
assert.ok(fn, '找不到 onSystemChanged 回调');
// 注释也明确写了为什么不写payload 里没 rawTheme
assert.ok(
!/localStorage\.setItem/.test(fn[0]),
'onSystemChanged 在写 localStorage —— payload 没有 rawTheme下次启动会拿不到 raw'
);
// DOM 更新仍然要用 effective
assert.match(fn[0], /effectiveTheme\s*\|\|\s*payload\.theme/,
'onSystemChanged 没读 effectiveTheme');
});
check('settings.js initTheme 用 effectiveTheme', () => {
const fn = settingsSrc.match(/async\s+function\s+initTheme\s*\([\s\S]*?\n\}/);
assert.ok(fn, '找不到 initTheme');
assert.match(fn[0], /cfg\.effectiveTheme\s*\|\|\s*cfg\.theme/,
'initTheme 没读 effectiveTheme —— 设置窗口初次打开「跟随系统」开时显示 raw');
});
check('settings.js onSystemChanged 用 effectiveTheme', () => {
const fn = settingsSrc.match(/onSystemChanged\(\s*\(payload\)\s*=>\s*\{[\s\S]*?\}\s*\)/);
assert.ok(fn, '找不到 settings.js onSystemChanged');
assert.match(fn[0], /effectiveTheme\s*\|\|\s*payload\.theme/,
'settings.js onSystemChanged 没读 effectiveTheme');
});
// ---------- theme-boot冷启动也用 effectiveTheme 避免闪 ----------
check('theme-boot.js 优先读 effectiveTheme避免「跟随系统」开时冷启动闪', () => {
assert.match(themeBootSrc, /effectiveTheme\s*\|\|\s*cached\.theme/,
'theme-boot.js 没读 effectiveTheme —— 冷启动在「跟随系统」开时会闪一下 raw 主题');
});
console.log(`\n${passed} checks passed`);