Files
photo-live/apps/admin/e2e/albums.spec.ts
T

133 lines
6.7 KiB
TypeScript
Raw Normal View History

// 相册管理 e2e(真实后端 + compose 基础设施):登录 → 创建(zh+en)→ 列表可见 →
// 编辑开关 → 标签更新;详情页:成员邀请(账号前缀搜索种子 staff)→ 分类创建 →
// banner 直传(init→PUT→complete)预览 → 管理照片列表(种子照片状态)→ 隐藏。
// 选择器一律 data-test(test.use testIdAttribute),与文案解耦。
import { expect, test, type Page } from '@playwright/test'
import { adminCredentials, loginAsAdmin, seedFixture } from './helpers'
test.use({ testIdAttribute: 'data-test' })
test.beforeAll(() => {
// 幂等种子 staff 账号(已存在则跳过;密码占位不可登录,仅用于邀请)
seedFixture('staff', 'staff-e2e', 'Staff E2E')
})
/** UI 创建相册(zh+en 标题),返回标题后缀 */
async function createAlbumViaUi(page: Page): Promise<string> {
const suffix = Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
await page.getByTestId('album-create-btn').click()
// UI06:创建改整页表单路由
await expect(page.getByTestId('album-form-page')).toBeVisible()
await page.getByTestId('album-form-title-zh-CN').fill(`E2E相册 ${suffix}`)
// 非激活页签的内容被隐藏(v-show):先切到英文页签再填写
await page.getByRole('tab', { name: '英文' }).click()
await page.getByTestId('album-form-title-en').fill(`E2E Album ${suffix}`)
// ElDatePicker 透传 attr 被 ElTooltip 吞掉:组件里用普通 div 挂 data-test,这里进 div 找 input
await page.getByTestId('album-form-start-at').locator('input').fill('2026-10-01') // UI06:日期粒度
await page.keyboard.press('Enter')
await page.getByTestId('album-form-submit').click()
// 保存成功后跳相册详情;返回列表做断言
await expect(page.getByTestId('album-form-page')).toBeHidden()
await page.goBack()
// UI06:列表默认封面卡片网格;表格断言前先切换
await page.getByTestId('album-view-table').click()
await expect(page.getByTestId('album-list-table').getByText(`E2E相册 ${suffix}`)).toBeVisible()
return suffix
}
/** 列表内定位目标相册行 */
function albumRow(page: Page, suffix: string) {
return page.getByTestId('album-list-table').locator('tr', { hasText: `E2E相册 ${suffix}` })
}
test('创建相册(zh+en)→ 列表可见 → 关闭上传开关 → 标签更新', async ({ page }) => {
await loginAsAdmin(page)
const suffix = await createAlbumViaUi(page)
const row = albumRow(page, suffix)
await row.getByTestId('album-edit-btn').click()
// UI06:编辑改整页表单(资料/访问页签)
await expect(page.getByTestId('album-form-page')).toBeVisible()
await page.getByRole('tab', { name: '访问' }).click()
await page.getByTestId('album-form-switch-upload').click()
await page.getByTestId('album-form-submit').click()
await expect(page.getByTestId('album-form-page')).toBeHidden()
await page.goBack()
await page.getByTestId('album-view-table').click()
await expect(albumRow(page, suffix).getByTestId('album-switch-upload')).toContainText('关')
})
test('详情:邀请成员 → 建分类 → 传 banner → 照片管理(隐藏)', async ({ page }) => {
await loginAsAdmin(page)
const suffix = await createAlbumViaUi(page)
// ── 进入详情 ──
await albumRow(page, suffix).getByTestId('album-detail-btn').click()
await expect(page.getByTestId('album-summary-cover')).toBeVisible()
const albumId = /\/albums\/detail\/([^/?#]+)/.exec(page.url())?.[1] ?? ''
expect(albumId).not.toBe('')
// ── 成员:前缀搜索种子 staff 账号并邀请 ──
await page.getByTestId('album-members-tab').click()
const searchSelect = page.getByTestId('member-search-select')
await searchSelect.click()
await searchSelect.locator('input').fill('staff-e2e')
await page.getByTestId('member-option-staff-e2e').click()
await page.getByTestId('member-invite-btn').click()
await expect(page.getByTestId('member-list-table').getByText('staff-e2e')).toBeVisible()
// owner 徽标(admin 自己)可见
await expect(
page.getByTestId('member-list-table').getByTestId('member-role-tag').first()
).toBeVisible()
// ── 分类:zh/en 名称 ──
await page.getByTestId('album-categories-tab').click()
await page.getByTestId('category-create-btn').click()
await page.getByTestId('category-form-name-zh').fill(`E2E分类 ${suffix}`)
await page.getByTestId('category-form-name-en').fill(`E2E Category ${suffix}`)
await page.getByTestId('category-form-submit').click()
await expect(page.getByTestId('category-form-dialog')).toBeHidden()
await expect(page.getByTestId('category-list-table').getByText(`E2E分类 ${suffix}`)).toBeVisible()
// ── banner:真实小 jpeg 走 file chooser → init/PUT/complete → 预览 ──
// UI06:banner 收进「品牌资产」页签
await page.getByTestId('album-assets-tab').click()
const fileChooserPromise = page.waitForEvent('filechooser')
await page.getByTestId('album-banner-pick').click()
const fileChooser = await fileChooserPromise
await fileChooser.setFiles({
name: 'banner-e2e.jpg',
mimeType: 'image/jpeg',
buffer: Buffer.from(
'/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwcJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPDs0NDT/wAALCAABAAEBAREA/8QAFAABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AmgA//9k=',
'base64'
)
})
await expect(page.getByTestId('album-banner-status-done')).toBeVisible({ timeout: 20_000 })
await expect(page.getByTestId('album-banner-preview-img')).toBeVisible()
// ── 照片管理:直种两种状态 → 列表可见 → 隐藏已发布照片 ──
seedFixture('photos', albumId, adminCredentials().account)
await page.reload()
// UI06:照片默认网格视图;表格断言前先切换
await page.getByTestId('photo-view-table').click()
await expect(page.getByTestId('photo-list-table')).toBeVisible()
// 用处理状态标签(就绪)锚定行:隐藏后行的可见性文案变化,锚点保持稳定
const publishedRow = page
.getByTestId('photo-list-table')
.locator('tr')
.filter({ has: page.getByTestId('photo-state-tag').filter({ hasText: '就绪' }) })
.first()
await expect(publishedRow.getByTestId('photo-state-tag')).toHaveText('就绪')
await expect(publishedRow.getByTestId('photo-visibility-tag')).toHaveText('已发布')
await publishedRow.getByTestId('photo-hide-btn').click()
await page.getByRole('button', { name: '确定' }).click()
await expect(publishedRow.getByTestId('photo-visibility-tag')).toHaveText('已隐藏')
// 处理失败状态标签也在列(种子第二行)
await expect(page.getByTestId('photo-list-table').getByText('处理失败')).toBeVisible()
})