126 lines
4.8 KiB
TypeScript
126 lines
4.8 KiB
TypeScript
import test from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { readSource } from './helpers.ts'
|
||
import {
|
||
toProductCategoryNode,
|
||
parseProductCategoryList,
|
||
parseProductCategorySearchPage,
|
||
} from '../src/pages/asin/product-category-model.ts'
|
||
|
||
test('test_task_078_product_category_tree_normal_primary_path', () => {
|
||
// 正常主路径:Java ProductCategoryListVo(tree 嵌套+childCount/path/level) 解析为节点树。
|
||
const { tree } = parseProductCategoryList({
|
||
success: true,
|
||
data: {
|
||
tree: [
|
||
{
|
||
id: 1,
|
||
parentId: null,
|
||
name: '厨房',
|
||
categoryKey: 'kitchen',
|
||
sortOrder: 1,
|
||
description: '厨房类目',
|
||
isBuiltin: true,
|
||
childCount: 1,
|
||
level: 1,
|
||
path: '厨房',
|
||
children: [
|
||
{ id: 2, parentId: 1, name: '刀具', sortOrder: 1, isBuiltin: false, childCount: 0, level: 2, path: '厨房 / 刀具' },
|
||
],
|
||
},
|
||
],
|
||
},
|
||
})
|
||
assert.equal(tree.length, 1)
|
||
const root = tree[0]
|
||
assert.equal(root.name, '厨房')
|
||
assert.equal(root.isBuiltin, true)
|
||
assert.equal(root.path, '厨房')
|
||
assert.equal(root.childCount, 1)
|
||
assert.equal(root.children.length, 1)
|
||
assert.equal(root.children[0].name, '刀具')
|
||
assert.equal(root.children[0].path, '厨房 / 刀具')
|
||
})
|
||
|
||
test('test_task_078_product_category_tree_normal_variant_input', () => {
|
||
// 正常变体:无父级/无内置/扁平 items 一并归一。
|
||
const { tree, items } = parseProductCategoryList({
|
||
data: {
|
||
tree: [{ id: 3, name: '收纳', sortOrder: 2, isBuiltin: false, childCount: 0, level: 1, path: '收纳' }],
|
||
items: [{ id: 3, name: '收纳', path: '收纳' }],
|
||
},
|
||
})
|
||
assert.equal(tree[0].parentId, null)
|
||
assert.equal(tree[0].isBuiltin, false)
|
||
assert.equal(items.length, 1)
|
||
})
|
||
|
||
test('test_task_078_product_category_tree_normal_repeated_operation_is_idempotent', () => {
|
||
// 正常重复:解析不改输入、结果稳定。
|
||
const payload = { data: { tree: [{ id: 5, name: 'X', children: [] }] } }
|
||
assert.deepEqual(parseProductCategoryList(payload), parseProductCategoryList(payload))
|
||
})
|
||
|
||
test('test_task_078_product_category_tree_boundary_empty_input', () => {
|
||
// 边界空值:空负载回空树与空 items,不崩溃。
|
||
const { tree, items } = parseProductCategoryList({})
|
||
assert.deepEqual(tree, [])
|
||
assert.deepEqual(items, [])
|
||
})
|
||
|
||
test('test_task_078_product_category_tree_boundary_single_item', () => {
|
||
// 边界单元素:缺 id 的节点被过滤;children 缺省为空数组。
|
||
const { tree } = parseProductCategoryList({
|
||
data: { tree: [{ id: 6, name: 'A' }, { name: 'no-id' }] },
|
||
})
|
||
assert.equal(tree.length, 1)
|
||
assert.equal(tree[0].id, 6)
|
||
assert.deepEqual(tree[0].children, [])
|
||
})
|
||
|
||
test('test_task_078_product_category_search_normal_page_result', () => {
|
||
// 正常主路径:search 分页结果(items/total/page/pageSize/hasMore)解析。
|
||
const page = parseProductCategorySearchPage({
|
||
success: true,
|
||
data: {
|
||
items: [{ id: 10, name: '刀具', level: 2, path: '厨房 / 刀具' }],
|
||
total: 21,
|
||
page: 1,
|
||
pageSize: 20,
|
||
hasMore: true,
|
||
},
|
||
})
|
||
assert.equal(page.items.length, 1)
|
||
assert.equal(page.items[0].path, '厨房 / 刀具')
|
||
assert.equal(page.total, 21)
|
||
assert.equal(page.hasMore, true)
|
||
})
|
||
|
||
test('test_task_078_product_category_search_boundary_empty_and_default', () => {
|
||
// 边界空值/缺字段:空负载 items 空、hasMore false、页大小回默认 20。
|
||
const page = parseProductCategorySearchPage({})
|
||
assert.deepEqual(page.items, [])
|
||
assert.equal(page.total, 0)
|
||
assert.equal(page.hasMore, false)
|
||
assert.equal(page.pageSize, 10)
|
||
})
|
||
|
||
test('test_task_078_product_category_invalid_input_rejected', () => {
|
||
// 异常输入:success=false 抛后端 message;垃圾/非对象节点过滤。
|
||
assert.throws(() => parseProductCategoryList({ success: false, message: '无权访问类目' }), /无权/)
|
||
assert.throws(() => parseProductCategorySearchPage({ success: false, message: '无权访问类目' }), /无权/)
|
||
assert.equal(toProductCategoryNode('garbage'), null)
|
||
assert.equal(toProductCategoryNode({ name: 'no id' }), null)
|
||
})
|
||
|
||
test('test_task_078_product_category_dependency_failure_returns_actionable_message', () => {
|
||
// 依赖失败/加载走 adapter:GET /product-categories(+keyword) 与 /product-categories/search。
|
||
const api = readSource('src/pages/asin/product-category-api.ts')
|
||
assert.match(api, /product-categories/)
|
||
assert.match(api, /http\.get/)
|
||
assert.match(api, /fetchProductCategoryTree|productCategoryTree/)
|
||
assert.match(api, /searchProductCategories|product-categories\/search/)
|
||
const mod = readSource('src/pages/asin/product-category-model.ts')
|
||
assert.equal(/axios|http\./.test(mod), false, '商品类目模型保持纯逻辑')
|
||
})
|