325 lines
12 KiB
TypeScript
325 lines
12 KiB
TypeScript
import { test, expect, describe } from "@playwright/test";
|
|
import { LoginPage } from "../pages/login.page";
|
|
import { DashboardPage } from "../pages/dashboard.page";
|
|
|
|
const TEST_USER = {
|
|
email: process.env.E2E_TEST_EMAIL || "admin@example.com",
|
|
password: process.env.E2E_TEST_PASSWORD || "admin@123",
|
|
};
|
|
|
|
async function loginAndWait(page: import("@playwright/test").Page) {
|
|
const loginPage = new LoginPage(page);
|
|
await loginPage.goto();
|
|
await loginPage.login(TEST_USER.email, TEST_USER.password);
|
|
try {
|
|
await page.waitForURL(/\/dashboard/, { timeout: 60000 });
|
|
} catch {
|
|
const currentUrl = page.url();
|
|
if (!currentUrl.includes("/dashboard")) {
|
|
await loginPage.goto();
|
|
await loginPage.login(TEST_USER.email, TEST_USER.password);
|
|
await page.waitForURL(/\/dashboard/, { timeout: 60000 });
|
|
}
|
|
}
|
|
await page.waitForLoadState("networkidle");
|
|
}
|
|
|
|
async function hasProjects(page: import("@playwright/test").Page): Promise<boolean> {
|
|
const dashboardPage = new DashboardPage(page);
|
|
await dashboardPage.waitForDashboardLoad();
|
|
const emptyMsg = page.getByText("开始优化您的AI可见性");
|
|
const errorTitle = page.getByText("数据加载失败");
|
|
const isEmpty = await emptyMsg.isVisible().catch(() => false);
|
|
const isError = await errorTitle.isVisible().catch(() => false);
|
|
return !isEmpty && !isError;
|
|
}
|
|
|
|
describe("诊断分析 - 页面加载测试", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginAndWait(page);
|
|
});
|
|
|
|
test("诊断分析页面标题正确显示", async ({ page }) => {
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
await expect(page.getByRole("heading", { name: "诊断分析" })).toBeVisible({ timeout: 15000 });
|
|
});
|
|
|
|
test("诊断分析页面副标题正确显示", async ({ page }) => {
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
await expect(page.getByText("全面评估品牌在搜索引擎和AI生成式引擎中的可见性")).toBeVisible({ timeout: 15000 });
|
|
});
|
|
|
|
test("无品牌时显示空状态", async ({ page }) => {
|
|
if (await hasProjects(page)) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
await expect(page.getByText("暂无品牌数据")).toBeVisible({ timeout: 15000 });
|
|
await expect(page.getByText("请先创建品牌,然后进行诊断分析")).toBeVisible();
|
|
});
|
|
});
|
|
|
|
describe("诊断分析 - 诊断流程测试", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginAndWait(page);
|
|
});
|
|
|
|
test("有品牌时显示重新诊断按钮", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const refreshBtn = page.getByRole("button", { name: /重新诊断/ });
|
|
await expect(refreshBtn).toBeVisible({ timeout: 15000 });
|
|
});
|
|
|
|
test("诊断页面显示三个评分卡片", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
await expect(page.getByText("综合评分")).toBeVisible({ timeout: 15000 });
|
|
await expect(page.getByText("SEO诊断评分")).toBeVisible();
|
|
await expect(page.getByText("GEO诊断评分")).toBeVisible();
|
|
});
|
|
|
|
test("诊断页面显示三个Tab标签", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
await expect(page.getByRole("tab", { name: "综合诊断" })).toBeVisible({ timeout: 15000 });
|
|
await expect(page.getByRole("tab", { name: "SEO诊断" })).toBeVisible();
|
|
await expect(page.getByRole("tab", { name: "GEO诊断" })).toBeVisible();
|
|
});
|
|
|
|
test("点击SEO诊断Tab显示SEO诊断详情", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const seoTab = page.getByRole("tab", { name: "SEO诊断" });
|
|
await seoTab.click();
|
|
|
|
await expect(page.getByText("SEO诊断详情")).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test("点击GEO诊断Tab显示GEO诊断详情", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const geoTab = page.getByRole("tab", { name: "GEO诊断" });
|
|
await geoTab.click();
|
|
|
|
await expect(page.getByText("GEO诊断详情")).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test("诊断结果显示5维度评分", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const geoTab = page.getByRole("tab", { name: "GEO诊断" });
|
|
await geoTab.click();
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const dimensionLabels = page.getByText(/内容可提取性|实体清晰度|E-E-A-T信号|Schema标记|主题权威|引用就绪度/);
|
|
const count = await dimensionLabels.count();
|
|
expect(count).toBeGreaterThanOrEqual(1);
|
|
});
|
|
|
|
test("点击重新诊断按钮触发刷新", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const refreshBtn = page.getByRole("button", { name: /重新诊断/ });
|
|
if (await refreshBtn.isVisible()) {
|
|
await refreshBtn.click();
|
|
await page.waitForLoadState("networkidle");
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("诊断分析 - 优先优化建议测试", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginAndWait(page);
|
|
});
|
|
|
|
test("诊断结果包含优先优化建议", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const recommendations = page.getByText("优先优化建议");
|
|
const hasRecommendations = await recommendations.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasRecommendations) { test.skip(); return; }
|
|
|
|
await expect(recommendations).toBeVisible();
|
|
});
|
|
|
|
test("建议列表包含基于诊断制定GEO方案按钮", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const geoPlanBtn = page.getByRole("button", { name: /基于诊断制定GEO方案/ });
|
|
const hasBtn = await geoPlanBtn.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasBtn) { test.skip(); return; }
|
|
|
|
await expect(geoPlanBtn).toBeVisible();
|
|
});
|
|
|
|
test("点击基于诊断制定GEO方案跳转到策略页面", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const geoPlanBtn = page.getByRole("button", { name: /基于诊断制定GEO方案/ });
|
|
const hasBtn = await geoPlanBtn.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasBtn) { test.skip(); return; }
|
|
|
|
await geoPlanBtn.click();
|
|
await expect(page).toHaveURL(/\/dashboard\/strategy/, { timeout: 15000 });
|
|
});
|
|
});
|
|
|
|
describe("策略制定 - 页面加载测试", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginAndWait(page);
|
|
});
|
|
|
|
test("策略制定页面标题正确显示", async ({ page }) => {
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
await expect(page.getByRole("heading", { name: "策略制定" })).toBeVisible({ timeout: 15000 });
|
|
});
|
|
|
|
test("策略制定页面副标题正确显示", async ({ page }) => {
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
await expect(page.getByText("制定GEO优化策略、关键词规划与目标设定")).toBeVisible({ timeout: 15000 });
|
|
});
|
|
|
|
test("无方案时显示生成新方案按钮", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const generateBtn = page.getByRole("button", { name: /生成新方案|生成优化方案/ });
|
|
const hasBtn = await generateBtn.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasBtn) { test.skip(); return; }
|
|
|
|
await expect(generateBtn.first()).toBeVisible();
|
|
});
|
|
});
|
|
|
|
describe("策略制定 - 方案详情测试", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await loginAndWait(page);
|
|
});
|
|
|
|
test("有方案时显示诊断分数和目标分数", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const scoreLabel = page.getByText("诊断分数 → 目标分数");
|
|
const hasScore = await scoreLabel.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasScore) { test.skip(); return; }
|
|
|
|
await expect(scoreLabel).toBeVisible();
|
|
});
|
|
|
|
test("有方案时显示预计周数", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const weeksLabel = page.getByText("预计周数");
|
|
const hasWeeks = await weeksLabel.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasWeeks) { test.skip(); return; }
|
|
|
|
await expect(weeksLabel).toBeVisible();
|
|
});
|
|
|
|
test("有方案时显示行动项进度", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const progressLabel = page.getByText("行动项进度");
|
|
const hasProgress = await progressLabel.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasProgress) { test.skip(); return; }
|
|
|
|
await expect(progressLabel).toBeVisible();
|
|
});
|
|
|
|
test("有方案时显示行动项列表", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const actionList = page.getByText("行动项列表");
|
|
const hasActions = await actionList.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasActions) { test.skip(); return; }
|
|
|
|
await expect(actionList).toBeVisible();
|
|
});
|
|
|
|
test("行动项包含AI生成内容按钮", async ({ page }) => {
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/strategy");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const aiGenBtn = page.getByRole("button", { name: /AI生成内容/ });
|
|
const hasBtn = await aiGenBtn.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasBtn) { test.skip(); return; }
|
|
|
|
await expect(aiGenBtn.first()).toBeVisible();
|
|
});
|
|
});
|
|
|
|
describe("诊断→策略完整流程测试", () => {
|
|
test("从诊断页面导航到策略制定页面", async ({ page }) => {
|
|
await loginAndWait(page);
|
|
|
|
if (!(await hasProjects(page))) { test.skip(); return; }
|
|
|
|
await page.goto("/dashboard/diagnosis");
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
const geoPlanBtn = page.getByRole("button", { name: /基于诊断制定GEO方案/ });
|
|
const hasBtn = await geoPlanBtn.isVisible({ timeout: 10000 }).catch(() => false);
|
|
if (!hasBtn) { test.skip(); return; }
|
|
|
|
await geoPlanBtn.click();
|
|
await expect(page).toHaveURL(/\/dashboard\/strategy/, { timeout: 15000 });
|
|
await expect(page.getByRole("heading", { name: "策略制定" })).toBeVisible({ timeout: 15000 });
|
|
});
|
|
});
|