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, '商品类目模型保持纯逻辑') })