329 lines
12 KiB
TypeScript
329 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/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
await expect(page.getByRole("heading", { name: "内容工坊" })).toBeVisible({ timeout: 15000 });
|
||
});
|
||
|
||
test("内容工坊页面副标题正确显示", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
await expect(page.getByText("AI驱动的内容生产流水线")).toBeVisible({ timeout: 15000 });
|
||
});
|
||
|
||
test("内容工坊页面显示AI生成新内容按钮", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const generateBtn = page.getByRole("button", { name: /AI生成新内容/ });
|
||
await expect(generateBtn).toBeVisible({ timeout: 15000 });
|
||
});
|
||
});
|
||
|
||
describe("内容工坊 - 内容列表测试", () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
await loginAndWait(page);
|
||
});
|
||
|
||
test("有内容时显示内容卡片列表", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("还没有内容");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
|
||
if (hasEmpty) { test.skip(); return; }
|
||
|
||
const contentCards = page.locator(".bg-white.rounded-xl.border");
|
||
const count = await contentCards.count();
|
||
expect(count).toBeGreaterThanOrEqual(1);
|
||
});
|
||
|
||
test("内容卡片显示状态标签", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("还没有内容");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
|
||
if (hasEmpty) { test.skip(); return; }
|
||
|
||
const statusBadge = page.getByText(/草稿|待审核|已审核|已发布|已归档/).first();
|
||
await expect(statusBadge).toBeVisible({ timeout: 10000 });
|
||
});
|
||
|
||
test("内容卡片显示类型标签", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("还没有内容");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
|
||
if (hasEmpty) { test.skip(); return; }
|
||
|
||
const typeBadge = page.getByText(/文章|问答|知识库|社媒/).first();
|
||
await expect(typeBadge).toBeVisible({ timeout: 10000 });
|
||
});
|
||
|
||
test("空状态时显示引导文案和AI生成按钮", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("还没有内容");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
if (!hasEmpty) { test.skip(); return; }
|
||
|
||
await expect(emptyState).toBeVisible();
|
||
const generateBtn = page.getByRole("button", { name: /AI生成新内容/ });
|
||
await expect(generateBtn).toBeVisible();
|
||
});
|
||
});
|
||
|
||
describe("内容工坊 - 内容生成测试", () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
await loginAndWait(page);
|
||
});
|
||
|
||
test("点击AI生成新内容打开生成对话框", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const generateBtn = page.getByRole("button", { name: /AI生成新内容/ }).first();
|
||
await generateBtn.click();
|
||
|
||
await expect(page.getByRole("dialog")).toBeVisible({ timeout: 10000 });
|
||
await expect(page.getByText("AI生成新内容")).toBeVisible();
|
||
});
|
||
|
||
test("生成对话框包含目标关键词输入框", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const generateBtn = page.getByRole("button", { name: /AI生成新内容/ }).first();
|
||
await generateBtn.click();
|
||
|
||
await expect(page.getByLabel("目标关键词")).toBeVisible({ timeout: 10000 });
|
||
});
|
||
|
||
test("生成对话框包含目标平台选择器", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const generateBtn = page.getByRole("button", { name: /AI生成新内容/ }).first();
|
||
await generateBtn.click();
|
||
|
||
await expect(page.getByLabel("目标平台")).toBeVisible({ timeout: 10000 });
|
||
});
|
||
|
||
test("未填写必填项时开始AI生成按钮禁用", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const generateBtn = page.getByRole("button", { name: /AI生成新内容/ }).first();
|
||
await generateBtn.click();
|
||
|
||
const submitBtn = page.getByRole("button", { name: /开始AI生成/ });
|
||
await expect(submitBtn).toBeDisabled({ timeout: 10000 });
|
||
});
|
||
|
||
test("填写关键词和平台后开始AI生成按钮启用", async ({ page }) => {
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const generateBtn = page.getByRole("button", { name: /AI生成新内容/ }).first();
|
||
await generateBtn.click();
|
||
|
||
const keywordInput = page.getByLabel("目标关键词");
|
||
await keywordInput.fill("AI营销");
|
||
|
||
const platformSelect = page.getByLabel("目标平台");
|
||
await platformSelect.click();
|
||
await page.getByText("通用").click();
|
||
|
||
const submitBtn = page.getByRole("button", { name: /开始AI生成/ });
|
||
await expect(submitBtn).toBeEnabled({ timeout: 10000 });
|
||
});
|
||
});
|
||
|
||
describe("监测优化 - 页面加载测试", () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
await loginAndWait(page);
|
||
});
|
||
|
||
test("监测优化页面标题正确显示", async ({ page }) => {
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
await expect(page.getByRole("heading", { name: "监测优化" })).toBeVisible({ timeout: 15000 });
|
||
});
|
||
|
||
test("监测优化页面副标题正确显示", async ({ page }) => {
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
await expect(page.getByText("实时监控品牌AI可见性,及时响应告警通知")).toBeVisible({ timeout: 15000 });
|
||
});
|
||
|
||
test("监测优化页面显示告警配置按钮", async ({ page }) => {
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const settingsBtn = page.getByRole("button", { name: /告警配置/ });
|
||
await expect(settingsBtn).toBeVisible({ timeout: 15000 });
|
||
});
|
||
|
||
test("监测优化页面显示监测记录和告警通知Tab", async ({ page }) => {
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
await expect(page.getByRole("tab", { name: /监测记录/ })).toBeVisible({ timeout: 15000 });
|
||
await expect(page.getByRole("tab", { name: /告警通知/ })).toBeVisible();
|
||
});
|
||
});
|
||
|
||
describe("监测优化 - 监测记录测试", () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
await loginAndWait(page);
|
||
});
|
||
|
||
test("无监测记录时显示空状态", async ({ page }) => {
|
||
if (!(await hasProjects(page))) { test.skip(); return; }
|
||
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("暂无监测记录");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
if (!hasEmpty) { test.skip(); return; }
|
||
|
||
await expect(emptyState).toBeVisible();
|
||
});
|
||
|
||
test("有监测记录时显示记录卡片", async ({ page }) => {
|
||
if (!(await hasProjects(page))) { test.skip(); return; }
|
||
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("暂无监测记录");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
if (hasEmpty) { test.skip(); return; }
|
||
|
||
const recordCards = page.locator("div.flex.items-center.gap-4");
|
||
const count = await recordCards.count();
|
||
expect(count).toBeGreaterThanOrEqual(1);
|
||
});
|
||
|
||
test("监测记录卡片包含立即检测按钮", async ({ page }) => {
|
||
if (!(await hasProjects(page))) { test.skip(); return; }
|
||
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("暂无监测记录");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
if (hasEmpty) { test.skip(); return; }
|
||
|
||
const checkBtn = page.getByRole("button", { name: /立即检测/ }).first();
|
||
await expect(checkBtn).toBeVisible({ timeout: 10000 });
|
||
});
|
||
|
||
test("监测记录卡片包含暂停/启用按钮", async ({ page }) => {
|
||
if (!(await hasProjects(page))) { test.skip(); return; }
|
||
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const emptyState = page.getByText("暂无监测记录");
|
||
const hasEmpty = await emptyState.isVisible({ timeout: 10000 }).catch(() => false);
|
||
if (hasEmpty) { test.skip(); return; }
|
||
|
||
const toggleBtn = page.getByRole("button", { name: /暂停|启用/ }).first();
|
||
await expect(toggleBtn).toBeVisible({ timeout: 10000 });
|
||
});
|
||
});
|
||
|
||
describe("监测优化 - 告警通知测试", () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
await loginAndWait(page);
|
||
});
|
||
|
||
test("点击告警通知Tab切换到告警列表", async ({ page }) => {
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const alertsTab = page.getByRole("tab", { name: /告警通知/ });
|
||
await alertsTab.click();
|
||
|
||
await expect(page.getByText("告警列表").or(page.getByText("暂无告警"))).toBeVisible({ timeout: 10000 });
|
||
});
|
||
|
||
test("告警通知Tab显示统计卡片", async ({ page }) => {
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
|
||
const alertsTab = page.getByRole("tab", { name: /告警通知/ });
|
||
await alertsTab.click();
|
||
|
||
const statCards = page.getByText(/未读告警|严重告警|今日新增|已处理/);
|
||
const count = await statCards.count();
|
||
expect(count).toBeGreaterThanOrEqual(1);
|
||
});
|
||
});
|
||
|
||
describe("内容→监测完整流程测试", () => {
|
||
test("从内容工坊导航到监测优化页面", async ({ page }) => {
|
||
await loginAndWait(page);
|
||
|
||
await page.goto("/dashboard/content");
|
||
await page.waitForLoadState("networkidle");
|
||
await expect(page.getByRole("heading", { name: "内容工坊" })).toBeVisible({ timeout: 15000 });
|
||
|
||
await page.goto("/dashboard/monitoring");
|
||
await page.waitForLoadState("networkidle");
|
||
await expect(page.getByRole("heading", { name: "监测优化" })).toBeVisible({ timeout: 15000 });
|
||
});
|
||
});
|