3828c90b4c
POST /api/admin/product-category + PUT /product-category/{id} 保存适配
(名称必填/排序可选非负整数校验), 导出 URL(keyword), 8 个契约测试。
81 lines
3.7 KiB
TypeScript
81 lines
3.7 KiB
TypeScript
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')
|
||
})
|