import test from 'node:test' import assert from 'node:assert/strict' import { readSource } from './helpers.ts' import { createProductCategoryDraft, categoryDraftError, toCategorySaveRequest, } from '../src/pages/asin/product-category-editor-model.ts' import { buildProductCategoryExportUrl } from '../src/pages/asin/product-category-export.ts' test('test_task_079_product_category_editor_normal_primary_path', () => { // 正常主路径:名称/父级/排序/备注 → 保存请求(camel, 名称 trim)。 const draft = createProductCategoryDraft() draft.parentId = 3 draft.name = ' 厨房刀具 ' draft.sortOrder = '2' draft.description = ' 锋利 ' assert.equal(categoryDraftError(draft), null) assert.deepEqual(toCategorySaveRequest(draft), { parentId: 3, name: '厨房刀具', sortOrder: 2, description: '锋利', }) }) test('test_task_079_product_category_editor_normal_variant_input', () => { // 正常变体:顶级(无父级/无排序/无备注)仅提交名称。 const draft = { parentId: null, name: '收纳', sortOrder: '', description: '' } assert.equal(categoryDraftError(draft), null) assert.deepEqual(toCategorySaveRequest(draft), { name: '收纳' }) }) test('test_task_079_product_category_editor_normal_repeated_operation_is_idempotent', () => { // 正常重复:校验与序列化不改输入、结果稳定。 const draft = { parentId: 1, name: ' A ', sortOrder: '1', description: '' } assert.deepEqual(toCategorySaveRequest(draft), toCategorySaveRequest(draft)) assert.deepEqual(draft, { parentId: 1, name: ' A ', sortOrder: '1', description: '' }) }) test('test_task_079_product_category_editor_boundary_empty_input', () => { // 边界空值:空名称被拒。 const draft = { parentId: null, name: ' ', sortOrder: '', description: '' } assert.match(categoryDraftError(draft) || '', /名称/) }) test('test_task_079_product_category_editor_boundary_limit_or_missing_field', () => { // 边界上限/缺字段:排序为空省略;排序 0 保留;描述为空省略。 const noSort = toCategorySaveRequest({ parentId: null, name: 'X', sortOrder: '', description: '' }) assert.equal('sortOrder' in noSort, false) const zero = toCategorySaveRequest({ parentId: null, name: 'X', sortOrder: '0', description: '' }) assert.equal(zero.sortOrder, 0) assert.equal('description' in zero, false) }) test('test_task_079_product_category_editor_invalid_input_rejected', () => { // 异常输入:非法/负数排序被拒并给出可读错误。 assert.match(categoryDraftError({ parentId: null, name: 'X', sortOrder: 'abc', description: '' }) || '', /排序/) assert.match(categoryDraftError({ parentId: null, name: 'X', sortOrder: '-1', description: '' }) || '', /排序/) }) test('test_task_079_product_category_editor_dependency_failure_returns_actionable_message', () => { // 依赖失败/保存走 adapter:POST /product-category + PUT /product-category/{id}。 const api = readSource('src/pages/asin/product-category-editor-api.ts') assert.match(api, /product-category/) assert.match(api, /http\.post/) assert.match(api, /http\.put/) assert.match(api, /createProductCategory/) assert.match(api, /updateProductCategory/) const mod = readSource('src/pages/asin/product-category-editor-model.ts') assert.equal(/axios|http\./.test(mod), false, '类目编辑模型保持纯逻辑') }) test('test_task_079_product_category_export_normal_and_boundary', () => { // 正常/边界:导出 URL 带 keyword(编码)或不带参数。 const url = buildProductCategoryExportUrl(' 厨房 刀 ') assert.match(url, /\/product-categories\/export\?keyword=/) assert.match(url, /%20/) assert.equal(buildProductCategoryExportUrl(' '), '/api/admin/product-categories/export') })