Files
novalon-website/e2e/pages/AdminContentPage.ts
T
张翔 cda168cf60 feat: 创建Page Object Model基础结构
新增文件:
- e2e/pages/AdminLoginPage.ts - 管理员登录页面对象
- e2e/pages/AdminContentPage.ts - 内容管理页面对象
- e2e/pages/AdminUserPage.ts - 用户管理页面对象
- e2e/pages/FrontendNewsPage.ts - 前端新闻页面对象
- e2e/pages/FrontendProductPage.ts - 前端产品页面对象
- e2e/pages/index.ts - 导出索引文件

功能特性:
- 封装页面交互逻辑,减少测试代码重复
- 提供清晰的API接口,提升测试可读性
- 支持内容创建、删除、验证等核心操作
- 统一等待策略,提升测试稳定性
2026-04-09 13:17:37 +08:00

86 lines
2.5 KiB
TypeScript

import { Page, expect } from '@playwright/test';
export interface ContentData {
type: 'news' | 'product' | 'service' | 'case';
title: string;
slug: string;
excerpt?: string;
content?: string;
category?: string;
tags?: string[];
status?: 'draft' | 'published' | 'archived';
}
export class AdminContentPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/admin/content');
await this.page.waitForLoadState('networkidle');
}
async gotoCreate() {
await this.page.goto('/admin/content/new');
await this.page.waitForLoadState('domcontentloaded');
await this.page.waitForSelector('input[placeholder="请输入标题"]', { timeout: 60000 });
}
async createContent(data: ContentData): Promise<string | null> {
await this.gotoCreate();
await this.page.fill('input[placeholder="请输入标题"]', data.title);
await this.page.fill('input[placeholder="url-slug"]', data.slug);
if (data.excerpt) {
await this.page.fill('textarea', data.excerpt);
}
if (data.type) {
await this.page.locator('select').first().selectOption(data.type);
}
if (data.status) {
await this.page.locator('select').nth(1).selectOption(data.status);
}
if (data.category) {
await this.page.fill('input[placeholder="分类名称"]', data.category);
}
await this.page.click('button:has-text("发布")');
await this.page.waitForURL(/\/admin\/content\/[a-zA-Z0-9]+/, { timeout: 15000 });
const url = this.page.url();
const match = url.match(/\/admin\/content\/([a-zA-Z0-9]+)/);
return match ? match[1] : null;
}
async deleteContent(contentId: string) {
await this.goto();
const row = this.page.locator(`tr:has-text("${contentId}")`);
if (await row.count() > 0) {
await row.locator('button:has-text("删除")').click();
await this.page.locator('button:has-text("确认"), button:has-text("确定")').click();
await this.page.waitForResponse(resp =>
resp.url().includes('/api/admin/content') &&
resp.request().method() === 'DELETE',
{ timeout: 10000 }
);
}
}
async expectContentInList(title: string) {
await this.goto();
const row = this.page.locator(`tr:has-text("${title}")`);
await expect(row).toBeVisible();
}
async expectContentNotInList(title: string) {
await this.goto();
const row = this.page.locator(`tr:has-text("${title}")`);
await expect(row).not.toBeVisible();
}
}