import { test, expect, describe, Page } from "@playwright/test"; import { LoginPage } from "../pages/login.page"; const TEST_USER = { email: "admin@example.com", password: "admin@123", }; // 引导流程页面对象 class OnboardingPage { page: Page; // Step 1: 品牌名称输入 brandNameInput: ReturnType; startAnalysisButton: ReturnType; skipToDashboardButton: ReturnType; // Step 2: 竞品确认 competitorCheckboxes: ReturnType; addCompetitorInput: ReturnType; addCompetitorButton: ReturnType; nextButton: ReturnType; backButton: ReturnType; skipStepButton: ReturnType; // Step 3: 平台选择 platformCheckboxes: ReturnType; selectAllButton: ReturnType; queryFrequencyOptions: ReturnType; // Step 4: 健康报告 healthScore: ReturnType; healthLevelBadge: ReturnType; viewActionsButton: ReturnType; // Step 5: 行动建议 completeButton: ReturnType; // 进度指示器 progressSteps: ReturnType; constructor(page: Page) { this.page = page; // Step 1 this.brandNameInput = this.page.locator("#brandName"); this.startAnalysisButton = this.page.getByRole("button", { name: /开始分析/, }); this.skipToDashboardButton = this.page.getByRole("button", { name: /跳过.*Dashboard/, }); // Step 2 this.competitorCheckboxes = this.page .locator(".border.rounded-lg") .filter({ has: this.page.locator(".flex.h-5.w-5") }); this.addCompetitorInput = this.page.locator( 'input[placeholder="输入竞品名称"]', ); this.addCompetitorButton = this.page .locator('button:has-text("添加")') .first(); this.nextButton = this.page.getByRole("button", { name: /继续/ }); this.backButton = this.page.getByRole("button", { name: /上一步/ }); this.skipStepButton = this.page.getByRole("button", { name: /跳过此步骤/ }); // Step 3 this.platformCheckboxes = this.page.locator(".grid.gap-3 button"); this.selectAllButton = this.page.getByRole("button", { name: "全选" }); this.queryFrequencyOptions = this.page.locator(".grid.gap-3 button"); // Step 4 this.healthScore = this.page.locator("text-7xl.font-bold"); this.healthLevelBadge = this.page.locator("text-base.px-4.py-1"); this.viewActionsButton = this.page.getByRole("button", { name: /查看行动建议/, }); // Step 5 this.completeButton = this.page.getByRole("button", { name: /完成设置/ }); // 进度指示器 - 使用更精确的选择器 this.progressSteps = this.page.locator( ".flex.items-center.justify-between .flex.flex-1.items-center", ); } async goto() { await this.page.goto("/onboarding"); } async loginAndGoToOnboarding() { const loginPage = new LoginPage(this.page); await loginPage.goto(); await loginPage.login(TEST_USER.email, TEST_USER.password); // 等待登录完成并跳转到Dashboard // 使用更长的超时时间和更多的等待条件 try { await this.page.waitForURL(/\/dashboard/, { timeout: 20000 }); } catch (e) { // 如果超时,检查当前URL console.log("Current URL after login timeout:", this.page.url()); throw e; } await this.page.goto("/onboarding"); } async fillBrandName(name: string) { await this.brandNameInput.fill(name); } async clickStartAnalysis() { await this.startAnalysisButton.click(); } async selectCompetitor(name: string) { const competitorCard = this.page .locator(".border.rounded-lg") .filter({ hasText: name }); await competitorCard.click(); } async selectPlatform(platformName: string) { const platformCard = this.page .locator(".grid.gap-3 button") .filter({ hasText: platformName }); await platformCard.click(); } async selectQueryFrequency(frequency: string) { await this.queryFrequencyOptions.filter({ hasText: frequency }).click(); } } describe("新用户引导向导 - 完整流程测试", () => { test.beforeEach(async ({ page }) => { // 先登录 const onboardingPage = new OnboardingPage(page); await onboardingPage.loginAndGoToOnboarding(); }); test("Step 1: 应该显示品牌名称输入页面", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // 验证标题 await expect( page.getByRole("heading", { name: /输入您的品牌名称/ }), ).toBeVisible(); // 验证输入框存在 await expect(onboardingPage.brandNameInput).toBeVisible(); // 验证按钮存在 await expect(onboardingPage.startAnalysisButton).toBeVisible(); await expect(onboardingPage.skipToDashboardButton).toBeVisible(); // 验证进度指示器 await expect(onboardingPage.progressSteps).toHaveCount(5); }); test("Step 1: 品牌名称验证 - 太短应显示错误", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // 输入太短的名称 await onboardingPage.fillBrandName("a"); await onboardingPage.startAnalysisButton.click(); // 应该显示错误提示 await expect(page.getByText(/至少需要2个字符/)).toBeVisible(); }); test("Step 1: 正确输入品牌名称应进入下一步", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // 输入有效的品牌名称 await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); // 应该进入Step 2 await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); }); test("Step 2: 可以选择竞品并继续", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // Step 1 await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); // Step 2 - 等待加载 await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); // 等待推荐竞品加载 await page.waitForTimeout(2000); // 选择一个竞品(如果存在的话) const firstCompetitor = page .locator(".border.rounded-lg") .filter({ has: page.locator(".flex.h-5.w-5") }) .first(); if (await firstCompetitor.isVisible()) { await firstCompetitor.click(); } // 点击继续 await onboardingPage.nextButton.click(); // 应该进入Step 3 await expect( page.getByRole("heading", { name: /选择监控平台/ }), ).toBeVisible({ timeout: 5000 }); }); test("Step 2: 跳过应进入下一步", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // Step 1 await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); // Step 2 - 点击跳过 await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); await onboardingPage.skipStepButton.click(); // 应该进入Step 3 await expect( page.getByRole("heading", { name: /选择监控平台/ }), ).toBeVisible({ timeout: 5000 }); }); test("Step 3: 平台默认全选", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // Step 1 -> Step 2 -> Step 3 await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); await onboardingPage.skipStepButton.click(); await expect( page.getByRole("heading", { name: /选择监控平台/ }), ).toBeVisible({ timeout: 5000 }); // 验证平台数量提示 await expect(page.getByText(/\d+\/\d+ 个平台/)).toBeVisible(); }); test("Step 3: 可以选择不同频率", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // 到达Step 3 await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); await onboardingPage.skipStepButton.click(); await expect( page.getByRole("heading", { name: /选择监控平台/ }), ).toBeVisible({ timeout: 5000 }); // 选择每日频率 await onboardingPage.selectQueryFrequency("每日"); // 验证选中状态 await expect(page.locator(".border-primary.bg-primary\\/5")).toBeVisible(); }); test("Step 3: 返回上一步", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // 到达Step 3 await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); await onboardingPage.skipStepButton.click(); await expect( page.getByRole("heading", { name: /选择监控平台/ }), ).toBeVisible({ timeout: 5000 }); // 返回 await onboardingPage.backButton.click(); // 应该回到Step 2 await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); }); test("Step 4: 跳过直接进入Dashboard", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // Step 1 -> 跳过 await expect( page.getByRole("heading", { name: /输入您的品牌名称/ }), ).toBeVisible(); await onboardingPage.skipToDashboardButton.click(); // 应该跳转到Dashboard await expect(page).toHaveURL(/\/dashboard/, { timeout: 10000 }); }); }); describe("新用户引导向导 - 响应式设计测试", () => { test("移动端视图应该正常显示", async ({ page }) => { await page.setViewportSize({ width: 375, height: 667 }); const onboardingPage = new OnboardingPage(page); await onboardingPage.loginAndGoToOnboarding(); // 验证主要内容可见 await expect( page.getByRole("heading", { name: /输入您的品牌名称/ }), ).toBeVisible(); // 验证按钮可点击 await expect(onboardingPage.startAnalysisButton).toBeVisible(); }); test("平板视图应该正常显示", async ({ page }) => { await page.setViewportSize({ width: 768, height: 1024 }); const onboardingPage = new OnboardingPage(page); await onboardingPage.loginAndGoToOnboarding(); // 验证主要内容可见 await expect( page.getByRole("heading", { name: /输入您的品牌名称/ }), ).toBeVisible(); }); }); describe("新用户引导向导 - 进度指示器测试", () => { test.beforeEach(async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.loginAndGoToOnboarding(); }); test("初始应显示Step 1为当前步骤", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); // Step 1 应该显示为当前步骤 const firstStepIndicator = page .locator(".flex.flex-col.items-center") .first(); await expect( firstStepIndicator.locator(".border-primary.bg-primary\\/10"), ).toBeVisible(); }); test("完成Step 1后Step 2应为当前步骤", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.goto(); await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); // 等待Step 2加载 await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); // Step 2 应该显示为当前步骤(第二个圆圈) const secondStepIndicator = page .locator(".flex.flex-col.items-center") .nth(1); await expect(secondStepIndicator.locator(".border-primary")).toBeVisible(); }); }); describe("新用户引导向导 - 健康等级颜色测试", () => { test("健康等级应使用正确的颜色", async ({ page }) => { const onboardingPage = new OnboardingPage(page); await onboardingPage.loginAndGoToOnboarding(); // 到达Step 3 await onboardingPage.fillBrandName("华为"); await onboardingPage.startAnalysisButton.click(); await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({ timeout: 5000, }); await onboardingPage.skipStepButton.click(); await expect( page.getByRole("heading", { name: /选择监控平台/ }), ).toBeVisible({ timeout: 5000 }); // 选择一个平台(next按钮需要至少选择一个平台才能点击) await onboardingPage.selectPlatform("文心一言"); // 等待按钮可用 await expect(onboardingPage.nextButton).toBeEnabled({ timeout: 5000 }); await onboardingPage.nextButton.click(); // 等待健康报告加载 await page.waitForTimeout(2000); // 验证健康等级标签存在(优秀/良好/及格/危险之一) const healthLabels = ["优秀", "良好", "及格", "危险"]; for (const label of healthLabels) { const labelElement = page.getByText(label); if (await labelElement.isVisible()) { break; } } }); });