# 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: onboarding.spec.ts >> 新用户引导向导 - 完整流程测试 >> Step 1: 应该显示品牌名称输入页面
- Location: e2e/tests/onboarding.spec.ts:144:7

# Error details

```
Error: expect(locator).toHaveCount(expected) failed

Locator:  locator('.flex.items-center.justify-between > div')
Expected: 5
Received: 6
Timeout:  5000ms

Call log:
  - Expect "toHaveCount" with timeout 5000ms
  - waiting for locator('.flex.items-center.justify-between > div')
    9 × locator resolved to 6 elements
      - unexpected value "6"

```

# Page snapshot

```yaml
- generic [ref=e1]:
  - generic [ref=e2]:
    - complementary [ref=e3]:
      - generic [ref=e5]: GEO Platform
      - navigation [ref=e6]:
        - link "数据总览" [ref=e7] [cursor=pointer]:
          - /url: /dashboard
          - img [ref=e8]
          - text: 数据总览
        - link "品牌管理" [ref=e13] [cursor=pointer]:
          - /url: /brands
          - img [ref=e14]
          - text: 品牌管理
        - link "竞品对比" [ref=e16] [cursor=pointer]:
          - /url: /compare
          - img [ref=e17]
          - text: 竞品对比
        - link "查询管理" [ref=e22] [cursor=pointer]:
          - /url: /dashboard/queries
          - img [ref=e23]
          - text: 查询管理
        - link "引用记录" [ref=e26] [cursor=pointer]:
          - /url: /dashboard/citations
          - img [ref=e27]
          - text: 引用记录
        - link "报告导出" [ref=e30] [cursor=pointer]:
          - /url: /dashboard/reports
          - img [ref=e31]
          - text: 报告导出
        - link "设置" [ref=e35] [cursor=pointer]:
          - /url: /dashboard/settings
          - img [ref=e36]
          - text: 设置
        - link "管理后台" [ref=e39] [cursor=pointer]:
          - /url: /dashboard/admin
          - img [ref=e40]
          - text: 管理后台
    - generic [ref=e42]:
      - banner [ref=e43]:
        - heading "GEO Platform" [level=1] [ref=e44]
        - generic [ref=e45]:
          - generic [ref=e46]:
            - img [ref=e47]
            - generic [ref=e50]: 管理员
          - button "退出登录" [ref=e51] [cursor=pointer]:
            - img [ref=e52]
            - text: 退出登录
      - main [ref=e55]:
        - generic [ref=e57]:
          - generic [ref=e58]:
            - heading "GEO 平台" [level=1] [ref=e59]
            - paragraph [ref=e60]: 新用户引导
          - generic [ref=e63]:
            - generic [ref=e65]:
              - generic [ref=e67]: "1"
              - generic [ref=e68]: 输入品牌名称
            - generic [ref=e71]:
              - generic [ref=e73]: "2"
              - generic [ref=e74]: 确认竞品
            - generic [ref=e77]:
              - generic [ref=e79]: "3"
              - generic [ref=e80]: 选择平台
            - generic [ref=e83]:
              - generic [ref=e85]: "4"
              - generic [ref=e86]: 健康报告
            - generic [ref=e89]:
              - generic [ref=e91]: "5"
              - generic [ref=e92]: 行动建议
          - generic [ref=e94]:
            - generic [ref=e95]:
              - img [ref=e97]
              - heading "输入您的品牌名称" [level=2] [ref=e100]
              - paragraph [ref=e101]: 输入您要在AI搜索中监控的品牌名称，我们将为您分析其曝光度
            - generic [ref=e104]:
              - generic [ref=e105]:
                - generic [ref=e106]: 品牌名称 *
                - textbox "品牌名称 *" [active] [ref=e107]:
                  - /placeholder: 例如：华为、小米、苹果
                - paragraph [ref=e108]: 品牌名称创建后可以修改，最多50个字符
              - generic [ref=e109]:
                - button "开始分析" [disabled]:
                  - text: 开始分析
                  - img
                - button "跳过，直接进入Dashboard" [ref=e110] [cursor=pointer]
            - generic [ref=e113]: 输入品牌名称后，系统将自动开始监控
  - alert [ref=e114]
```

# Test source

