Files
photo-live/apps/admin/e2e/albums.spec.ts
T
2026-09-18 12:33:46 +08:00

120 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 相册管理 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()
await expect(page.getByTestId('album-form-dialog')).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 10:00:00')
await page.keyboard.press('Enter')
await page.getByTestId('album-form-submit').click()
await expect(page.getByTestId('album-form-dialog')).toBeHidden()
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()
await expect(page.getByTestId('album-form-dialog')).toBeVisible()
await page.getByTestId('album-form-switch-upload').click()
await page.getByTestId('album-form-submit').click()
await expect(page.getByTestId('album-form-dialog')).toBeHidden()
await expect(row.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-detail-card')).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 → 预览 ──
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()
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()
})