Files
MyNote/apps/desktop/tests/e2e/appearance-enhanced.spec.ts

107 lines
4.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect } from '@playwright/test';
import { _electron as electron } from 'playwright';
import { promises as fs } from 'node:fs';
import nodePath from 'node:path';
import os from 'node:os';
const MAIN_JS = nodePath.join(process.cwd(), 'dist-electron/main/index.js');
async function launch(userData: string) {
const app = await electron.launch({ args: ['--user-data-dir=' + userData, MAIN_JS] });
const page = await app.firstWindow();
await page.waitForLoadState('domcontentloaded');
const invoke = (ch: string, args: any) => page.evaluate(({ ch, args }) => (globalThis as any).dsh.invoke(ch, args), { ch, args });
return { app, page, invoke };
}
async function openAppearance(a: { page: any }) {
await a.page.getByTitle('外观定制').click();
await expect(a.page.getByText('外观定制')).toBeVisible({ timeout: 5000 });
}
// FR-A7:Esc 关闭外观面板并回滚
test('FR-A7:Esc 关闭外观面板', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-a7-'));
const userData = nodePath.join(tmp, 'userdata');
const vault = nodePath.join(tmp, 'vault');
await fs.mkdir(userData, { recursive: true });
await fs.mkdir(vault, { recursive: true });
const a = await launch(userData);
await a.invoke('vault:switch', { root: vault });
await openAppearance(a);
await a.page.keyboard.press('Escape');
await expect(a.page.getByText('外观定制')).not.toBeVisible({ timeout: 5000 });
await a.app.close();
});
// FR-A6:恢复主题默认按钮 + save 剥离等于默认的项
test('FR-A6:恢复主题默认 + 保存剥离默认值', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-a6-'));
const userData = nodePath.join(tmp, 'userdata');
const vault = nodePath.join(tmp, 'vault');
await fs.mkdir(userData, { recursive: true });
await fs.mkdir(vault, { recursive: true });
const a = await launch(userData);
await a.invoke('vault:switch', { root: vault });
await openAppearance(a);
// 改一个颜色参数 -> dirty
const accentInput = a.page.locator('input[type="color"]').first();
await accentInput.fill('#ff0000');
await expect(a.page.getByText('更改尚未保存')).toBeVisible({ timeout: 5000 });
// 恢复主题默认 -> 应恢复
await a.page.getByRole('button', { name: '恢复主题默认' }).click();
await expect(a.page.getByText('所有设置已保存')).toBeVisible({ timeout: 3000 });
// 保存后 config.json 的 params 应为空(全等于默认)
await a.page.getByRole('button', { name: '保存外观' }).click();
await expect(a.page.getByText('外观定制')).not.toBeVisible({ timeout: 5000 });
const cfgPath = nodePath.join(userData, 'config.json');
const cfg = JSON.parse(await fs.readFile(cfgPath, 'utf-8'));
// params 应为空对象或只含非默认项
const paramKeys = Object.keys(cfg.appearance?.params ?? {});
expect(paramKeys.length).toBe(0);
await a.app.close();
});
// FR-A10:背景图压缩为 WebP(检查 data URL 前缀)
test('FR-A10:背景图压缩为 WebP', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-a10-'));
const userData = nodePath.join(tmp, 'userdata');
const vault = nodePath.join(tmp, 'vault');
await fs.mkdir(userData, { recursive: true });
await fs.mkdir(vault, { recursive: true });
const a = await launch(userData);
await a.invoke('vault:switch', { root: vault });
// 创建一个小测试 PNG
const pngData = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';
const pngBuf = Buffer.from(pngData, 'base64');
const imgPath = nodePath.join(tmp, 'test.png');
await fs.writeFile(imgPath, pngBuf);
await openAppearance(a);
// 上传图片
const fileInput = a.page.locator('input[type="file"]');
await fileInput.setInputFiles(imgPath);
await a.page.waitForTimeout(1000);
// 检查 bgImage 在 store 中是 WebP data URL
const bgImage = await a.page.evaluate(() => {
// 从背景图 img 元素获取 src
const img = document.querySelector('img[alt="bg"]') as HTMLImageElement;
return img?.src ?? '';
});
// 应为 data:image/webp 开头
expect(bgImage.startsWith('data:image/webp')).toBeTruthy();
await a.app.close();
});