diff --git a/admin-frontend-vue/tests/live/task-140-records-live.test.ts b/admin-frontend-vue/tests/live/task-140-records-live.test.ts new file mode 100644 index 00000000..226002fa --- /dev/null +++ b/admin-frontend-vue/tests/live/task-140-records-live.test.ts @@ -0,0 +1,114 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import { parseHistoryPage } from '../../src/pages/records/history-model.ts' +import { parseSoftwareVersionList } from '../../src/pages/records/version-model.ts' +import { parseDigitalHumanVersions } from '../../src/pages/records/digitalhuman-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-task140-records-acceptance' + +let sessionCookie = '' +let bearerToken = '' + +async function ensureSession(): Promise { + 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 { + const headers: Record = { ...(init.headers as Record) } + if (sessionCookie) headers.Cookie = sessionCookie + else if (bearerToken) headers.Authorization = `Bearer ${bearerToken}` + return fetch(`${BASE}${path}`, { ...init, headers }) +} + +test('test_task_140_records_live_reachability', async () => { + // 真实服务在线。 + const res = await fetch(`${BASE}/login`) + assert.equal(res.status, 200) +}) + +test('test_task_140_records_live_unauth', async () => { + // 未登录访问后台记录/版本 → 401。 + for (const path of ['/api/admin/history?page=1&page_size=5&time_start=2026-08-01 00:00:00&time_end=2026-09-05 23:59:59', '/api/admin/versions']) { + 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_140_records_live_history', { skip: !HAS_CREDS }, async () => { + // 真实历史记录分页。 + await ensureSession() + const res = await authedFetch('/api/admin/history?page=1&page_size=5&time_start=2026-08-01 00:00:00&time_end=2026-09-05 23:59:59') + const page = parseHistoryPage(await res.json()) + assert.equal(res.status, 200) + assert.ok(Array.isArray(page.items)) + assert.equal(typeof page.total, 'number') +}) + +test('test_task_140_records_live_versions', { skip: !HAS_CREDS }, async () => { + // 真实客户端软件版本列表。 + await ensureSession() + const res = await authedFetch('/api/admin/versions') + const list = parseSoftwareVersionList(await res.json()) + assert.equal(res.status, 200) + assert.ok(Array.isArray(list.items)) +}) + +test('test_task_140_records_live_digital_human', { skip: !HAS_CREDS }, async () => { + // 真实数字人版本列表。 + await ensureSession() + const res = await authedFetch('/api/digital-human/versions') + const list = parseDigitalHumanVersions(await res.json()) + assert.equal(res.status, 200) + assert.ok(Array.isArray(list.items)) +}) + +test('test_task_140_records_live_contract', { skip: !HAS_CREDS }, async () => { + // 统一信封覆盖后台列表。 + await ensureSession() + for (const path of ['/api/admin/versions']) { + 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) + } +}) + +test('test_task_140_records_live_history_items', { skip: !HAS_CREDS }, async () => { + // 历史行字段契约(若有数据):username/panel_type 均为 string。 + await ensureSession() + const res = await authedFetch('/api/admin/history?page=1&page_size=5&time_start=2026-08-01 00:00:00&time_end=2026-09-05 23:59:59') + const page = parseHistoryPage(await res.json()) + if (page.items.length) { + assert.equal(typeof page.items[0].username, 'string') + assert.equal(typeof page.items[0].panelType, 'string') + } +}) + +test('test_task_140_records_live_versions_items', { skip: !HAS_CREDS }, async () => { + // 软件版本行字段契约(若有数据):version 为 string。 + await ensureSession() + const res = await authedFetch('/api/admin/versions') + const list = parseSoftwareVersionList(await res.json()) + if (list.items.length) { + assert.equal(typeof list.items[0].version, 'string') + } +})