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

107
test/settings-tabs.test.js Normal file
View File

@@ -0,0 +1,107 @@
'use strict';
// 在真实 Electron 窗口尺寸(420x690与 main.js openSettingsWindow 一致)下
// 验证设置窗口的标签页与布局。
// 运行electron test/settings-tabs.test.js
const assert = require('node:assert');
const path = require('node:path');
const { app, BrowserWindow, ipcMain } = require('electron');
const cfg = {
autoLaunch: false, maxItems: 0, displayLimit: 300, pollMs: 1000,
dataDir: 'C:\\Users\\guan\\.clipboard-app',
theme: 'linear', accent: 'purple', followSystem: false,
};
ipcMain.handle('settings:get', () => ({ ...cfg }));
ipcMain.handle('settings:set', () => ({ ...cfg }));
ipcMain.handle('settings:clear-history', () => 0);
ipcMain.handle('settings:open-dir', () => {});
ipcMain.handle('settings:choose-dir', () => ({ ok: false }));
ipcMain.handle('theme:get', () => ({ ...cfg }));
ipcMain.handle('theme:set', (_e, { theme }) => ({ theme, accent: cfg.accent }));
ipcMain.handle('theme:set-accent', (_e, { accent }) => ({ theme: cfg.theme, accent }));
ipcMain.handle('theme:set-follow-system', () => ({ theme: cfg.theme, accent: cfg.accent }));
// 与 settings-render.test.js 同理settings.js 启动时会订阅主题变更,
// stub 缺这个 handler 会往终端打一条未捕获错误(此测试不断言 console
// 但留着噪音会掩盖真问题)。
ipcMain.handle('theme:subscribe', () => true);
let passed = 0;
async function check(name, fn) {
try { await fn(); console.log(' ok -', name); passed++; }
catch (e) { console.error(' FAIL -', name, '\n', e.message); process.exitCode = 1; }
}
app.whenReady().then(async () => {
const win = new BrowserWindow({
width: 420, height: 690, show: false, frame: false, resizable: false,
webPreferences: {
preload: path.join(__dirname, '..', 'preload.js'),
contextIsolation: true, nodeIntegration: false, sandbox: false,
},
});
await win.loadFile(path.join(__dirname, '..', 'renderer', 'settings.html'));
await new Promise((r) => setTimeout(r, 900));
const js = (code) => win.webContents.executeJavaScript(code);
await check('三个标签存在且文案顺序正确', async () => {
const labels = JSON.parse(await js(
`JSON.stringify([...document.querySelectorAll('#tab-bar [role="tab"]')].map(t => t.textContent.trim()))`
));
assert.deepStrictEqual(labels, ['外观', '通用', '关于']);
});
await check('初始只显示「外观」页', async () => {
const r = JSON.parse(await js(`JSON.stringify({
visible: [...document.querySelectorAll('.tab-panel')].filter(p => !p.hidden).map(p => p.id),
selected: document.querySelector('[role="tab"][aria-selected="true"]').textContent.trim(),
})`));
assert.deepStrictEqual(r.visible, ['panel-appearance']);
assert.strictEqual(r.selected, '外观');
});
await check('点击「通用」切到通用页并互斥', async () => {
const r = JSON.parse(await js(`(() => {
document.getElementById('tab-general').click();
return JSON.stringify({
visible: [...document.querySelectorAll('.tab-panel')].filter(p => !p.hidden).map(p => p.id),
cur: document.getElementById('tab-general').getAttribute('aria-selected'),
prev: document.getElementById('tab-appearance').getAttribute('aria-selected'),
});
})()`));
assert.deepStrictEqual(r.visible, ['panel-general']);
assert.strictEqual(r.cur, 'true');
assert.strictEqual(r.prev, 'false');
});
await check('→ 键切到下一个标签,← 键回上一个', async () => {
const r = JSON.parse(await js(`(() => {
const bar = document.getElementById('tab-bar');
const cur = () => document.querySelector('[role="tab"][aria-selected="true"]').textContent.trim();
const key = (k) => bar.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true }));
document.getElementById('tab-appearance').click();
key('ArrowRight'); const right = cur();
key('ArrowLeft'); const back = cur();
return JSON.stringify({ right, back });
})()`));
assert.strictEqual(r.right, '通用');
assert.strictEqual(r.back, '外观');
});
await check('每一页在 690px 窗口内都放得下(不需要滚动)', async () => {
const rows = JSON.parse(await js(`JSON.stringify(
[...document.querySelectorAll('#tab-bar [role="tab"]')].map(t => {
t.click();
const p = document.getElementById(t.getAttribute('aria-controls'));
return { id: p.id, clientH: p.clientHeight, scrollH: p.scrollHeight };
})
)`));
for (const r of rows) {
assert.ok(r.scrollH <= r.clientH + 1,
`${r.id} 内容溢出:${r.scrollH}px > 可视 ${r.clientH}px`);
}
});
console.log(`\n${passed} checks passed`);
app.exit(process.exitCode ? 1 : 0);
});