Files
iven f32216e1e0
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
docs: 添加发散探讨文档和测试截图
添加了关于管家主动性与行业配置体系的发散探讨文档,包含现状诊断、关键讨论、架构设计等内容。同时添加了测试失败的截图和日志文件。
2026-04-12 22:40:45 +08:00

8.2 KiB
Raw Permalink Blame History

Instructions

  • Following Playwright test failed.
  • Explain why, be concise, respect Playwright best practices.
  • Provide a snippet of code with the fix, if possible.

Test info

  • Name: smoke_admin.spec.ts >> A6: 模型服务页面加载→Provider和Model tab可见
  • Location: tests\e2e\smoke_admin.spec.ts:179:1

Error details

TimeoutError: page.waitForSelector: Timeout 15000ms exceeded.
Call log:
  - waiting for locator('#main-content') to be visible

Page snapshot

- generic [ref=e1]:
  - link "跳转到主要内容" [ref=e2] [cursor=pointer]:
    - /url: "#main-content"
  - generic [ref=e5]:
    - generic [ref=e9]:
      - generic [ref=e11]: Z
      - heading "ZCLAW" [level=1] [ref=e12]
      - paragraph [ref=e13]: AI Agent 管理平台
      - paragraph [ref=e15]: 统一管理 AI 服务商、模型配置、API 密钥、用量监控与系统配置
    - generic [ref=e17]:
      - heading "登录" [level=2] [ref=e18]
      - paragraph [ref=e19]: 输入您的账号信息以继续
      - generic [ref=e22]:
        - generic [ref=e28]:
          - img "user" [ref=e30]:
            - img [ref=e31]
          - textbox "请输入用户名" [active] [ref=e33]
        - generic [ref=e40]:
          - img "lock" [ref=e42]:
            - img [ref=e43]
          - textbox "请输入密码" [ref=e45]
          - img "eye-invisible" [ref=e47] [cursor=pointer]:
            - img [ref=e48]
        - button "登 录" [ref=e51] [cursor=pointer]:
          - generic [ref=e52]: 登 录

