import { expect, test, type Page } from '@playwright/test' import { getDebugState, loginAdmin, resetMockState } from './helpers' test.beforeEach(async ({ request }) => { await resetMockState(request) }) function acceptNextDialog(page: Page) { page.once('dialog', async (dialog) => { await dialog.accept() }) } function buildSvgPayload(name: string, label: string) { return { name, mimeType: 'image/svg+xml', buffer: Buffer.from( `${label}`, 'utf8', ), } } test('后台登录、导航与关键模块页面可加载', async ({ page }) => { await loginAdmin(page) const routes = [ { label: '概览', url: /\/$/, text: 'Astro 终端博客信息架构实战' }, { label: '数据分析', url: /\/analytics$/, text: 'playwright' }, { label: '文章', url: /\/posts$/, text: 'playwright-regression-workflow' }, { label: '分类', url: /\/categories$/, text: '前端工程' }, { label: '标签', url: /\/tags$/, text: 'Playwright' }, { label: '备份', url: /\/backups$/, text: '导出' }, { label: '版本', url: /\/revisions$/, text: 'astro-terminal-blog' }, { label: '评论', url: /\/comments$/, text: 'Carol' }, { label: '友链', url: /\/friend-links$/, text: 'Pending Link Review' }, { label: '评测', url: /\/reviews$/, text: '《漫长的季节》' }, { label: '媒体库', url: /\/media$/, text: '漫长的季节封面' }, { label: '订阅', url: /\/subscriptions$/, text: 'watcher@example.com' }, { label: '审计', url: /\/audit$/, text: 'playwright-smoke' }, { label: '设置', url: /\/settings$/, text: 'InitCool' }, ] for (const route of routes) { await page.getByRole('link', { name: route.label }).click() await expect(page).toHaveURL(route.url) await expect(page.locator('main')).toContainText(route.text) } }) test('后台可以审核评论和友链,并更新站点设置', async ({ page }) => { await loginAdmin(page) await page.getByRole('link', { name: '评论' }).click() await expect(page.locator('main')).toContainText('Carol') await page.getByRole('button', { name: '通过' }).first().click() await page.getByRole('link', { name: '友链' }).click() await expect(page.locator('main')).toContainText('Pending Link Review') await page.getByRole('button', { name: '通过' }).first().click() await page.getByRole('link', { name: '设置' }).click() await expect(page.locator('main')).toContainText('InitCool') await expect(page.getByTestId('site-settings-save')).toBeVisible() }) test('后台可完成分类与标签的创建、更新、删除', async ({ page, request }) => { await loginAdmin(page) await page.getByRole('link', { name: '分类' }).click() await page.getByTestId('category-name-input').fill('Playwright 深回归分类') await page.getByTestId('category-slug-input').fill('playwright-deep-category') await page.getByPlaceholder('介绍这个分类主要收录哪些内容。').fill('用于后台深度回归的分类。') await page.getByTestId('category-save').click() await expect(page.getByTestId('category-item-playwright-deep-category')).toBeVisible() await page.getByTestId('category-item-playwright-deep-category').click() await page.getByPlaceholder('前端工程专题 - Termi').fill('Playwright 深回归分类 SEO') await page.getByTestId('category-save').click() let state = await getDebugState(request) expect( state.categories.some( (item: { slug: string; seo_title: string }) => item.slug === 'playwright-deep-category' && item.seo_title === 'Playwright 深回归分类 SEO', ), ).toBeTruthy() acceptNextDialog(page) await page.getByTestId('category-delete').click() await expect(page.getByTestId('category-item-playwright-deep-category')).toHaveCount(0) await page.getByRole('link', { name: '标签' }).click() await page.getByTestId('tag-name-input').fill('Playwright 深回归标签') await page.getByTestId('tag-slug-input').fill('playwright-deep-tag') await page.getByPlaceholder('介绍这个标签常见主题、适合谁看。').fill('用于后台深度回归的标签。') await page.getByTestId('tag-save').click() await expect(page.getByTestId('tag-item-playwright-deep-tag')).toBeVisible() await page.getByTestId('tag-item-playwright-deep-tag').click() await page.getByPlaceholder('Astro 相关文章 - Termi').fill('Playwright 深回归标签 SEO') await page.getByTestId('tag-save').click() state = await getDebugState(request) expect( state.tags.some( (item: { slug: string; seo_title: string }) => item.slug === 'playwright-deep-tag' && item.seo_title === 'Playwright 深回归标签 SEO', ), ).toBeTruthy() acceptNextDialog(page) await page.getByTestId('tag-delete').click() await expect(page.getByTestId('tag-item-playwright-deep-tag')).toHaveCount(0) }) test('后台可完成订阅 CRUD、测试投递与 digest 入队', async ({ page, request }) => { await loginAdmin(page) await page.getByRole('link', { name: '订阅' }).click() await page.getByPlaceholder('name@example.com').fill('deep-regression@example.com') await page.getByPlaceholder('例如 站长邮箱 / Discord 运维群').fill('Deep Regression') await page.getByTestId('subscriptions-save').click() const row = page .locator('[data-testid^="subscription-row-"]') .filter({ hasText: 'deep-regression@example.com' }) await expect(row).toBeVisible() await row.getByTestId(/subscription-edit-/).click() await page.getByPlaceholder('例如 站长邮箱 / Discord 运维群').fill('Deep Regression Updated') await page.getByTestId('subscriptions-save').click() await expect(row).toContainText('Deep Regression Updated') await row.getByTestId(/subscription-test-/).click() await page.getByTestId('subscriptions-send-weekly').click() await page.getByTestId('subscriptions-send-monthly').click() let state = await getDebugState(request) expect( state.deliveries.some((item: { event_type: string; target: string }) => item.event_type === 'subscription.test' && item.target === 'deep-regression@example.com'), ).toBeTruthy() expect(state.deliveries.some((item: { event_type: string }) => item.event_type === 'digest.weekly')).toBeTruthy() expect(state.deliveries.some((item: { event_type: string }) => item.event_type === 'digest.monthly')).toBeTruthy() await row.getByTestId(/subscription-delete-/).click() await expect(row).toHaveCount(0) state = await getDebugState(request) expect( state.subscriptions.some((item: { target: string }) => item.target === 'deep-regression@example.com'), ).toBeFalsy() }) test('后台可完成文章创建、保存、版本恢复与删除', async ({ page, request }) => { await loginAdmin(page) await page.getByRole('link', { name: '文章' }).click() await page.getByTestId('posts-open-create').click() await page.getByTestId('post-create-title').fill('Playwright 深回归文章') await page.getByTestId('post-create-slug').fill('playwright-deep-post') await page.getByTestId('post-create-submit').click() await expect(page).toHaveURL(/\/posts\/playwright-deep-post$/) await expect(page.getByTestId('post-editor-title')).toHaveValue('Playwright 深回归文章') await page.getByTestId('post-editor-title').fill('Playwright 深回归文章(已更新)') await page.getByTestId('post-editor-save').click() await expect(page.getByTestId('post-editor-title')).toHaveValue('Playwright 深回归文章(已更新)') let state = await getDebugState(request) expect( state.posts.some( (item: { slug: string; title: string }) => item.slug === 'playwright-deep-post' && item.title === 'Playwright 深回归文章(已更新)', ), ).toBeTruthy() await page.getByTestId('post-editor-close').click() state = await getDebugState(request) const createRevision = state.post_revisions.find( (item: { id: number; post_slug: string; operation: string }) => item.post_slug === 'playwright-deep-post' && item.operation === 'create', ) expect(createRevision).toBeTruthy() await page.getByRole('link', { name: '版本' }).click() await page.getByTestId('revisions-slug-filter').fill('playwright-deep-post') await page.getByTestId(`revision-open-${createRevision.id}`).click() await page.getByTestId('revision-restore-full').click() await page.getByRole('link', { name: '文章' }).click() await page.getByTestId('post-item-playwright-deep-post').click() await expect(page.getByTestId('post-editor-title')).toHaveValue('Playwright 深回归文章') acceptNextDialog(page) await page.getByTestId('post-editor-delete').click() await expect(page).toHaveURL(/\/posts$/) state = await getDebugState(request) expect(state.posts.some((item: { slug: string }) => item.slug === 'playwright-deep-post')).toBeFalsy() }) test('后台可完成媒体库上传/元数据/替换/删除,并执行设置页关键动作', async ({ page, request }) => { await loginAdmin(page) await page.getByRole('link', { name: '媒体库' }).click() await page.getByTestId('media-upload-input').setInputFiles([ buildSvgPayload('deep-regression-cover.svg', 'deep-upload'), ]) await page.getByTestId('media-upload').click() await expect(page.getByTestId('media-item-0')).toContainText('deep-regression-cover.svg') await page.getByTestId('media-edit-0').click() await page.getByPlaceholder('文章封面 / 站点横幅').fill('Deep Regression Cover') await page.getByPlaceholder('夜色下的终端风格博客封面').fill('Deep Regression Alt') await page.getByPlaceholder('cover, astro, terminal').fill('playwright, regression') await page.getByTestId('media-save-metadata').click() let state = await getDebugState(request) expect( state.media.some( (item: { title: string; alt_text: string; tags: string[] }) => item.title === 'Deep Regression Cover' && item.alt_text === 'Deep Regression Alt' && item.tags.includes('playwright'), ), ).toBeTruthy() await page.getByTestId('media-replace-input-0').setInputFiles([ buildSvgPayload('deep-regression-cover.svg', 'deep-replaced'), ]) acceptNextDialog(page) await page.getByTestId('media-delete-0').click() state = await getDebugState(request) expect(state.media.some((item: { title: string }) => item.title === 'Deep Regression Cover')).toBeFalsy() await page.getByRole('link', { name: '设置' }).click() await page.getByTestId('site-settings-site-name').fill('InitCool Deep Regression') await page.getByTestId('site-settings-popup-title').fill('订阅深回归') await page.getByTestId('site-settings-save').click() await page.getByTestId('site-settings-reindex').click() await page.getByTestId('site-settings-test-provider').click() await page.getByTestId('site-settings-test-image-provider').click() await page.getByTestId('site-settings-test-storage').click() state = await getDebugState(request) expect(state.site_settings.site_name).toBe('InitCool Deep Regression') expect(state.site_settings.subscription_popup_title).toBe('订阅深回归') expect(state.site_settings.ai_chunks_count).toBeGreaterThan(128) }) test('后台可完成评测 CRUD、AI 润色,以及评论画像/黑名单管理', async ({ page, request }) => { await loginAdmin(page) await page.getByRole('link', { name: '评测' }).click() await page.getByTestId('review-title').fill('Playwright 深评测') await page.getByTestId('review-date').fill('2026-04-01') await page.getByTestId('review-description').fill('这是一段用于深度回归的评测简介。') await page.getByTestId('review-save').click() await expect(page.locator('main')).toContainText('Playwright 深评测') await page.getByTestId('review-ai-polish').click() await expect(page.getByText('AI 点评润色对比')).toBeVisible() await page.getByTestId('review-ai-adopt').click() await page.getByTestId('review-save').click() let state = await getDebugState(request) expect( state.reviews.some((item: { title: string }) => item.title === 'Playwright 深评测'), ).toBeTruthy() acceptNextDialog(page) await page.getByTestId('review-delete').click() state = await getDebugState(request) expect( state.reviews.some((item: { title: string }) => item.title === 'Playwright 深评测'), ).toBeFalsy() await page.getByRole('link', { name: '评论' }).click() await page.getByRole('button', { name: 'AI 分析' }).click() await expect(page.locator('main')).toContainText('建议保持观察') await page.getByPlaceholder('输入要封禁的值').fill('203.0.113.55') await page.getByPlaceholder('原因(可选)').first().fill('playwright deep regression') await page.getByTestId('comment-blacklist-add').click() state = await getDebugState(request) const createdRule = state.comment_blacklist.find( (item: { id: number; matcher_value: string }) => item.matcher_value === '203.0.113.55', ) expect(createdRule).toBeTruthy() await page.getByTestId(`blacklist-toggle-${createdRule.id}`).click() await page.getByTestId(`blacklist-toggle-${createdRule.id}`).click() acceptNextDialog(page) await page.getByTestId(`blacklist-delete-${createdRule.id}`).click() state = await getDebugState(request) expect( state.comment_blacklist.some((item: { matcher_value: string }) => item.matcher_value === '203.0.113.55'), ).toBeFalsy() })