Files
huangzd1997 9b21e1f22e task-118(任务与重复分析中心): 实现重复检查详情抽屉
duplicate-model.ts 增加 DuplicateDetail 解析与详情分页负载解析,duplicate-api.ts
增加 fetchDuplicateDetail(GET /duplicate-check-detail)。

TDD: task-118.test.ts 8 用例先 RED 后 GREEN。
2026-09-05 17:26:54 +08:00

82 lines
3.5 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 { parseDuplicateDetail, parseDuplicateDetailPage } from '../src/pages/tasks/duplicate-model.ts'
test('test_task_118_duplicate_detail_normal_primary_path', () => {
// 正常主路径:详情卡(snake)解析为类型化详情。
const detail = parseDuplicateDetail({
asin: 'B0ABC',
shop_count: 3,
record_count: 4,
shop_names: ['A店', 'B店', 'C店'],
brand: 'X',
first_date: '2026-01-01',
occurrences: [
{ asin: 'B0ABC', shop_name: 'A店', country: 'DE', date: '2026-01-01', price: '9.9', brand: 'X' },
{ asin: 'B0ABC', shop_name: 'B店', country: 'DE', date: '2026-01-02', price: '10.1', brand: 'X' },
],
})
assert.equal(detail.asin, 'B0ABC')
assert.equal(detail.shopCount, 3)
assert.deepEqual(detail.shopNames, ['A店', 'B店', 'C店'])
assert.equal(detail.brand, 'X')
assert.equal(detail.firstDate, '2026-01-01')
assert.equal(detail.occurrences.length, 2)
})
test('test_task_118_duplicate_detail_normal_variant_input', () => {
// 正常变体:详情分页负载解析。
const page = parseDuplicateDetailPage({
data: { pending: false, items: [{ asin: 'B0X', shop_count: 2, record_count: 2, shop_names: ['A'], occurrences: [] }], total: 1, page: 1, page_size: 6 },
})
assert.equal(page.items.length, 1)
assert.equal(page.items[0].asin, 'B0X')
assert.equal(page.pageSize, 6)
})
test('test_task_118_duplicate_detail_repeated_is_idempotent', () => {
// 正常重复:解析稳定、不改输入。
const payload = { data: { items: [{ asin: 'A', shop_count: 1, record_count: 1, shop_names: [], occurrences: [] }], total: 1, page: 1, page_size: 6 } }
assert.deepEqual(parseDuplicateDetailPage(payload), parseDuplicateDetailPage(payload))
})
test('test_task_118_duplicate_detail_boundary_empty_input', () => {
// 边界空值:pending 空详情列表。
const page = parseDuplicateDetailPage({ data: { pending: true, items: [], total: 0, page: 1, page_size: 6 } })
assert.equal(page.pending, true)
assert.deepEqual(page.items, [])
})
test('test_task_118_duplicate_detail_boundary_single_item', () => {
// 边界单元素:单详情卡无店名列表。
const detail = parseDuplicateDetail({ asin: 'S', shop_count: 1, record_count: 1, occurrences: [] })
assert.ok(detail)
assert.deepEqual(detail.shopNames, [])
assert.equal(detail.brand, '')
})
test('test_task_118_duplicate_detail_boundary_limit_or_missing_field', () => {
// 边界上限/缺字段:缺字段回默认。
const detail = parseDuplicateDetail({ asin: 'Z' })
assert.ok(detail)
assert.equal(detail.shopCount, 0)
assert.equal(detail.firstDate, '')
})
test('test_task_118_duplicate_detail_invalid_input_rejected', () => {
// 异常输入:缺 asin 详情视为无效;success=false 抛后端 message。
assert.equal(parseDuplicateDetail('garbage'), null)
assert.equal(parseDuplicateDetail({ shop_count: 2 }), null)
assert.throws(() => parseDuplicateDetailPage({ success: false, message: '无权查看详情' }), /无权查看/)
})
test('test_task_118_duplicate_detail_dependency_failure_returns_actionable_message', () => {
// 依赖失败/加载走 adapterGET /duplicate-check-detail。
const api = readSource('src/pages/tasks/duplicate-api.ts')
assert.match(api, /\/duplicate-check-detail/)
assert.match(api, /fetchDuplicateDetail/)
const model = readSource('src/pages/tasks/duplicate-model.ts')
assert.equal(/axios|http\./.test(model), false, '详情解析保持纯逻辑')
})