cb8e092cc6
live 验收(8/8 通过, 对 api.aishufu.top:18080 admin 账号, Node fetch 直连): 登录可达、未登录 401、shop-keys 列表(camel)、shop-manages 列表+shopName 筛选 (仅掩码密码)、分组选项、无效店铺取凭证被拒、统一信封,均经真实响应与项目 解析器验证。
126 lines
5.7 KiB
TypeScript
126 lines
5.7 KiB
TypeScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { parseShopKeyPage } from '../../src/pages/shop/shop-key-model.ts'
|
|
import { parseShopManagePage } from '../../src/pages/shop/shop-manage-model.ts'
|
|
import { parseShopManageGroups } from '../../src/pages/shop/shop-group-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-task100-shop-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_100_shop_live_reachability_normal_primary_path', async () => {
|
|
// 正常主路径(无需凭据):真实服务在线,登录页可访问(200 + HTML)。
|
|
const res = await fetch(`${BASE}/login`)
|
|
assert.equal(res.status, 200)
|
|
const html = await res.text()
|
|
assert.ok(html.length > 0)
|
|
})
|
|
|
|
test('test_task_100_shop_live_unauth_rejected', async () => {
|
|
// 异常输入(无需凭据):无会话请求店铺中心列表 → 401 未登录。
|
|
for (const path of ['/api/admin/shop-keys', '/api/admin/shop-manages', '/api/admin/shop-manages/groups']) {
|
|
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_100_shop_live_keys_list', { skip: !HAS_CREDS }, async () => {
|
|
// 真实店铺密钥列表:camel pageSize 参数;经同一解析器归一(令牌为敏感字段)。
|
|
await ensureSession()
|
|
const res = await authedFetch('/api/admin/shop-keys?page=1&pageSize=15')
|
|
const page = parseShopKeyPage(await res.json())
|
|
assert.equal(res.status, 200)
|
|
assert.equal(typeof page.total, 'number')
|
|
assert.ok(Array.isArray(page.items))
|
|
if (page.items.length) {
|
|
const item = page.items[0]
|
|
assert.equal(typeof item.id, 'number')
|
|
assert.equal(typeof item.remarkName, 'string')
|
|
assert.equal(typeof item.ziniaoAccountName, 'string')
|
|
}
|
|
})
|
|
|
|
test('test_task_100_shop_live_manage_list', { skip: !HAS_CREDS }, async () => {
|
|
// 真实店铺列表:camel pageSize 参数;行仅保留掩码密码。
|
|
await ensureSession()
|
|
const res = await authedFetch('/api/admin/shop-manages?page=1&pageSize=15')
|
|
const page = parseShopManagePage(await res.json())
|
|
assert.equal(res.status, 200)
|
|
assert.equal(typeof page.total, 'number')
|
|
assert.ok(Array.isArray(page.items))
|
|
if (page.items.length) {
|
|
const item = page.items[0]
|
|
assert.equal(typeof item.id, 'number')
|
|
assert.equal('password' in item, false, '列表行不应携带密码明文字段')
|
|
assert.ok('shopName' in item)
|
|
}
|
|
})
|
|
|
|
test('test_task_100_shop_live_manage_filter', { skip: !HAS_CREDS }, async () => {
|
|
// 真实店铺筛选变体:非空 shopName 过滤返回也是合法分页。
|
|
await ensureSession()
|
|
const res = await authedFetch(`/api/admin/shop-manages?page=1&pageSize=15&shopName=${encodeURIComponent('店')}`)
|
|
const page = parseShopManagePage(await res.json())
|
|
assert.equal(res.status, 200)
|
|
assert.ok(Array.isArray(page.items))
|
|
})
|
|
|
|
test('test_task_100_shop_live_groups', { skip: !HAS_CREDS }, async () => {
|
|
// 真实店铺分组选项:GET /groups 返回下拉数组。
|
|
await ensureSession()
|
|
const res = await authedFetch('/api/admin/shop-manages/groups')
|
|
const options = parseShopManageGroups(await res.json())
|
|
assert.equal(res.status, 200)
|
|
assert.ok(Array.isArray(options))
|
|
})
|
|
|
|
test('test_task_100_shop_live_credential_denied_for_garbage', { skip: !HAS_CREDS }, async () => {
|
|
// 异常路径(真实):对不存在/无权限店铺取明文凭证应被拒绝(不再放行明文)。
|
|
await ensureSession()
|
|
const res = await authedFetch(`/api/admin/shop-manages/0/credential?shop_name=${encodeURIComponent('__no_such_shop__')}`)
|
|
const body = (await res.json()) as { success?: boolean; message?: string }
|
|
assert.equal(body.success, false, '无权限/不存在的店铺凭据不应下发')
|
|
})
|
|
|
|
test('test_task_100_shop_live_reachable_contract_summary', { skip: !HAS_CREDS }, async () => {
|
|
// 正常主路径(写? 否):只做读契约;三个列表接口均返回统一 success 信封。
|
|
await ensureSession()
|
|
for (const path of ['/api/admin/shop-keys?page=1&pageSize=5', '/api/admin/shop-manages?page=1&pageSize=5']) {
|
|
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)
|
|
}
|
|
})
|