Files
crawler-plugin/admin-frontend-vue/tests/task-71.test.ts
T
huangzd1997 9d25f13fe9 task-71(ASIN 数据中心): 实现查询 ASIN 列表和筛选
GET /api/admin/query-asins 列表解析(QueryAsinPageVo, 每店铺 5 国家 ASIN 宽行)
+ 分组/店铺名/ASIN/国家筛选归一与 camel 序列化(页大小上限 100 对齐后端),
9 个纯逻辑契约测试覆盖正常/边界/异常路径。
2026-09-05 16:05:10 +08:00

177 lines
7.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.
import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import {
parseQueryAsinPage,
toQueryAsinItem,
asinForCountry,
queryAsinItemHasAnyAsin,
QUERY_ASIN_COUNTRIES,
} from '../src/pages/asin/query-asin-model.ts'
import {
createQueryAsinFilterState,
queryAsinFilterActive,
normalizeQueryAsinCountry,
toQueryAsinParams,
toQueryAsinQuery,
} from '../src/pages/asin/query-asin-filter.ts'
test('test_task_071_query_asin_list_normal_primary_path', () => {
// 正常主路径:Java QueryAsinPageVo(camel) 宽行(每店铺 5 国家 ASIN)解析为前端分页结果。
const page = parseQueryAsinPage({
success: true,
data: {
items: [
{
id: 11,
groupId: 3,
groupName: '华东组',
shopName: 'BlueWave',
asinDe: 'B0DE001',
asinUk: 'B0UK001',
asinFr: 'B0FR001',
asinIt: 'B0IT001',
asinEs: 'B0ES001',
createdAt: '2026-01-01T10:00:00',
updatedAt: '2026-01-02T11:00:00',
},
],
total: 1,
page: 1,
pageSize: 15,
},
})
assert.equal(page.items.length, 1)
const item = page.items[0]
assert.equal(item.id, 11)
assert.equal(item.groupId, 3)
assert.equal(item.groupName, '华东组')
assert.equal(item.shopName, 'BlueWave')
assert.equal(item.asinDe, 'B0DE001')
assert.equal(item.asinUk, 'B0UK001')
assert.equal(item.asinFr, 'B0FR001')
assert.equal(item.asinIt, 'B0IT001')
assert.equal(item.asinEs, 'B0ES001')
assert.equal(item.createdAt, '2026-01-01T10:00:00')
assert.equal(page.total, 1)
assert.equal(page.pageSize, 15)
})
test('test_task_071_query_asin_list_normal_variant_input', () => {
// 正常变体:已解包 VO 直传归一;蛇形 asin_de 兜底;缺国家 ASIN/分组留空。
const page = parseQueryAsinPage({
items: [{ id: 12, shopName: 'RedSun', asin_de: 'B0DE002', asinUk: 'B0UK002' }],
total: 4,
page: 2,
pageSize: 20,
})
const item = page.items[0]
assert.equal(item.shopName, 'RedSun')
assert.equal(item.asinDe, 'B0DE002')
assert.equal(item.asinUk, 'B0UK002')
assert.equal(item.asinFr, '')
assert.equal(item.groupId, null)
assert.equal(item.groupName, '')
assert.equal(page.page, 2)
assert.equal(page.pageSize, 20)
})
test('test_task_071_query_asin_list_normal_repeated_is_idempotent', () => {
// 正常重复:解析与筛选参数生成不改输入、结果稳定。
const payload = {
data: { items: [{ id: 13, shopName: 'A', asinDe: 'X' }], total: 1, page: 1, pageSize: 15 },
}
assert.deepEqual(parseQueryAsinPage(payload), parseQueryAsinPage(payload))
const state = { groupId: null, shopName: ' 店 ', asin: '', country: '' }
const first = toQueryAsinParams(state, 1, 15)
const second = toQueryAsinParams(state, 1, 15)
assert.deepEqual(first, second)
assert.deepEqual(state, { groupId: null, shopName: ' 店 ', asin: '', country: '' }, '不修改调用方状态')
})
test('test_task_071_query_asin_list_boundary_empty_input', () => {
// 边界空值:空负载回默认分页结果(空列表/total 0/page 1/页大小 15)。
const page = parseQueryAsinPage({})
assert.deepEqual(page.items, [])
assert.equal(page.total, 0)
assert.equal(page.page, 1)
assert.equal(page.pageSize, 15)
})
test('test_task_071_query_asin_list_boundary_single_item', () => {
// 边界单元素:单条记录;缺 id 的行被过滤。
const page = parseQueryAsinPage({
data: { items: [{ id: 7, shopName: 'Z' }, { shopName: 'no-id' }], total: 2, page: 1, pageSize: 15 },
})
assert.equal(page.items.length, 1)
assert.equal(page.items[0].id, 7)
})
test('test_task_071_query_asin_list_boundary_limit_or_missing_field', () => {
// 边界上限/缺字段:页码下限 1、页大小上限 100 对齐后端;空白/非法/小于1的分组不下发。
const query = toQueryAsinQuery(toQueryAsinParams(
{ groupId: 0, shopName: ' ', asin: '', country: 'XX' },
0,
999,
))
assert.equal(query.page, 1)
assert.equal(query.pageSize, 100)
assert.equal('groupId' in query, false, '分组 0 不应下发')
assert.equal('shopName' in query, false, '空白店铺名不应下发')
assert.equal('asin' in query, false)
assert.equal('country' in query, false, '不支持的国家码不应下发')
// 正常非空值仍以 Java camelCase 参数名下发。
const filled = toQueryAsinQuery(toQueryAsinParams(
{ groupId: 5, shopName: ' 蓝店 ', asin: 'B0X', country: 'de' },
3,
25,
))
assert.equal(filled.page, 3)
assert.equal(filled.pageSize, 25)
assert.equal(filled.groupId, 5)
assert.equal(filled.shopName, '蓝店')
assert.equal(filled.asin, 'B0X')
assert.equal(filled.country, 'DE')
assert.equal('page_size' in (filled as Record<string, unknown>), false, '不应下发 page_size(snake)')
})
test('test_task_071_query_asin_country_semantics', () => {
// 国家语义:每店铺行按国家取 ASIN 列、整行是否有任一国家 ASIN;国家码大小写归一与白名单。
const item = toQueryAsinItem({ id: 21, shopName: 'S', asinDe: 'DE1', asinEs: 'ES1' })
assert.ok(item)
assert.equal(QUERY_ASIN_COUNTRIES.length, 5)
assert.equal(asinForCountry(item!, 'DE'), 'DE1')
assert.equal(asinForCountry(item!, 'UK'), '')
assert.equal(asinForCountry(item!, 'ES'), 'ES1')
assert.equal(asinForCountry(item!, 'XX'), '')
assert.equal(queryAsinItemHasAnyAsin(item!), true)
const empty = toQueryAsinItem({ id: 22, shopName: 'E' })
assert.equal(queryAsinItemHasAnyAsin(empty!), false)
assert.equal(normalizeQueryAsinCountry('de'), 'DE')
assert.equal(normalizeQueryAsinCountry('UK'), 'UK')
assert.equal(normalizeQueryAsinCountry(''), '')
assert.equal(normalizeQueryAsinCountry('CN'), '')
assert.equal(queryAsinFilterActive({ groupId: null, shopName: '', asin: '', country: '' }), false)
assert.equal(queryAsinFilterActive({ groupId: null, shopName: ' 店 ', asin: '', country: '' }), true)
assert.equal(queryAsinFilterActive({ groupId: 2, shopName: '', asin: '', country: '' }), true)
})
test('test_task_071_query_asin_list_invalid_input_rejected', () => {
// 异常输入:success=false 抛后端 message;非对象/非数字 id 行不入列表;非法国家被归一丢弃。
assert.throws(() => parseQueryAsinPage({ success: false, message: '无权访问查询 ASIN 数据' }), /无权访问/)
assert.equal(toQueryAsinItem('garbage'), null)
assert.equal(toQueryAsinItem({ shopName: 'no id' }), null)
assert.deepEqual(createQueryAsinFilterState(), { groupId: null, shopName: '', asin: '', country: '' })
})
test('test_task_071_query_asin_list_dependency_failure_returns_actionable_message', () => {
// 依赖失败/加载走 adapterGET /api/admin/query-asins + http.get + 解析,页面不内联。
const api = readSource('src/pages/asin/query-asin-api.ts')
assert.match(api, /\/api\/admin\/query-asins/)
assert.match(api, /http\.get/)
assert.match(api, /parseQueryAsinPage/)
assert.match(api, /toQueryAsinQuery/)
const model = readSource('src/pages/asin/query-asin-model.ts')
assert.equal(/axios|http\./.test(model), false, '查询 ASIN 列表解析保持纯逻辑')
})