377 lines
12 KiB
TypeScript
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;
|
|
}
|
|
}
|
|
});
|
|
});
|