fix: S1 安全冲刺——切库清空标签页+冲刷(FR-V6)、重命名/移动同步标签页路径(FR-T7)、默认库路径设置页(FR-V5);vaultBrowse IPC+pickDirectory;tab-store closeAll/renamePath;store resetEditor/syncCurrentPath;safety E2E 2 项

This commit is contained in:
hunter-dev
2026-08-26 11:05:22 +08:00
parent 81b410e281
commit c4af03adce
10 changed files with 190 additions and 8 deletions
+89
View File
@@ -0,0 +1,89 @@
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 };
}
test('FR-T7:重命名文档后标签页路径同步', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-t7-'));
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 a.page.getByRole('button', { name: /新建文档/ }).click();
await a.page.getByPlaceholder(/输入文档标题/).fill('原稿');
await a.page.getByPlaceholder(/输入文档标题/).press('Enter');
await expect(a.page.getByTestId('tabbar').getByText('原稿', { exact: true })).toBeVisible({ timeout: 10000 });
// 文件树悬停「原稿」→ 点重命名 → 输入「改稿」→ 回车
await a.page.getByTestId('filetree').getByText('原稿', { exact: true }).hover();
await a.page.getByTestId('filetree').getByTitle('重命名').click();
// 重命名 input 是 filetree 内唯一的 input(搜索框在 filetree 外)
const renameInput = a.page.getByTestId('filetree').locator('input');
await renameInput.fill('改稿');
await renameInput.press('Enter');
// 标签页文本应从「原稿」变为「改稿」(路径已同步)
await expect(a.page.getByTestId('tabbar').getByText('改稿', { exact: true })).toBeVisible({ timeout: 10000 });
// 「原稿」标签页文本应消失
await expect(a.page.getByTestId('tabbar').getByText('原稿', { exact: true })).toHaveCount(0);
await a.app.close();
});
test('FR-V5+V6:设置页切换默认库路径 + 切库清空标签页', async () => {
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-v56-'));
const userData = nodePath.join(tmp, 'userdata');
const vault1 = nodePath.join(tmp, 'vault1');
const vault2 = nodePath.join(tmp, 'vault2');
await fs.mkdir(userData, { recursive: true });
await fs.mkdir(vault1, { recursive: true });
await fs.mkdir(vault2, { recursive: true });
const a = await launch(userData);
await a.invoke('vault:switch', { root: vault1 });
// 在 vault1 新建并打开文档 → 标签页出现
await a.page.getByRole('button', { name: /新建文档/ }).click();
await a.page.getByPlaceholder(/输入文档标题/).fill('库1文档');
await a.page.getByPlaceholder(/输入文档标题/).press('Enter');
await expect(a.page.getByTestId('tabbar').getByText('库1文档', { exact: true })).toBeVisible({ timeout: 10000 });
// 设置 → 文件路径页 → 填入 vault2 路径 → 立即切换
await a.page.getByTitle('设置').click();
await a.page.getByRole('button', { name: '文件路径' }).click();
await a.page.getByPlaceholder(/填写或浏览/).fill(vault2);
await a.page.getByRole('button', { name: '立即切换' }).click();
// 等待切换完成
await expect(a.page.getByText(/已切换/)).toBeVisible({ timeout: 10000 });
// FR-V6:标签页应被清空(TabBar 返回 null → DOM 中无 tabbar)
await expect(a.page.getByTestId('tabbar')).toHaveCount(0);
// FR-V5:库元数据应更新为 vault2
const meta: { currentRoot: string } = await a.invoke('vault:list', null);
expect(meta.currentRoot).toBe(vault2);
// 关闭设置面板(点击遮罩层),在 vault2 新建文档应正常工作
await a.page.mouse.click(5, 5);
await a.page.getByRole('button', { name: /新建文档/ }).click();
await a.page.getByPlaceholder(/输入文档标题/).fill('库2文档');
await a.page.getByPlaceholder(/输入文档标题/).press('Enter');
await expect(a.page.getByTestId('tabbar').getByText('库2文档', { exact: true })).toBeVisible({ timeout: 10000 });
await a.app.close();
});