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 }; } // FR-V4:最近库下拉快速切换 test('FR-V4:最近库下拉快速切换', async () => { const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-v4-')); const ud = nodePath.join(tmp, 'ud'); const v1 = nodePath.join(tmp, 'vault1'); const v2 = nodePath.join(tmp, 'vault2'); await fs.mkdir(ud, { recursive: true }); await fs.mkdir(v1, { recursive: true }); await fs.mkdir(v2, { recursive: true }); const a = await launch(ud); // 切换到 v1(自动加入 recents)— 通过 UI 工具栏 await a.invoke('vault:switch', { root: v1 }); await a.page.waitForTimeout(500); // 切换到 v2 await a.invoke('vault:switch', { root: v2 }); await a.page.waitForTimeout(500); // 刷新渲染层 vault 元数据 await a.page.evaluate(() => (window as any).__STORE__?.getState?.().loadVault?.()); await a.page.waitForTimeout(500); // 现在 recents 应有 v1 和 v2 const meta = await a.invoke('vault:list', null as any); expect(meta.recents.length).toBeGreaterThanOrEqual(2); // 点击「最近库」下拉 await a.page.getByTestId('recents-toggle').click(); await a.page.waitForTimeout(300); // 应显示两个库 const dropdown = a.page.locator('div').filter({ has: a.page.getByText(v1.split(/[\\/]/).pop()!) }); await expect(dropdown.first()).toBeVisible({ timeout: 3000 }); await a.app.close(); });