Files
huangzd1997 c1d6ce6d20 task-77(ASIN 数据中心): 实现最低价 ASIN 详情编辑抽屉
抽屉副标题/5 国家草稿(ASIN+最低价)与变更差异(清空 ASIN→删除, 仅清价→
update)纯逻辑, 保存走 PUT/DELETE /api/admin/skip-price-asins/{id}/countries/{country},
10 个契约测试。
2026-09-05 16:14:22 +08:00

115 lines
5.3 KiB
TypeScript
Raw Permalink 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 {
skipPriceDetailSubtitle,
skipPriceCountryDraftsOf,
diffSkipPriceCountryChanges,
normalizeSkipPriceCellPrice,
type SkipPriceCountryDraft,
} from '../src/pages/asin/skip-price-detail-model.ts'
import { toSkipPriceItem } from '../src/pages/asin/skip-price-model.ts'
test('test_task_077_skip_price_detail_subtitle_normal_primary_path', () => {
// 正常主路径:抽屉副标题 = 分组 / 店铺名。
const item = toSkipPriceItem({ id: 1, groupName: '华东组', shopName: 'BlueWave' })!
assert.equal(skipPriceDetailSubtitle(item), '华东组 / BlueWave')
})
test('test_task_077_skip_price_detail_subtitle_normal_variant_input', () => {
// 正常变体:无分组时仅店铺名。
const item = toSkipPriceItem({ id: 2, shopName: 'RedSun' })!
assert.equal(skipPriceDetailSubtitle(item), 'RedSun')
})
test('test_task_077_skip_price_detail_drafts_normal_primary', () => {
// 正常主路径:由行生成 5 国家草稿(ASIN + 最低价输入初值)。
const item = toSkipPriceItem({ id: 3, shopName: 'S', asinDe: 'B0DE1', minimumPriceDe: 12.5, asinEs: 'B0ES1' })!
const drafts = skipPriceCountryDraftsOf(item)
assert.equal(drafts.length, 5)
const de = drafts[0]
assert.equal(de.code, 'DE')
assert.equal(de.label, '德国')
assert.equal(de.asin, 'B0DE1')
assert.equal(de.price, '12.5')
assert.equal(drafts[4].code, 'ES')
assert.equal(drafts[4].asin, 'B0ES1')
assert.equal(drafts[1].price, '')
})
test('test_task_077_skip_price_detail_diff_normal_no_change', () => {
// 正常重复:ASIN 与最低价均未变(大小写/空白/数字等价归一) → 无变更。
const item = toSkipPriceItem({ id: 4, shopName: 'S', asinDe: 'B0DE1', minimumPriceDe: 12 })!
const changes = diffSkipPriceCountryChanges(item, [
{ code: 'DE', asin: ' b0de1 ', price: '12' },
{ code: 'UK', asin: '', price: '' },
])
assert.deepEqual(changes, [])
})
test('test_task_077_skip_price_detail_diff_boundary_empty_asin_means_delete', () => {
// 边界空值:当前有 ASIN 但草稿清空 → 删除该国家。
const item = toSkipPriceItem({ id: 5, shopName: 'S', asinUk: 'B0UK1', minimumPriceUk: 8, asinDe: 'B0DE1' })!
const changes = diffSkipPriceCountryChanges(item, [
{ code: 'UK', asin: '', price: '' },
{ code: 'DE', asin: 'B0DE1', price: '' },
])
assert.equal(changes.length, 1)
assert.equal(changes[0].kind, 'delete')
assert.equal(changes[0].code, 'UK')
})
test('test_task_077_skip_price_detail_diff_normal_update_asin_and_price', () => {
// 正常主路径:ASIN 改变非空 → update,ASIN 大写、最低价随行。
const item = toSkipPriceItem({ id: 6, shopName: 'S', asinFr: 'B0OLD', minimumPriceFr: 5 })!
const changes = diffSkipPriceCountryChanges(item, [{ code: 'FR', asin: ' b0new1 ', price: ' 18.5 ' }])
assert.equal(changes.length, 1)
assert.equal(changes[0].kind, 'update')
assert.equal(changes[0].asin, 'B0NEW1')
assert.equal(changes[0].minimumPrice, 18.5)
})
test('test_task_077_skip_price_detail_diff_boundary_price_cleared_keeps_asin', () => {
// 边界:ASIN 不变仅清空最低价 → update(保留 ASIN, 最低价置空)。
const item = toSkipPriceItem({ id: 7, shopName: 'S', asinEs: 'B0ES1', minimumPriceEs: 9.9 })!
const changes = diffSkipPriceCountryChanges(item, [{ code: 'ES', asin: 'B0ES1', price: '' }])
assert.equal(changes.length, 1)
assert.equal(changes[0].kind, 'update')
assert.equal(changes[0].asin, 'B0ES1')
assert.equal(changes[0].minimumPrice, null)
})
test('test_task_077_skip_price_detail_diff_invalid_input_rejected', () => {
// 异常输入:未知国家码草稿忽略;缺失草稿不产生变更;非法价格归空。
const item = toSkipPriceItem({ id: 8, shopName: 'S', asinDe: 'B0DE1', minimumPriceDe: 1 })!
const changes = diffSkipPriceCountryChanges(item, [
{ code: 'XX', asin: 'abc', price: '' },
{ code: 'DE', asin: 'B0DE1', price: '1' },
])
assert.deepEqual(changes, [])
assert.equal(normalizeSkipPriceCellPrice(''), null)
assert.equal(normalizeSkipPriceCellPrice(' 12.5 '), 12.5)
assert.equal(normalizeSkipPriceCellPrice('abc'), null)
assert.equal(normalizeSkipPriceCellPrice('-1'), null)
})
test('test_task_077_skip_price_detail_dependency_failure_returns_actionable_message', () => {
// 依赖失败/保存走 adapterPUT/DELETE /skip-price-asins/{id}/countries/{country}。
const api = readSource('src/pages/asin/skip-price-detail-api.ts')
assert.match(api, /skip-price-asins/)
assert.match(api, /countries/)
assert.match(api, /http\.put/)
assert.match(api, /http\.delete/)
assert.match(api, /updateSkipPriceCountry|saveSkipPriceCountry/)
assert.match(api, /deleteSkipPriceCountry/)
const mod = readSource('src/pages/asin/skip-price-detail-model.ts')
assert.equal(/axios|http\./.test(mod), false, '最低价 ASIN 抽屉模型保持纯逻辑')
})
test('test_task_077_skip_price_detail_diff_boundary_no_drafts', () => {
// 边界:空草稿列表不产生变更;skip-price 行缺失字段安全。
const item = toSkipPriceItem({ id: 9, shopName: 'S' })!
assert.deepEqual(diffSkipPriceCountryChanges(item, [] as SkipPriceCountryDraft[]), [])
assert.deepEqual(diffSkipPriceCountryChanges(item, null as unknown as SkipPriceCountryDraft[]), [])
})