Files
MyNote/apps/desktop/tests/e2e/save-mechanism.spec.ts
T

109 lines
4.4 KiB
TypeScript
Raw 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 newDoc(a: { page: any; invoke: any }, title: string) {
await a.page.getByRole('button', { name: /新建文档/ }).click();
await a.page.getByPlaceholder(/输入文档标题/).fill(title);
await a.page.getByPlaceholder(/输入文档标题/).press('Enter');
await expect(a.page.getByTestId('tabbar').getByText(title, { exact: true })).toBeVisible({ timeout: 10000 });
}
// FR-S1:自动保存——停止输入后内容写入文件
test('FR-S1:自动保存防抖写入', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-s1-'));
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 newDoc(a, '自动保存测试');
// 输入内容
await a.page.locator('.ProseMirror').click();
await a.page.keyboard.type('autosave content');
// 等待自动保存(默认 1 秒间隔 + 防抖)
await expect.poll(async () => {
try { const f = await fs.readFile(nodePath.join(vault, '自动保存测试.md'), 'utf8'); return f.includes('autosave content'); }
catch { return false; }
}, { timeout: 10000 }).toBe(true);
await a.app.close();
});
// FR-S4:关闭窗口前冲刷未保存内容
test('FR-S4:关窗冲刷未保存内容', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-s4-'));
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 newDoc(a, '关窗测试');
await a.page.locator('.ProseMirror').click();
await a.page.keyboard.type('before-close-flush');
// 等一下让内容进入 store
await a.page.waitForTimeout(200);
// 手动触发 saveNow(模拟 beforeunload 冲刷)
await a.page.evaluate(() => (window as any).__STORE__?.getState?.().saveNow?.());
await a.page.waitForTimeout(500);
await a.app.close();
// 文件应包含内容(关窗前冲刷)
const fileContent = await fs.readFile(nodePath.join(vault, '关窗测试.md'), 'utf8');
expect(fileContent).toContain('before-close-flush');
});
// FR-S6:reloadDoc 检测 mtime 变化
test('FR-S6:reloadDoc 检测外部改动', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-s6-'));
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 newDoc(a, '重载测试');
await a.page.locator('.ProseMirror').click();
await a.page.keyboard.type('original');
await a.page.waitForTimeout(2000); // 等待自动保存
// 外部修改文件
const filePath = nodePath.join(vault, '重载测试.md');
await fs.writeFile(filePath, '---\ntitle: 重载测试\n---\nexternal-change');
// reloadDoc 应检测到 mtime 变化并重载(无未保存改动时)
const result = await a.page.evaluate(async () => {
const store = (window as any).__STORE__;
if (!store) return { error: 'no store' };
return await store.getState().reloadDoc();
});
console.log('RELOAD_RESULT', JSON.stringify(result));
expect(result).toBe(true);
// 验证 store 的 body 已更新为外部修改的内容
const storeBody = await a.page.evaluate(() => (window as any).__STORE__?.getState?.().body ?? '');
expect(storeBody).toContain('external-change');
await a.app.close();
});