import { test, expect } from 'playwright/test' // 冒烟用例:纯浏览器(无 Tauri 壳)打开 vite dev server, // 验证 Tauri IPC 垫片(src/mocks/tauri-shim.ts)能让应用完整挂载并路由不白屏。 // 全程只读内存假数据,不接触任何真实数据库。 // 主路由取样:AI 首页(默认路由)、任务、项目、知识库,覆盖四条典型挂载链 const ROUTES = ['/ai-home', '/tasks', '/projects', '/knowledge'] for (const route of ROUTES) { test(`路由 ${route} 挂载且无未捕获异常`, async ({ page }) => { const pageErrors: string[] = [] page.on('pageerror', (err) => { pageErrors.push(`${err.name}: ${err.message}`) }) await page.goto(`/#${route}`) // app 完成挂载:main.ts 等路由就绪后才 mount,#app 有元素子节点即视为挂载成功 await expect(page.locator('#app > *').first()).toBeVisible({ timeout: 20_000 }) // 白屏判定:挂载壳内应有实质内容(空壳 fallback 文案也会超过 0,取较高阈值) const html = await page.innerHTML('#app') expect(html.length).toBeGreaterThan(200) // ResizeObserver 循环超限是浏览器布局抖动的良性告警,与业务逻辑无关,过滤 const realErrors = pageErrors.filter(msg => !/ResizeObserver loop/i.test(msg)) expect(realErrors, `路由 ${route} 出现未捕获异常: ${realErrors.join(' | ')}`).toEqual([]) }) } test('垫片注入生效且假数据链路可用', async ({ page }) => { await page.goto('/#/ai-home') await expect(page.locator('#app > *').first()).toBeVisible({ timeout: 20_000 }) // 浏览器里垫片必须已注入(否则所有 invoke 同步 TypeError) const injected = await page.evaluate(() => Boolean((window as unknown as Record).__TAURI_INTERNALS__)) expect(injected).toBe(true) // 假数据链路:经 window 上的垫片 invoke 会话列表命令,验证分发到内存 fixture。 // 不 import @tauri-apps/api,page.evaluate 内联脚本解析不了裸模块名 const convCount = await page.evaluate(async () => { const internals = (window as unknown as { __TAURI_INTERNALS__: { invoke: (cmd: string) => Promise } }).__TAURI_INTERNALS__ const list = (await internals.invoke('ai_conversation_list')) as unknown[] return list.length }) expect(convCount).toBeGreaterThan(0) })