Test source

  1   | /**
  2   |  * Smoke Tests — Admin V2 连通性断裂探测
  3   |  *
  4   |  * 6 个冒烟测试验证 Admin V2 页面与 SaaS 后端的完整连通性。
  5   |  * 所有测试使用真实浏览器 + 真实 SaaS Server。
  6   |  *
  7   |  * 前提条件:
  8   |  * - SaaS Server 运行在 http://localhost:8080
  9   |  * - Admin V2 dev server 运行在 http://localhost:5173
  10  |  * - 种子用户: testadmin / Admin123456 (super_admin)
  11  |  *
  12  |  * 运行: cd admin-v2 && npx playwright test smoke_admin
  13  |  */
  14  | 
  15  | import { test, expect, type Page } from '@playwright/test';
  16  | 
  17  | const SaaS_BASE = 'http://localhost:8080/api/v1';
  18  | const ADMIN_USER = 'admin';
  19  | const ADMIN_PASS = 'admin123';
  20  | 
  21  | // Helper: 通过 API 登录获取 HttpOnly cookie + 设置 localStorage
  22  | async function apiLogin(page: Page) {
  23  |   const res = await page.request.post(`${SaaS_BASE}/auth/login`, {
  24  |     data: { username: ADMIN_USER, password: ADMIN_PASS },
  25  |   });
  26  |   const json = await res.json();
  27  |   // 设置 localStorage 让 Admin V2 AuthGuard 认为已登录
  28  |   await page.goto('/');
  29  |   await page.evaluate((account) => {
  30  |     localStorage.setItem('zclaw_admin_account', JSON.stringify(account));
  31  |   }, json.account);
  32  |   return json;
  33  | }
  34  | 
  35  | // Helper: 通过 API 登录 + 导航到指定路径
  36  | async function loginAndGo(page: Page, path: string) {
  37  |   await apiLogin(page);
  38  |   // 重新导航到目标路径 (localStorage 已设置React 应识别为已登录)
  39  |   await page.goto(path, { waitUntil: 'networkidle' });
  40  |   // 等待主内容区加载
> 41  |   await page.waitForSelector('#main-content', { timeout: 15000 });
      |              ^ TimeoutError: page.waitForSelector: Timeout 15000ms exceeded.
  42  | }
  43  | 
  44  | // ── A1: 登录→Dashboard ────────────────────────────────────────────
  45  | 
  46  | test('A1: 登录→Dashboard 5个统计卡片', async ({ page }) => {
  47  |   // 导航到登录页
  48  |   await page.goto('/login');
  49  |   await expect(page.getByPlaceholder('请输入用户名')).toBeVisible({ timeout: 10000 });
  50  | 
  51  |   // 填写表单
  52  |   await page.getByPlaceholder('请输入用户名').fill(ADMIN_USER);
  53  |   await page.getByPlaceholder('请输入密码').fill(ADMIN_PASS);
  54  | 
  55  |   // 提交 (Ant Design 按钮文本有全角空格 "登 录")
  56  |   const loginBtn = page.locator('button').filter({ hasText: /登/ }).first();
  57  |   await loginBtn.click();
  58  | 
  59  |   // 验证跳转到 Dashboard (可能需要等待 API 响应)
  60  |   await expect(page).toHaveURL(/\/(login)?$/, { timeout: 20000 });
  61  | 
  62  |   // 验证 5 个统计卡片
  63  |   await expect(page.getByText('总账号')).toBeVisible({ timeout: 10000 });
  64  |   await expect(page.getByText('活跃服务商')).toBeVisible();
  65  |   await expect(page.getByText('活跃模型')).toBeVisible();
  66  |   await expect(page.getByText('今日请求')).toBeVisible();
  67  |   await expect(page.getByText('今日 Token')).toBeVisible();
  68  | 
  69  |   // 验证统计卡片有数值 (不是 loading 状态)
  70  |   const statCards = page.locator('.ant-statistic-content-value');
  71  |   await expect(statCards.first()).not.toBeEmpty({ timeout: 10000 });
  72  | });
  73  | 
  74  | // ── A2: Provider CRUD ──────────────────────────────────────────────
  75  | 
  76  | test('A2: Provider 创建→列表可见→禁用', async ({ page }) => {
  77  |   // 通过 API 创建 Provider
  78  |   await apiLogin(page);
  79  |   const createRes = await page.request.post(`${SaaS_BASE}/providers`, {
  80  |     data: {
  81  |       name: `smoke_provider_${Date.now()}`,
  82  |       provider_type: 'openai',
  83  |       base_url: 'https://api.smoke.test/v1',
  84  |       enabled: true,
  85  |       display_name: 'Smoke Test Provider',
  86  |     },
  87  |   });
  88  |   if (!createRes.ok()) {
  89  |     const body = await createRes.text();
  90  |     console.log(`A2: Provider create failed: ${createRes.status()}${body.slice(0, 300)}`);
  91  |   }
  92  |   expect(createRes.ok()).toBeTruthy();
  93  | 
  94  |   // 导航到 Model Services 页面
  95  |   await page.goto('/model-services');
  96  |   await page.waitForSelector('#main-content', { timeout: 15000 });
  97  | 
  98  |   // 切换到 Provider tab (如果存在 tab 切换)
  99  |   const providerTab = page.getByRole('tab', { name: /服务商|Provider/i });
  100 |   if (await providerTab.isVisible()) {
  101 |     await providerTab.click();
  102 |   }
  103 | 
  104 |   // 验证 Provider 列表非空
  105 |   const tableRows = page.locator('.ant-table-row');
  106 |   await expect(tableRows.first()).toBeVisible({ timeout: 10000 });
  107 |   expect(await tableRows.count()).toBeGreaterThan(0);
  108 | });
  109 | 
  110 | // ── A3: Account 管理 ───────────────────────────────────────────────
  111 | 
  112 | test('A3: Account 列表加载→角色可见', async ({ page }) => {
  113 |   await loginAndGo(page, '/accounts');
  114 | 
  115 |   // 验证表格加载
  116 |   const tableRows = page.locator('.ant-table-row');
  117 |   await expect(tableRows.first()).toBeVisible({ timeout: 10000 });
  118 | 
  119 |   // 至少有 testadmin 自己
  120 |   expect(await tableRows.count()).toBeGreaterThanOrEqual(1);
  121 | 
  122 |   // 验证有角色列
  123 |   const roleText = await page.locator('.ant-table').textContent();
  124 |   expect(roleText).toMatch(/super_admin|admin|user/);
  125 | });
  126 | 
  127 | // ── A4: 知识管理 ───────────────────────────────────────────────────
  128 | 
  129 | test('A4: 知识分类→条目→搜索', async ({ page }) => {
  130 |   // 通过 API 创建分类和条目
  131 |   await apiLogin(page);
  132 | 
  133 |   const catRes = await page.request.post(`${SaaS_BASE}/knowledge/categories`, {
  134 |     data: { name: `smoke_cat_${Date.now()}`, description: 'Smoke test category' },
  135 |   });
  136 |   expect(catRes.ok()).toBeTruthy();
  137 |   const catJson = await catRes.json();
  138 | 
  139 |   const itemRes = await page.request.post(`${SaaS_BASE}/knowledge/items`, {
  140 |     data: {
  141 |       title: 'Smoke Test Knowledge Item',