```ts
  61  |     this.addCompetitorButton = this.page
  62  |       .locator('button:has-text("添加")')
  63  |       .first();
  64  |     this.nextButton = this.page.getByRole("button", { name: /继续/ });
  65  |     this.backButton = this.page.getByRole("button", { name: /上一步/ });
  66  |     this.skipStepButton = this.page.getByRole("button", { name: /跳过此步骤/ });
  67  | 
  68  |     // Step 3
  69  |     this.platformCheckboxes = this.page.locator(".grid.gap-3 button");
  70  |     this.selectAllButton = this.page.getByRole("button", { name: "全选" });
  71  |     this.queryFrequencyOptions = this.page.locator(".grid.gap-3 button");
  72  | 
  73  |     // Step 4
  74  |     this.healthScore = this.page.locator("text-7xl.font-bold");
  75  |     this.healthLevelBadge = this.page.locator("text-base.px-4.py-1");
  76  |     this.viewActionsButton = this.page.getByRole("button", {
  77  |       name: /查看行动建议/,
  78  |     });
  79  | 
  80  |     // Step 5
  81  |     this.completeButton = this.page.getByRole("button", { name: /完成设置/ });
  82  | 
  83  |     // 进度指示器
  84  |     this.progressSteps = this.page.locator(
  85  |       ".flex.items-center.justify-between > div",
  86  |     );
  87  |   }
  88  | 
  89  |   async goto() {
  90  |     await this.page.goto("/onboarding");
  91  |   }
  92  | 
  93  |   async loginAndGoToOnboarding() {
  94  |     const loginPage = new LoginPage(this.page);
  95  |     await loginPage.goto();
  96  |     await loginPage.login(TEST_USER.email, TEST_USER.password);
  97  | 
  98  |     // 等待登录完成并跳转到Dashboard
  99  |     // 使用更长的超时时间和更多的等待条件
  100 |     try {
  101 |       await this.page.waitForURL(/\/dashboard/, { timeout: 20000 });
  102 |     } catch (e) {
  103 |       // 如果超时，检查当前URL
  104 |       console.log("Current URL after login timeout:", this.page.url());
  105 |       throw e;
  106 |     }
  107 |     await this.page.goto("/onboarding");
  108 |   }
  109 | 
  110 |   async fillBrandName(name: string) {
  111 |     await this.brandNameInput.fill(name);
  112 |   }
  113 | 
  114 |   async clickStartAnalysis() {
  115 |     await this.startAnalysisButton.click();
  116 |   }
  117 | 
  118 |   async selectCompetitor(name: string) {
  119 |     const competitorCard = this.page
  120 |       .locator(".border.rounded-lg")
  121 |       .filter({ hasText: name });
  122 |     await competitorCard.click();
  123 |   }
  124 | 
  125 |   async selectPlatform(platformName: string) {
  126 |     const platformCard = this.page
  127 |       .locator(".grid.gap-3 button")
  128 |       .filter({ hasText: platformName });
  129 |     await platformCard.click();
  130 |   }
  131 | 
  132 |   async selectQueryFrequency(frequency: string) {
  133 |     await this.queryFrequencyOptions.filter({ hasText: frequency }).click();
  134 |   }
  135 | }
  136 | 
  137 | describe("新用户引导向导 - 完整流程测试", () => {
  138 |   test.beforeEach(async ({ page }) => {
  139 |     // 先登录
  140 |     const onboardingPage = new OnboardingPage(page);
  141 |     await onboardingPage.loginAndGoToOnboarding();
  142 |   });
  143 | 
  144 |   test("Step 1: 应该显示品牌名称输入页面", async ({ page }) => {
  145 |     const onboardingPage = new OnboardingPage(page);
  146 |     await onboardingPage.goto();
  147 | 
  148 |     // 验证标题
  149 |     await expect(
  150 |       page.getByRole("heading", { name: /输入您的品牌名称/ }),
  151 |     ).toBeVisible();
  152 | 
  153 |     // 验证输入框存在
  154 |     await expect(onboardingPage.brandNameInput).toBeVisible();
  155 | 
  156 |     // 验证按钮存在
  157 |     await expect(onboardingPage.startAnalysisButton).toBeVisible();
  158 |     await expect(onboardingPage.skipToDashboardButton).toBeVisible();
  159 | 
  160 |     // 验证进度指示器
> 161 |     await expect(onboardingPage.progressSteps).toHaveCount(5);
      |                                                ^ Error: expect(locator).toHaveCount(expected) failed
  162 |   });
  163 | 
  164 |   test("Step 1: 品牌名称验证 - 太短应显示错误", async ({ page }) => {
  165 |     const onboardingPage = new OnboardingPage(page);
  166 |     await onboardingPage.goto();
  167 | 
  168 |     // 输入太短的名称
  169 |     await onboardingPage.fillBrandName("a");
  170 |     await onboardingPage.startAnalysisButton.click();
  171 | 
  172 |     // 应该显示错误提示
  173 |     await expect(page.getByText(/至少需要2个字符/)).toBeVisible();
  174 |   });
  175 | 
  176 |   test("Step 1: 正确输入品牌名称应进入下一步", async ({ page }) => {
  177 |     const onboardingPage = new OnboardingPage(page);
  178 |     await onboardingPage.goto();
  179 | 
  180 |     // 输入有效的品牌名称
  181 |     await onboardingPage.fillBrandName("华为");
  182 |     await onboardingPage.startAnalysisButton.click();
  183 | 
  184 |     // 应该进入Step 2
  185 |     await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
  186 |       timeout: 5000,
  187 |     });
  188 |   });
  189 | 
  190 |   test("Step 2: 可以选择竞品并继续", async ({ page }) => {
  191 |     const onboardingPage = new OnboardingPage(page);
  192 |     await onboardingPage.goto();
  193 | 
  194 |     // Step 1
  195 |     await onboardingPage.fillBrandName("华为");
  196 |     await onboardingPage.startAnalysisButton.click();
  197 | 
  198 |     // Step 2 - 等待加载
  199 |     await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
  200 |       timeout: 5000,
  201 |     });
  202 | 
  203 |     // 等待推荐竞品加载
  204 |     await page.waitForTimeout(2000);
  205 | 
  206 |     // 选择一个竞品（如果存在的话）
  207 |     const firstCompetitor = page
  208 |       .locator(".border.rounded-lg")
  209 |       .filter({ has: page.locator(".flex.h-5.w-5") })
  210 |       .first();
  211 |     if (await firstCompetitor.isVisible()) {
  212 |       await firstCompetitor.click();
  213 |     }
  214 | 
  215 |     // 点击继续
  216 |     await onboardingPage.nextButton.click();
  217 | 
  218 |     // 应该进入Step 3
  219 |     await expect(
  220 |       page.getByRole("heading", { name: /选择监控平台/ }),
  221 |     ).toBeVisible({ timeout: 5000 });
  222 |   });
  223 | 
  224 |   test("Step 2: 跳过应进入下一步", async ({ page }) => {
  225 |     const onboardingPage = new OnboardingPage(page);
  226 |     await onboardingPage.goto();
  227 | 
  228 |     // Step 1
  229 |     await onboardingPage.fillBrandName("华为");
  230 |     await onboardingPage.startAnalysisButton.click();
  231 | 
  232 |     // Step 2 - 点击跳过
  233 |     await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
  234 |       timeout: 5000,
  235 |     });
  236 |     await onboardingPage.skipStepButton.click();
  237 | 
  238 |     // 应该进入Step 3
  239 |     await expect(
  240 |       page.getByRole("heading", { name: /选择监控平台/ }),
  241 |     ).toBeVisible({ timeout: 5000 });
  242 |   });
  243 | 
  244 |   test("Step 3: 平台默认全选", async ({ page }) => {
  245 |     const onboardingPage = new OnboardingPage(page);
  246 |     await onboardingPage.goto();
  247 | 
  248 |     // Step 1 -> Step 2 -> Step 3
  249 |     await onboardingPage.fillBrandName("华为");
  250 |     await onboardingPage.startAnalysisButton.click();
  251 |     await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
  252 |       timeout: 5000,
  253 |     });
  254 |     await onboardingPage.skipStepButton.click();
  255 |     await expect(
  256 |       page.getByRole("heading", { name: /选择监控平台/ }),
  257 |     ).toBeVisible({ timeout: 5000 });
  258 | 
  259 |     // 验证平台数量提示
  260 |     await expect(page.getByText(/\d+\/\d+ 个平台/)).toBeVisible();
  261 |   });
```