task-120(任务与重复分析中心): 完成任务与重复检查真实验收
live 验收(8/8, api.aishufu.top admin 账号, Node fetch 直连):登录可达、未登录 401、视频任务列表、店铺数据任务列表、重复检查总览/明细/详情、统一信封。
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { parseImageVideoPage } from '../../src/pages/tasks/image-video-model.ts'
|
||||
import { parseShopDataTaskPage } from '../../src/pages/tasks/shop-data-model.ts'
|
||||
import { parseDuplicateOverview } from '../../src/pages/tasks/duplicate-model.ts'
|
||||
import { parseDuplicateItemsPage } from '../../src/pages/tasks/duplicate-model.ts'
|
||||
|
||||
const BASE = process.env.AIIMAGE_LIVE_BASE || 'http://127.0.0.1:18080'
|
||||
const USER = process.env.AIIMAGE_LIVE_USER || ''
|
||||
const PASS = process.env.AIIMAGE_LIVE_PASS || ''
|
||||
const HAS_CREDS = Boolean(USER && PASS)
|
||||
const DEVICE = 'claude-task120-task-acceptance'
|
||||
|
||||
let sessionCookie = ''
|
||||
let bearerToken = ''
|
||||
|
||||
async function ensureSession(): Promise<void> {
|
||||
if (sessionCookie || bearerToken) return
|
||||
const res = await fetch(`${BASE}/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username: USER, password: PASS, deviceId: DEVICE }),
|
||||
})
|
||||
const body = (await res.json()) as { success?: boolean; message?: string; data?: { token?: string } }
|
||||
assert.equal(body.success, true, `登录应成功: ${body.message || ''}`)
|
||||
if (body.data?.token) bearerToken = body.data.token
|
||||
const cookies = typeof res.headers.getSetCookie === 'function' ? res.headers.getSetCookie() : []
|
||||
const setCookie = cookies[0] || res.headers.get('set-cookie') || ''
|
||||
const match = /aiimage_token=([^;]+)/.exec(setCookie)
|
||||
if (match) sessionCookie = `aiimage_token=${match[1]}`
|
||||
assert.ok(sessionCookie || bearerToken, '登录应下发会话 cookie 或 token')
|
||||
}
|
||||
|
||||
async function authedFetch(path: string, init: RequestInit = {}): Promise<Response> {
|
||||
const headers: Record<string, string> = { ...(init.headers as Record<string, string>) }
|
||||
if (sessionCookie) headers.Cookie = sessionCookie
|
||||
else if (bearerToken) headers.Authorization = `Bearer ${bearerToken}`
|
||||
return fetch(`${BASE}${path}`, { ...init, headers })
|
||||
}
|
||||
|
||||
test('test_task_120_task_live_reachability_normal_primary_path', async () => {
|
||||
// 正常主路径(无需凭据):真实服务在线,登录页可访问。
|
||||
const res = await fetch(`${BASE}/login`)
|
||||
assert.equal(res.status, 200)
|
||||
const html = await res.text()
|
||||
assert.ok(html.length > 0)
|
||||
})
|
||||
|
||||
test('test_task_120_task_live_unauth_rejected', async () => {
|
||||
// 异常输入(无需凭据):任务/重复检查列表未登录返回 401。
|
||||
for (const path of ['/api/admin/image-video-tasks?page=1&page_size=5', '/api/admin/shop-data-crawl-tasks?page=1&page_size=5']) {
|
||||
const res = await fetch(`${BASE}${path}`)
|
||||
const body = (await res.json()) as { success?: boolean; code?: number }
|
||||
assert.equal(body.success, false, path)
|
||||
assert.equal(body.code, 401, path)
|
||||
}
|
||||
})
|
||||
|
||||
test('test_task_120_task_live_video_tasks', { skip: !HAS_CREDS }, async () => {
|
||||
// 真实视频任务列表:snake page_size 参数 + 解析归一。
|
||||
await ensureSession()
|
||||
const res = await authedFetch('/api/admin/image-video-tasks?page=1&page_size=5')
|
||||
const page = parseImageVideoPage(await res.json())
|
||||
assert.equal(res.status, 200)
|
||||
assert.ok(Array.isArray(page.items))
|
||||
assert.equal(typeof page.total, 'number')
|
||||
})
|
||||
|
||||
test('test_task_120_task_live_shop_data_tasks', { skip: !HAS_CREDS }, async () => {
|
||||
// 真实店铺数据任务列表(按店铺分组)。
|
||||
await ensureSession()
|
||||
const res = await authedFetch('/api/admin/shop-data-crawl-tasks?page=1&page_size=5')
|
||||
const page = parseShopDataTaskPage(await res.json())
|
||||
assert.equal(res.status, 200)
|
||||
assert.ok(Array.isArray(page.items))
|
||||
assert.equal(typeof page.total, 'number')
|
||||
})
|
||||
|
||||
test('test_task_120_task_live_duplicate_overview', { skip: !HAS_CREDS }, async () => {
|
||||
// 真实重复检查总览(pending 或已扫描均可解析)。
|
||||
await ensureSession()
|
||||
const res = await authedFetch('/api/admin/shop-data-crawl/duplicate-check-overview')
|
||||
const overview = parseDuplicateOverview(await res.json())
|
||||
assert.equal(res.status, 200)
|
||||
assert.equal(typeof overview.pending, 'boolean')
|
||||
assert.ok(Array.isArray(overview.shops))
|
||||
})
|
||||
|
||||
test('test_task_120_task_live_duplicate_items', { skip: !HAS_CREDS }, async () => {
|
||||
// 真实重复检查明细列表(pending 空态或数据)。
|
||||
await ensureSession()
|
||||
const res = await authedFetch('/api/admin/shop-data-crawl/duplicate-check-items?page=1&page_size=10')
|
||||
const page = parseDuplicateItemsPage(await res.json())
|
||||
assert.equal(res.status, 200)
|
||||
assert.equal(typeof page.pending, 'boolean')
|
||||
assert.ok(Array.isArray(page.items))
|
||||
})
|
||||
|
||||
test('test_task_120_task_live_duplicate_detail', { skip: !HAS_CREDS }, async () => {
|
||||
// 真实重复详情卡片分页。
|
||||
await ensureSession()
|
||||
const res = await authedFetch('/api/admin/shop-data-crawl/duplicate-check-detail?page=1&page_size=3')
|
||||
const detail = await res.json()
|
||||
assert.equal(res.status, 200)
|
||||
assert.ok(typeof detail === 'object')
|
||||
})
|
||||
|
||||
test('test_task_120_task_live_contract_summary', { skip: !HAS_CREDS }, async () => {
|
||||
// 正常主路径(读契约):统一 success 信封覆盖任务列表接口。
|
||||
await ensureSession()
|
||||
for (const path of ['/api/admin/image-video-tasks?page=1&page_size=2', '/api/admin/shop-data-crawl-tasks?page=1&page_size=2']) {
|
||||
const res = await authedFetch(path)
|
||||
const body = (await res.json()) as { success?: boolean; data?: unknown }
|
||||
assert.equal(body.success, true, path)
|
||||
assert.ok(body.data && typeof body.data === 'object', path)
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user