feat(e2e): 优化测试配置并增强富文本编辑器测试
refactor(cases): 更新案例数据结构字段 test(admin): 增加富文本编辑器多种格式测试 fix(contact-form): 修复表单提交测试并移除skip标记 perf(smart-wait): 改进页面就绪等待逻辑 ci(playwright): 调整firefox配置并优化全局setup
This commit is contained in:
+37
-20
@@ -1,32 +1,49 @@
|
||||
import { chromium, FullConfig } from '@playwright/test';
|
||||
import { chromium, firefox, webkit, FullConfig } from '@playwright/test';
|
||||
import { getEnvironment } from './src/config/environments';
|
||||
|
||||
const env = getEnvironment();
|
||||
|
||||
async function globalSetup(_config: FullConfig) {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
|
||||
async function globalSetup(config: FullConfig) {
|
||||
const browserName = config.projects?.[0]?.use?.browserName || 'chromium';
|
||||
let browser;
|
||||
|
||||
try {
|
||||
await page.goto(`${env.baseURL}/admin/login`, { waitUntil: 'commit', timeout: 120000 });
|
||||
|
||||
await page.waitForSelector('#email', { timeout: 30000 });
|
||||
|
||||
await page.locator('#email').fill('admin@novalon.cn');
|
||||
await page.locator('#password').fill('admin123456');
|
||||
|
||||
await page.locator('button[type="submit"]').click();
|
||||
switch (browserName) {
|
||||
case 'firefox':
|
||||
browser = await firefox.launch();
|
||||
break;
|
||||
case 'webkit':
|
||||
browser = await webkit.launch();
|
||||
break;
|
||||
default:
|
||||
browser = await chromium.launch();
|
||||
}
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
||||
try {
|
||||
await page.waitForURL(/\/admin(?!\/login)/, { timeout: 30000 });
|
||||
await page.context().storageState({ path: '.auth/admin.json' });
|
||||
await page.goto(`${env.baseURL}/admin/login`, { waitUntil: 'commit', timeout: 120000 });
|
||||
|
||||
await page.waitForSelector('#email', { timeout: 30000 });
|
||||
|
||||
await page.locator('#email').fill('admin@novalon.cn');
|
||||
await page.locator('#password').fill('admin123456');
|
||||
|
||||
await page.locator('button[type="submit"]').click();
|
||||
|
||||
try {
|
||||
await page.waitForURL(/\/admin(?!\/login)/, { timeout: 30000 });
|
||||
await page.context().storageState({ path: '.auth/admin.json' });
|
||||
} catch {
|
||||
console.warn('登录失败,跳过需要认证的测试');
|
||||
}
|
||||
} catch {
|
||||
console.warn('登录失败,跳过需要认证的测试');
|
||||
console.warn('Admin登录页面不可用,跳过需要认证的测试');
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
} catch {
|
||||
console.warn('Admin登录页面不可用,跳过需要认证的测试');
|
||||
} finally {
|
||||
await browser.close();
|
||||
} catch (error) {
|
||||
console.warn(`浏览器启动失败 (${browserName}),跳过需要认证的测试:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ export default defineConfig({
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
globalSetup: undefined,
|
||||
},
|
||||
{
|
||||
name: 'webkit',
|
||||
|
||||
@@ -18,7 +18,7 @@ export const environments: Record<string, EnvironmentConfig> = {
|
||||
apiURL: 'http://localhost:3000/api',
|
||||
timeout: 120000,
|
||||
retries: 0,
|
||||
headless: false,
|
||||
headless: true,
|
||||
slowMo: 100,
|
||||
screenshot: 'only-on-failure',
|
||||
video: 'retain-on-failure',
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { test, expect } from '../../fixtures/admin.fixture';
|
||||
|
||||
test.describe('富文本编辑器E2E测试', () => {
|
||||
test('应该能够输入文本内容', async ({ page }) => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/admin/content/new');
|
||||
await page.locator('select[name="type"]').selectOption('news');
|
||||
});
|
||||
|
||||
test('应该能够输入文本内容', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('富文本测试');
|
||||
await page.locator('input[name="slug"]').fill('rich-text-test');
|
||||
|
||||
@@ -17,28 +20,194 @@ test.describe('富文本编辑器E2E测试', () => {
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用格式化工具', async ({ page }) => {
|
||||
await page.goto('/admin/content/new');
|
||||
await page.locator('select[name="type"]').selectOption('news');
|
||||
await page.locator('input[name="title"]').fill('格式化测试');
|
||||
await page.locator('input[name="slug"]').fill('formatting-test');
|
||||
test('应该能够使用粗体格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('粗体测试');
|
||||
await page.locator('input[name="slug"]').fill('bold-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('普通文本');
|
||||
await editor.fill('粗体文本');
|
||||
|
||||
await page.keyboard.selectText('普通文本');
|
||||
await page.keyboard.selectText('粗体文本');
|
||||
await page.getByRole('button', { name: '粗体' }).click();
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
const boldButton = page.getByRole('button', { name: '粗体' });
|
||||
await expect(boldButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用斜体格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('斜体测试');
|
||||
await page.locator('input[name="slug"]').fill('italic-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('斜体文本');
|
||||
|
||||
await page.keyboard.selectText('斜体文本');
|
||||
await page.getByRole('button', { name: '斜体' }).click();
|
||||
|
||||
const italicButton = page.getByRole('button', { name: '斜体' });
|
||||
await expect(italicButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用删除线格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('删除线测试');
|
||||
await page.locator('input[name="slug"]').fill('strikethrough-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('删除线文本');
|
||||
|
||||
await page.keyboard.selectText('删除线文本');
|
||||
await page.getByRole('button', { name: '删除线' }).click();
|
||||
|
||||
const strikeButton = page.getByRole('button', { name: '删除线' });
|
||||
await expect(strikeButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用代码格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('代码测试');
|
||||
await page.locator('input[name="slug"]').fill('code-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('console.log("test")');
|
||||
|
||||
await page.keyboard.selectText('console.log("test")');
|
||||
await page.getByRole('button', { name: '代码' }).click();
|
||||
|
||||
const codeButton = page.getByRole('button', { name: '代码' });
|
||||
await expect(codeButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用标题格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('标题测试');
|
||||
await page.locator('input[name="slug"]').fill('heading-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('标题1');
|
||||
|
||||
await page.keyboard.selectText('标题1');
|
||||
await page.getByRole('button', { name: '标题 1' }).click();
|
||||
|
||||
const h1Button = page.getByRole('button', { name: '标题 1' });
|
||||
await expect(h1Button).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用标题2格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('标题2测试');
|
||||
await page.locator('input[name="slug"]').fill('heading2-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('标题2');
|
||||
|
||||
await page.keyboard.selectText('标题2');
|
||||
await page.getByRole('button', { name: '标题 2' }).click();
|
||||
|
||||
const h2Button = page.getByRole('button', { name: '标题 2' });
|
||||
await expect(h2Button).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用标题3格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('标题3测试');
|
||||
await page.locator('input[name="slug"]').fill('heading3-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('标题3');
|
||||
|
||||
await page.keyboard.selectText('标题3');
|
||||
await page.getByRole('button', { name: '标题 3' }).click();
|
||||
|
||||
const h3Button = page.getByRole('button', { name: '标题 3' });
|
||||
await expect(h3Button).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用无序列表', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('无序列表测试');
|
||||
await page.locator('input[name="slug"]').fill('bullet-list-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('列表项1');
|
||||
|
||||
await page.getByRole('button', { name: '无序列表' }).click();
|
||||
|
||||
const listButton = page.getByRole('button', { name: '无序列表' });
|
||||
await expect(listButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用有序列表', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('有序列表测试');
|
||||
await page.locator('input[name="slug"]').fill('ordered-list-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('列表项1');
|
||||
|
||||
await page.getByRole('button', { name: '有序列表' }).click();
|
||||
|
||||
const listButton = page.getByRole('button', { name: '有序列表' });
|
||||
await expect(listButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够使用引用格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('引用测试');
|
||||
await page.locator('input[name="slug"]').fill('quote-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('这是一段引用文字');
|
||||
|
||||
await page.getByRole('button', { name: '引用' }).click();
|
||||
|
||||
const quoteButton = page.getByRole('button', { name: '引用' });
|
||||
await expect(quoteButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够添加链接', async ({ page }) => {
|
||||
await page.goto('/admin/content/new');
|
||||
await page.locator('select[name="type"]').selectOption('news');
|
||||
await page.locator('input[name="title"]').fill('链接测试');
|
||||
await page.locator('input[name="slug"]').fill('link-test');
|
||||
|
||||
@@ -61,24 +230,88 @@ test.describe('富文本编辑器E2E测试', () => {
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够添加列表', async ({ page }) => {
|
||||
await page.goto('/admin/content/new');
|
||||
await page.locator('select[name="type"]').selectOption('news');
|
||||
await page.locator('input[name="title"]').fill('列表测试');
|
||||
await page.locator('input[name="slug"]').fill('list-test');
|
||||
test('应该能够撤销操作', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('撤销测试');
|
||||
await page.locator('input[name="slug"]').fill('undo-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('原始文本');
|
||||
|
||||
await editor.fill('列表项1');
|
||||
await page.keyboard.press('Enter');
|
||||
await editor.type('列表项2');
|
||||
await page.keyboard.press('Enter');
|
||||
await editor.type('列表项3');
|
||||
await page.keyboard.selectText('原始文本');
|
||||
await page.getByRole('button', { name: '粗体' }).click();
|
||||
|
||||
const undoButton = page.getByRole('button', { name: '撤销' });
|
||||
await expect(undoButton).toBeEnabled();
|
||||
await undoButton.click();
|
||||
|
||||
const boldButton = page.getByRole('button', { name: '粗体' });
|
||||
await expect(boldButton).not.toHaveClass(/bg-gray-200/);
|
||||
});
|
||||
|
||||
test('应该能够重做操作', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('重做测试');
|
||||
await page.locator('input[name="slug"]').fill('redo-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('原始文本');
|
||||
|
||||
await page.keyboard.selectText('原始文本');
|
||||
await page.getByRole('button', { name: '粗体' }).click();
|
||||
|
||||
const undoButton = page.getByRole('button', { name: '撤销' });
|
||||
await undoButton.click();
|
||||
|
||||
const redoButton = page.getByRole('button', { name: '重做' });
|
||||
await expect(redoButton).toBeEnabled();
|
||||
await redoButton.click();
|
||||
|
||||
const boldButton = page.getByRole('button', { name: '粗体' });
|
||||
await expect(boldButton).toHaveClass(/bg-gray-200/);
|
||||
});
|
||||
|
||||
test('应该能够组合多种格式', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('组合格式测试');
|
||||
await page.locator('input[name="slug"]').fill('combined-format-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('粗体斜体文本');
|
||||
|
||||
await page.keyboard.selectText('粗体斜体文本');
|
||||
await page.getByRole('button', { name: '粗体' }).click();
|
||||
await page.getByRole('button', { name: '斜体' }).click();
|
||||
|
||||
const boldButton = page.getByRole('button', { name: '粗体' });
|
||||
const italicButton = page.getByRole('button', { name: '斜体' });
|
||||
|
||||
await expect(boldButton).toHaveClass(/bg-gray-200/);
|
||||
await expect(italicButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: /保存/i }).click();
|
||||
|
||||
await expect(page.locator('text=保存成功')).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
|
||||
test('应该能够切换格式状态', async ({ page }) => {
|
||||
await page.locator('input[name="title"]').fill('切换格式测试');
|
||||
await page.locator('input[name="slug"]').fill('toggle-format-test');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.waitFor({ state: 'visible', timeout: 10000 });
|
||||
await editor.click();
|
||||
await editor.fill('切换文本');
|
||||
|
||||
await page.keyboard.selectText('切换文本');
|
||||
await page.getByRole('button', { name: '粗体' }).click();
|
||||
|
||||
const boldButton = page.getByRole('button', { name: '粗体' });
|
||||
await expect(boldButton).toHaveClass(/bg-gray-200/);
|
||||
|
||||
await page.getByRole('button', { name: '粗体' }).click();
|
||||
await expect(boldButton).not.toHaveClass(/bg-gray-200/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,19 +6,16 @@ test.describe('联系表单回归测试 @regression', () => {
|
||||
await contactPage.waitForPageLoad();
|
||||
});
|
||||
|
||||
test.skip('应该能够提交完整的表单', async ({ contactPage, testDataGenerator }) => {
|
||||
test('应该能够提交完整的表单', async ({ contactPage, testDataGenerator }) => {
|
||||
const formData = testDataGenerator.generateContactFormData();
|
||||
await contactPage.fillAndSubmitForm(formData);
|
||||
|
||||
await contactPage.page.waitForTimeout(3000);
|
||||
|
||||
const isFormVisible = await contactPage.isFormVisible();
|
||||
console.log('Form visible after submission:', isFormVisible);
|
||||
await contactPage.page.waitForTimeout(5000);
|
||||
|
||||
const isSuccessVisible = await contactPage.isSuccessMessageVisible();
|
||||
console.log('Success message visible:', isSuccessVisible);
|
||||
|
||||
expect(isSuccessVisible || !isFormVisible).toBe(true);
|
||||
expect(isSuccessVisible).toBe(true);
|
||||
});
|
||||
|
||||
test.skip('应该验证必填字段', async ({ contactPage }) => {
|
||||
@@ -122,35 +119,35 @@ test.describe('联系表单回归测试 @regression', () => {
|
||||
expect(isLoading).toBe(true);
|
||||
});
|
||||
|
||||
test.skip('应该显示成功消息', async ({ contactPage, testDataGenerator }) => {
|
||||
test('应该显示成功消息', async ({ contactPage, testDataGenerator }) => {
|
||||
const formData = testDataGenerator.generateContactFormData();
|
||||
await contactPage.fillAndSubmitForm(formData);
|
||||
await contactPage.waitForFormSubmission();
|
||||
await contactPage.page.waitForTimeout(5000);
|
||||
const isSuccessVisible = await contactPage.isSuccessMessageVisible();
|
||||
expect(isSuccessVisible).toBe(true);
|
||||
});
|
||||
|
||||
test.skip('应该显示正确的成功消息文本', async ({ contactPage, testDataGenerator }) => {
|
||||
test('应该显示正确的成功消息文本', async ({ contactPage, testDataGenerator }) => {
|
||||
const formData = testDataGenerator.generateContactFormData();
|
||||
await contactPage.fillAndSubmitForm(formData);
|
||||
await contactPage.waitForFormSubmission();
|
||||
await contactPage.page.waitForTimeout(5000);
|
||||
const messageText = await contactPage.getSuccessMessageText();
|
||||
expect(messageText).toContain('消息已发送');
|
||||
expect(messageText).toContain('成功');
|
||||
});
|
||||
|
||||
test.skip('应该能够重新提交表单', async ({ contactPage, testDataGenerator }) => {
|
||||
test('应该能够重新提交表单', async ({ contactPage, testDataGenerator }) => {
|
||||
const formData1 = testDataGenerator.generateContactFormData();
|
||||
await contactPage.fillAndSubmitForm(formData1);
|
||||
await contactPage.waitForFormSubmission();
|
||||
await contactPage.page.waitForTimeout(5000);
|
||||
|
||||
await contactPage.page.reload();
|
||||
await contactPage.waitForPageLoad();
|
||||
|
||||
const formData2 = testDataGenerator.generateContactFormData();
|
||||
await contactPage.fillAndSubmitForm(formData2);
|
||||
await contactPage.waitForFormSubmission();
|
||||
const isSubmitted = await contactPage.isFormSubmitted();
|
||||
expect(isSubmitted).toBe(true);
|
||||
await contactPage.page.waitForTimeout(5000);
|
||||
const isSuccessVisible = await contactPage.isSuccessMessageVisible();
|
||||
expect(isSuccessVisible).toBe(true);
|
||||
});
|
||||
|
||||
test('应该能够输入空格', async ({ contactPage, testDataGenerator }) => {
|
||||
@@ -198,10 +195,10 @@ test.describe('联系表单回归测试 @regression', () => {
|
||||
expect(isVisible).toBe(true);
|
||||
});
|
||||
|
||||
test.skip('应该能够截取成功消息截图', async ({ contactPage, testDataGenerator }) => {
|
||||
test('应该能够截取成功消息截图', async ({ contactPage, testDataGenerator }) => {
|
||||
const formData = testDataGenerator.generateContactFormData();
|
||||
await contactPage.fillAndSubmitForm(formData);
|
||||
await contactPage.waitForFormSubmission();
|
||||
await contactPage.page.waitForTimeout(5000);
|
||||
const isSuccessVisible = await contactPage.isSuccessMessageVisible();
|
||||
expect(isSuccessVisible).toBe(true);
|
||||
});
|
||||
|
||||
@@ -38,18 +38,14 @@ test.describe('管理后台冒烟测试', () => {
|
||||
await loginPage.goto();
|
||||
await loginPage.login('admin@novalon.cn', 'admin123456');
|
||||
|
||||
try {
|
||||
await expect(async () => {
|
||||
await page.waitForURL(/\/admin(?!\/login)/);
|
||||
}).toPass({ timeout: 15000 });
|
||||
} catch (error) {
|
||||
test.skip(true, '登录功能不稳定,跳过此测试');
|
||||
}
|
||||
await page.waitForURL(/\/admin(?!\/login)/, { timeout: 20000 });
|
||||
await page.waitForLoadState('networkidle', { timeout: 10000 });
|
||||
|
||||
await expect(dashboardPage.contentMenuItem).toBeVisible();
|
||||
await expect(dashboardPage.settingsMenuItem).toBeVisible();
|
||||
await expect(dashboardPage.usersMenuItem).toBeVisible();
|
||||
await expect(dashboardPage.logsMenuItem).toBeVisible();
|
||||
await expect(dashboardPage.sidebar).toBeVisible({ timeout: 10000 });
|
||||
await expect(dashboardPage.contentMenuItem).toBeVisible({ timeout: 5000 });
|
||||
await expect(dashboardPage.settingsMenuItem).toBeVisible({ timeout: 5000 });
|
||||
await expect(dashboardPage.usersMenuItem).toBeVisible({ timeout: 5000 });
|
||||
await expect(dashboardPage.logsMenuItem).toBeVisible({ timeout: 5000 });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -86,20 +86,28 @@ export class SmartWait {
|
||||
throw new Error(`文本内容未在 ${timeout}ms 内出现: ${expectedText}`);
|
||||
}
|
||||
|
||||
async waitForPageReady(timeout: number = 15000) {
|
||||
async waitForPageReady(timeout: number = 30000) {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
await this.page.waitForLoadState('domcontentloaded', { timeout });
|
||||
|
||||
await this.waitForNetworkIdle(3000);
|
||||
try {
|
||||
await this.waitForNetworkIdle(2000);
|
||||
} catch {
|
||||
console.log('网络空闲等待失败,继续页面加载检查');
|
||||
}
|
||||
|
||||
const body = this.page.locator('body');
|
||||
await this.waitForElement(body, { timeout: 5000, state: 'visible' });
|
||||
try {
|
||||
const body = this.page.locator('body');
|
||||
await this.waitForElement(body, { timeout: 5000, state: 'visible' });
|
||||
} catch {
|
||||
console.log('Body元素等待超时,尝试继续');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log(`页面未在 ${timeout}ms 内就绪`);
|
||||
console.log(`页面未在 ${timeout}ms 内就绪: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+5033
-4804
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,8 @@ interface CaseItem {
|
||||
content: string;
|
||||
category: string;
|
||||
slug: string;
|
||||
publishedAt?: string;
|
||||
createdAt: string;
|
||||
date: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
interface CaseDetailClientProps {
|
||||
@@ -223,7 +223,7 @@ export function CaseDetailClient({ caseItem }: CaseDetailClientProps) {
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-sm text-[#737373]">发布时间</dt>
|
||||
<dd className="text-[#1C1C1C] font-medium">{caseItem.publishedAt || caseItem.createdAt}</dd>
|
||||
<dd className="text-[#1C1C1C] font-medium">{caseItem.date}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
@@ -10,8 +10,8 @@ interface CaseItem {
|
||||
content: string;
|
||||
category: string;
|
||||
slug: string;
|
||||
publishedAt?: string;
|
||||
createdAt: string;
|
||||
date: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
|
||||
Reference in New Issue
Block a user