geo/frontend/e2e/tests/onboarding.spec.ts

377 lines
12 KiB
TypeScript

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;
brandNameInput: ReturnType<Page["locator"]>;
startAnalysisButton: ReturnType<Page["getByRole"]>;
skipToDashboardButton: ReturnType<Page["getByRole"]>;
competitorCheckboxes: ReturnType<Page["locator"]>;
addCompetitorInput: ReturnType<Page["locator"]>;
addCompetitorButton: ReturnType<Page["locator"]>;
nextButton: ReturnType<Page["getByRole"]>;
backButton: ReturnType<Page["getByRole"]>;
skipStepButton: ReturnType<Page["getByRole"]>;
platformCheckboxes: ReturnType<Page["locator"]>;
selectAllButton: ReturnType<Page["getByRole"]>;
queryFrequencyOptions: ReturnType<Page["locator"]>;
healthScore: ReturnType<Page["locator"]>;
healthLevelBadge: ReturnType<Page["locator"]>;
viewActionsButton: ReturnType<Page["getByRole"]>;
completeButton: ReturnType<Page["getByRole"]>;
progressSteps: ReturnType<Page["locator"]>;
constructor(page: Page) {
this.page = page;
this.brandNameInput = this.page.locator("#brandName");
this.startAnalysisButton = this.page.getByRole("button", {
name: /开始分析/,
});
this.skipToDashboardButton = this.page.getByRole("button", {
name: /跳过.*Dashboard/,
});
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: /跳过此步骤/ });
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");
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: /查看行动建议/,
});
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);
try {
await this.page.waitForURL(/\/dashboard/, { timeout: 60000 });
} catch {
const currentUrl = this.page.url();
if (!currentUrl.includes("/dashboard")) {
await loginPage.goto();
await loginPage.login(TEST_USER.email, TEST_USER.password);
await this.page.waitForURL(/\/dashboard/, { timeout: 60000 });
}
}
await this.page.waitForLoadState("networkidle");
await this.page.goto("/onboarding");
await this.page.waitForLoadState("networkidle");
}
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();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
});
test("Step 2: 可以选择竞品并继续", async ({ page }) => {
const onboardingPage = new OnboardingPage(page);
await onboardingPage.goto();
await onboardingPage.fillBrandName("华为");
await onboardingPage.startAnalysisButton.click();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
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();
await expect(
page.getByRole("heading", { name: /选择监控平台/ }),
).toBeVisible({ timeout: 10000 });
});
test("Step 2: 跳过应进入下一步", async ({ page }) => {
const onboardingPage = new OnboardingPage(page);
await onboardingPage.goto();
await onboardingPage.fillBrandName("华为");
await onboardingPage.startAnalysisButton.click();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
await onboardingPage.skipStepButton.click();
await expect(
page.getByRole("heading", { name: /选择监控平台/ }),
).toBeVisible({ timeout: 10000 });
});
test("Step 3: 平台默认全选", async ({ page }) => {
const onboardingPage = new OnboardingPage(page);
await onboardingPage.goto();
await onboardingPage.fillBrandName("华为");
await onboardingPage.startAnalysisButton.click();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
await onboardingPage.skipStepButton.click();
await expect(
page.getByRole("heading", { name: /选择监控平台/ }),
).toBeVisible({ timeout: 10000 });
await expect(page.getByText(/\d+\/\d+ 个平台/)).toBeVisible();
});
test("Step 3: 可以选择不同频率", async ({ page }) => {
const onboardingPage = new OnboardingPage(page);
await onboardingPage.goto();
await onboardingPage.fillBrandName("华为");
await onboardingPage.startAnalysisButton.click();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
await onboardingPage.skipStepButton.click();
await expect(
page.getByRole("heading", { name: /选择监控平台/ }),
).toBeVisible({ timeout: 10000 });
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();
await onboardingPage.fillBrandName("华为");
await onboardingPage.startAnalysisButton.click();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
await onboardingPage.skipStepButton.click();
await expect(
page.getByRole("heading", { name: /选择监控平台/ }),
).toBeVisible({ timeout: 10000 });
await onboardingPage.backButton.click();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
});
test("Step 4: 跳过直接进入Dashboard", async ({ page }) => {
const onboardingPage = new OnboardingPage(page);
await onboardingPage.goto();
await expect(
page.getByRole("heading", { name: /输入您的品牌名称/ }),
).toBeVisible();
await onboardingPage.skipToDashboardButton.click();
await expect(page).toHaveURL(/\/dashboard/, { timeout: 15000 });
});
});
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();
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();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
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();
await onboardingPage.fillBrandName("华为");
await onboardingPage.startAnalysisButton.click();
await expect(page.getByRole("heading", { name: /确认竞品/ })).toBeVisible({
timeout: 10000,
});
await onboardingPage.skipStepButton.click();
await expect(
page.getByRole("heading", { name: /选择监控平台/ }),
).toBeVisible({ timeout: 10000 });
await onboardingPage.selectPlatform("文心一言");
await expect(onboardingPage.nextButton).toBeEnabled({ timeout: 10000 });
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;
}
}
});
});