dev #5
+145
-26
@@ -12,69 +12,188 @@ export interface ContentData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AdminContentPage {
|
export class AdminContentPage {
|
||||||
constructor(private page: Page) {}
|
constructor(private page: Page) { }
|
||||||
|
|
||||||
async goto() {
|
async goto() {
|
||||||
await this.page.goto('/admin/content');
|
try {
|
||||||
await this.page.waitForLoadState('networkidle');
|
await this.page.goto('/admin/content', { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||||
|
} catch (error) {
|
||||||
|
console.log('导航失败,尝试重新加载:', error);
|
||||||
|
try {
|
||||||
|
await this.page.reload({ waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||||
|
} catch (reloadError) {
|
||||||
|
console.log('重新加载失败:', reloadError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.page.waitForLoadState('domcontentloaded');
|
||||||
|
await this.page.waitForSelector('table', { timeout: 10000, state: 'visible' });
|
||||||
|
await this.page.waitForTimeout(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
async gotoCreate() {
|
async gotoCreate() {
|
||||||
await this.page.goto('/admin/content/new');
|
try {
|
||||||
|
await this.page.goto('/admin/content/new', { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||||
|
} catch (error) {
|
||||||
|
console.log('导航到创建页面失败,尝试重新加载:', error);
|
||||||
|
await this.page.reload({ waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||||
|
}
|
||||||
await this.page.waitForLoadState('domcontentloaded');
|
await this.page.waitForLoadState('domcontentloaded');
|
||||||
await this.page.waitForSelector('input[placeholder="请输入标题"]', { timeout: 60000 });
|
await this.page.waitForSelector('input[placeholder="请输入标题"]', { timeout: 10000, state: 'visible' });
|
||||||
}
|
}
|
||||||
|
|
||||||
async createContent(data: ContentData): Promise<string | null> {
|
async createContent(data: ContentData): Promise<string | null> {
|
||||||
await this.gotoCreate();
|
await this.gotoCreate();
|
||||||
|
|
||||||
await this.page.fill('input[placeholder="请输入标题"]', data.title);
|
await this.page.fill('input[placeholder="请输入标题"]', data.title);
|
||||||
await this.page.fill('input[placeholder="url-slug"]', data.slug);
|
await this.page.fill('input[placeholder="url-slug"]', data.slug);
|
||||||
|
|
||||||
if (data.excerpt) {
|
if (data.excerpt) {
|
||||||
await this.page.fill('textarea', data.excerpt);
|
await this.page.fill('textarea', data.excerpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type) {
|
if (data.type) {
|
||||||
await this.page.locator('select').first().selectOption(data.type);
|
await this.page.locator('select').first().selectOption(data.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.status) {
|
if (data.status) {
|
||||||
await this.page.locator('select').nth(1).selectOption(data.status);
|
await this.page.locator('select').nth(1).selectOption(data.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.category) {
|
if (data.category) {
|
||||||
await this.page.fill('input[placeholder="分类名称"]', data.category);
|
await this.page.fill('input[placeholder="分类名称"]', data.category);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.page.click('button:has-text("发布")');
|
await this.page.click('button:has-text("发布")');
|
||||||
|
|
||||||
await this.page.waitForURL(/\/admin\/content\/[a-zA-Z0-9]+/, { timeout: 15000 });
|
try {
|
||||||
|
await this.page.waitForURL(/\/admin\/content\/[a-zA-Z0-9]+/, { timeout: 15000 });
|
||||||
|
} catch {
|
||||||
|
console.log('等待URL跳转失败,当前URL:', this.page.url());
|
||||||
|
|
||||||
|
await this.page.waitForTimeout(2000);
|
||||||
|
|
||||||
|
const currentUrl = this.page.url();
|
||||||
|
if (currentUrl.includes('/admin/content/')) {
|
||||||
|
console.log('URL已跳转到内容详情页:', currentUrl);
|
||||||
|
} else {
|
||||||
|
console.log('URL未跳转,可能创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.page.waitForLoadState('domcontentloaded');
|
||||||
|
await this.page.waitForTimeout(1000);
|
||||||
|
|
||||||
const url = this.page.url();
|
const url = this.page.url();
|
||||||
|
console.log('最终URL:', url);
|
||||||
|
|
||||||
const match = url.match(/\/admin\/content\/([a-zA-Z0-9]+)/);
|
const match = url.match(/\/admin\/content\/([a-zA-Z0-9]+)/);
|
||||||
return match ? match[1] : null;
|
const contentId = match ? match[1] : null;
|
||||||
|
|
||||||
|
if (!contentId) {
|
||||||
|
console.log('无法从URL提取contentId:', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return contentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteContent(contentId: string) {
|
async deleteContent(contentId: string) {
|
||||||
await this.goto();
|
await this.goto();
|
||||||
|
|
||||||
const row = this.page.locator(`tr:has-text("${contentId}")`);
|
const row = this.page.locator(`tr:has-text("${contentId}")`);
|
||||||
|
|
||||||
if (await row.count() > 0) {
|
try {
|
||||||
await row.locator('button:has-text("删除")').click();
|
if (await row.count() > 0) {
|
||||||
await this.page.locator('button:has-text("确认"), button:has-text("确定")').click();
|
await row.first().locator('button:has-text("删除")').click({ timeout: 5000 });
|
||||||
await this.page.waitForResponse(resp =>
|
await this.page.waitForTimeout(500);
|
||||||
resp.url().includes('/api/admin/content') &&
|
const confirmButton = this.page.locator('button:has-text("确认"), button:has-text("确定"), button:has-text("删除")').first();
|
||||||
resp.request().method() === 'DELETE',
|
await confirmButton.click({ timeout: 5000 });
|
||||||
{ timeout: 10000 }
|
await this.page.waitForResponse(resp =>
|
||||||
);
|
resp.url().includes('/api/admin/content') &&
|
||||||
|
resp.request().method() === 'DELETE',
|
||||||
|
{ timeout: 10000 }
|
||||||
|
).catch(() => {
|
||||||
|
console.log('删除请求可能已完成');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`删除内容失败 (ID: ${contentId}):`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteContentByTitle(title: string) {
|
||||||
|
try {
|
||||||
|
await this.goto();
|
||||||
|
|
||||||
|
const row = this.page.locator(`tr:has-text("${title}")`);
|
||||||
|
|
||||||
|
if (await row.count() > 0) {
|
||||||
|
await row.first().locator('button[title="删除"]').click({ timeout: 5000 });
|
||||||
|
await this.page.waitForTimeout(300);
|
||||||
|
|
||||||
|
await this.page.click('button:has-text("确认删除")', { timeout: 5000 });
|
||||||
|
|
||||||
|
await this.page.waitForResponse(resp =>
|
||||||
|
resp.url().includes('/api/admin/content') &&
|
||||||
|
resp.request().method() === 'DELETE',
|
||||||
|
{ timeout: 8000 }
|
||||||
|
).catch(() => {
|
||||||
|
console.log('删除请求可能已完成');
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.page.waitForTimeout(500);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`删除内容失败 (标题: ${title}):`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async expectContentInList(title: string) {
|
async expectContentInList(title: string) {
|
||||||
|
console.log(`检查内容是否在列表中: ${title}`);
|
||||||
|
|
||||||
await this.goto();
|
await this.goto();
|
||||||
const row = this.page.locator(`tr:has-text("${title}")`);
|
await this.page.waitForLoadState('domcontentloaded');
|
||||||
await expect(row).toBeVisible();
|
await this.page.waitForTimeout(2000);
|
||||||
|
|
||||||
|
let row = this.page.locator(`tr:has-text("${title}")`);
|
||||||
|
let isVisible = await row.count() > 0;
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
console.log('内容不在第一页,尝试搜索');
|
||||||
|
|
||||||
|
const searchInput = this.page.locator('input[placeholder*="搜索"]');
|
||||||
|
if (await searchInput.count() > 0) {
|
||||||
|
await searchInput.fill(title);
|
||||||
|
await this.page.keyboard.press('Enter');
|
||||||
|
await this.page.waitForTimeout(2000);
|
||||||
|
|
||||||
|
row = this.page.locator(`tr:has-text("${title}")`);
|
||||||
|
isVisible = await row.count() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
console.log('搜索后仍未找到,尝试刷新页面');
|
||||||
|
await this.page.reload({ waitUntil: 'domcontentloaded' });
|
||||||
|
await this.page.waitForSelector('table', { timeout: 10000, state: 'visible' });
|
||||||
|
await this.page.waitForTimeout(2000);
|
||||||
|
|
||||||
|
row = this.page.locator(`tr:has-text("${title}")`);
|
||||||
|
isVisible = await row.count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
const allRows = this.page.locator('table tbody tr');
|
||||||
|
const rowCount = await allRows.count();
|
||||||
|
console.log(`列表中共有 ${rowCount} 行内容`);
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.min(rowCount, 10); i++) {
|
||||||
|
const rowText = await allRows.nth(i).textContent();
|
||||||
|
console.log(`行 ${i + 1}: ${rowText?.trim().substring(0, 150)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await expect(row.first()).toBeVisible({ timeout: 15000 });
|
||||||
|
console.log(`✅ 找到内容: ${title}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async expectContentNotInList(title: string) {
|
async expectContentNotInList(title: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user