library-picturebook-activity/lesingle-creation-frontend/e2e/public/work-status-split.spec.ts

256 lines
10 KiB
TypeScript
Raw Normal View History

import { test, expect, request as requestFactory, type APIRequestContext } from '@playwright/test'
/**
* UGC
*
* API localhost:8580
*/
// ── 配置 ──
const API_BASE = process.env.API_BASE_URL || 'http://localhost:8580/api'
const AUTH = {
username: process.env.TEST_USERNAME || 'demo',
password: process.env.TEST_PASSWORD || 'demo123456',
tenantCode: process.env.TEST_TENANT_CODE || 'gdlib',
}
const VALID_STATUSES = ['draft', 'unpublished', 'pending_review', 'published', 'rejected']
// ── Helper ──
function url(path: string) {
return `${API_BASE}${path}`
}
// ── Fixture ──
type Fixtures = { api: APIRequestContext }
const apiTest = test.extend<Fixtures>({
api: async ({}, use) => {
// 用 requestFactory顶层 import创建独立上下文来登录
const loginCtx = await requestFactory.newContext({})
const loginResp = await loginCtx.post(url('/public/auth/login'), {
data: { username: AUTH.username, password: AUTH.password, tenantCode: AUTH.tenantCode },
})
const loginJson = await loginResp.json()
await loginCtx.dispose()
if (loginJson.code !== 200 || !loginJson.data?.token) {
throw new Error(`登录失败: ${JSON.stringify(loginJson)}`)
}
const token = loginJson.data.token
// 创建带 auth header 的 API 上下文
const api = await requestFactory.newContext({
extraHTTPHeaders: { Authorization: `Bearer ${token}` },
})
await use(api)
await api.dispose()
},
})
// ══════════════════════════════════════════════════════
// 1. 我的作品列表 — status 是字符串枚举
// ══════════════════════════════════════════════════════
apiTest('S-01 我的作品列表 — status 字段为字符串', async ({ api }) => {
const resp = await api.get(url('/public/works?page=1&pageSize=5'))
const json = await resp.json()
expect(json.code).toBe(200)
expect(json.data.list).toBeInstanceOf(Array)
for (const work of json.data.list) {
expect(
VALID_STATUSES.includes(work.status),
`作品 id=${work.id} 的 status="${work.status}" 不是合法字符串枚举值`,
).toBe(true)
}
console.log(`✓ S-01: 返回 ${json.data.list.length} 条作品status 全部为字符串`)
})
apiTest('S-02 我的作品列表 — 按 status=draft 筛选', async ({ api }) => {
const resp = await api.get(url('/public/works?page=1&pageSize=50&status=draft'))
const json = await resp.json()
expect(json.code).toBe(200)
for (const work of json.data.list) {
expect(work.status).toBe('draft')
}
console.log(`✓ S-02: draft 筛选返回 ${json.data.list.length}`)
})
apiTest('S-03 我的作品列表 — 按 status=unpublished 筛选', async ({ api }) => {
const resp = await api.get(url('/public/works?page=1&pageSize=50&status=unpublished'))
const json = await resp.json()
expect(json.code).toBe(200)
for (const work of json.data.list) {
expect(work.status).toBe('unpublished')
}
console.log(`✓ S-03: unpublished 筛选返回 ${json.data.list.length}`)
})
apiTest('S-04 我的作品列表 — 按 status=published 筛选', async ({ api }) => {
const resp = await api.get(url('/public/works?page=1&pageSize=50&status=published'))
const json = await resp.json()
expect(json.code).toBe(200)
for (const work of json.data.list) {
expect(work.status).toBe('published')
}
console.log(`✓ S-04: published 筛选返回 ${json.data.list.length}`)
})
apiTest('S-05 我的作品列表 — 按 status=pending_review 筛选', async ({ api }) => {
const resp = await api.get(url('/public/works?page=1&pageSize=50&status=pending_review'))
const json = await resp.json()
expect(json.code).toBe(200)
for (const work of json.data.list) {
expect(work.status).toBe('pending_review')
}
console.log(`✓ S-05: pending_review 筛选返回 ${json.data.list.length}`)
})
apiTest('S-06 我的作品列表 — 按 status=rejected 筛选', async ({ api }) => {
const resp = await api.get(url('/public/works?page=1&pageSize=50&status=rejected'))
const json = await resp.json()
expect(json.code).toBe(200)
for (const work of json.data.list) {
expect(work.status).toBe('rejected')
}
console.log(`✓ S-06: rejected 筛选返回 ${json.data.list.length}`)
})
// ══════════════════════════════════════════════════════
// 2. 创建作品 — 初始 status 为 draft
// ══════════════════════════════════════════════════════
apiTest('S-07 创建作品 — 初始 status 为 draft', async ({ api }) => {
const resp = await api.post(url('/public/works'), {
data: {
title: `[E2E] 状态验证_${Date.now()}`,
description: 'Playwright 自动创建',
visibility: 'private',
},
})
const json = await resp.json()
expect(json.code).toBe(200)
expect(json.data.status).toBe('draft')
expect(typeof json.data.status).toBe('string')
console.log(`✓ S-07: 创建作品 id=${json.data.id}, status="${json.data.status}"`)
// 清理
if (json.data.id) {
await api.delete(url(`/public/works/${json.data.id}`))
}
})
// ══════════════════════════════════════════════════════
// 3. draft 不可发布
// ══════════════════════════════════════════════════════
apiTest('S-08 发布作品 — draft 状态不可发布', async ({ api }) => {
const createResp = await api.post(url('/public/works'), {
data: { title: `[E2E] 发布测试_${Date.now()}`, visibility: 'private' },
})
const createJson = await createResp.json()
expect(createJson.code).toBe(200)
const workId = createJson.data.id
const publishResp = await api.post(url(`/public/works/${workId}/publish`))
const publishJson = await publishResp.json()
expect(publishJson.code).toBe(400)
console.log(`✓ S-08: draft 发布被拒绝code=${publishJson.code}, msg="${publishJson.message}"`)
await api.delete(url(`/public/works/${workId}`))
})
// ══════════════════════════════════════════════════════
// 4. 创作历史
// ══════════════════════════════════════════════════════
apiTest('S-09 创作历史 — 作品 status 为字符串', async ({ api }) => {
const resp = await api.get(url('/public/creation/history?page=1&pageSize=5'))
const json = await resp.json()
expect(json.code).toBe(200)
if (json.data?.list?.length > 0) {
for (const work of json.data.list) {
expect(
VALID_STATUSES.includes(work.status),
`创作历史 id=${work.id} status="${work.status}" 不合法`,
).toBe(true)
}
}
console.log(`✓ S-09: 创作历史 ${json.data?.list?.length ?? 0}`)
})
// ══════════════════════════════════════════════════════
// 5. 作品详情
// ══════════════════════════════════════════════════════
apiTest('S-10 作品详情 — status + leaiStatus 字段', async ({ api }) => {
const listResp = await api.get(url('/public/works?page=1&pageSize=1'))
const listJson = await listResp.json()
if (listJson.data?.list?.length > 0) {
const workId = listJson.data.list[0].id
const detailResp = await api.get(url(`/public/works/${workId}`))
const detailJson = await detailResp.json()
expect(detailJson.code).toBe(200)
const work = detailJson.data.work
// status 必须是合法字符串
expect(VALID_STATUSES.includes(work.status)).toBe(true)
// leaiStatus 应为数字
if (work.leaiStatus != null) {
expect(typeof work.leaiStatus).toBe('number')
}
console.log(`✓ S-10: 作品详情 status="${work.status}", leaiStatus=${work.leaiStatus}`)
} else {
console.log('⚠ S-10: 没有作品可测试详情')
}
})
// ══════════════════════════════════════════════════════
// 6. 作品广场
// ══════════════════════════════════════════════════════
apiTest('S-11 作品广场 — 只返回已发布作品', async ({ api }) => {
const resp = await api.get(url('/public/gallery?page=1&pageSize=10'))
const json = await resp.json()
expect(json.code).toBe(200)
if (json.data?.list?.length > 0) {
for (const work of json.data.list) {
expect(work.status).toBe('published')
}
}
console.log(`✓ S-11: 广场 ${json.data?.list?.length ?? 0} 条已发布作品`)
})
// ══════════════════════════════════════════════════════
// 7. 收藏列表
// ══════════════════════════════════════════════════════
apiTest('S-12 我的收藏 — status 为字符串', async ({ api }) => {
const resp = await api.get(url('/public/mine/favorites?page=1&pageSize=5'))
const json = await resp.json()
expect(json.code).toBe(200)
if (json.data?.list?.length > 0) {
for (const item of json.data.list) {
if (item.status) {
expect(VALID_STATUSES.includes(item.status)).toBe(true)
}
}
}
console.log(`✓ S-12: 收藏 ${json.data?.list?.length ?? 0}`)
})