479cc449d6
新增 duplicate-filter.ts(明细筛选 snake 查询) 与 parseDuplicateItemsPage/ fetchDuplicateItems(GET /duplicate-check-items)。 TDD: task-117.test.ts 8 用例先 RED 后 GREEN。
85 lines
3.6 KiB
TypeScript
85 lines
3.6 KiB
TypeScript
import test from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { readSource } from './helpers.ts'
|
||
import { parseDuplicateItemsPage } from '../src/pages/tasks/duplicate-model.ts'
|
||
import { toDuplicateItemsQuery } from '../src/pages/tasks/duplicate-filter.ts'
|
||
|
||
test('test_task_117_duplicate_items_normal_primary_path', () => {
|
||
// 正常主路径:明细筛选序列化与分页负载解析。
|
||
const query = toDuplicateItemsQuery(
|
||
{ view: 'monitor', asin: 'B0X', shopName: '店', country: 'DE', site: '', dateFrom: '2026-01-01', dateTo: '2026-01-31' },
|
||
2,
|
||
20,
|
||
)
|
||
assert.equal(query.view, 'monitor')
|
||
assert.equal(query.asin, 'B0X')
|
||
assert.equal(query.shop_name, '店')
|
||
assert.equal(query.country, 'DE')
|
||
assert.equal(query.date_from, '2026-01-01')
|
||
assert.equal(query.page, 2)
|
||
assert.equal(query.page_size, 20)
|
||
})
|
||
|
||
test('test_task_117_duplicate_items_normal_variant_input', () => {
|
||
// 正常变体:明细项含跨店出现记录解析。
|
||
const page = parseDuplicateItemsPage({
|
||
data: {
|
||
pending: false,
|
||
items: [
|
||
{ asin: 'B0ABC', shop_count: 2, record_count: 3, occurrences: [
|
||
{ asin: 'B0ABC', shop_name: 'A店', group_name: '华东', country_codes: ['DE'], country: 'DE', date: '2026-01-01', price: '9.9', brand: 'X' },
|
||
] },
|
||
],
|
||
total: 1,
|
||
page: 1,
|
||
page_size: 20,
|
||
},
|
||
})
|
||
assert.equal(page.items.length, 1)
|
||
const item = page.items[0]
|
||
assert.equal(item.asin, 'B0ABC')
|
||
assert.equal(item.shopCount, 2)
|
||
assert.equal(item.occurrences[0].shopName, 'A店')
|
||
assert.equal(item.occurrences[0].price, '9.9')
|
||
})
|
||
|
||
test('test_task_117_duplicate_items_repeated_is_idempotent', () => {
|
||
// 正常重复:查询序列化稳定。
|
||
const filter = { view: '', asin: 'A', shopName: '', country: '', site: '', dateFrom: '', dateTo: '' }
|
||
assert.deepEqual(toDuplicateItemsQuery(filter, 1, 20), toDuplicateItemsQuery(filter, 1, 20))
|
||
})
|
||
|
||
test('test_task_117_duplicate_items_boundary_empty_input', () => {
|
||
// 边界空值:空筛选回默认分页;pending 空态。
|
||
const page = parseDuplicateItemsPage({ data: { pending: true, items: [], total: 0, page: 1, page_size: 20 } })
|
||
assert.equal(page.pending, true)
|
||
assert.deepEqual(page.items, [])
|
||
})
|
||
|
||
test('test_task_117_duplicate_items_boundary_single_item', () => {
|
||
// 边界单元素:单明细项。
|
||
const page = parseDuplicateItemsPage({ data: { pending: false, items: [{ asin: 'S', shop_count: 1, record_count: 1, occurrences: [] }], total: 1, page: 1, page_size: 20 } })
|
||
assert.equal(page.items[0].asin, 'S')
|
||
assert.deepEqual(page.items[0].occurrences, [])
|
||
})
|
||
|
||
test('test_task_117_duplicate_items_boundary_limit_or_missing_field', () => {
|
||
// 边界上限/缺字段:页大小钳制到上限。
|
||
const query = toDuplicateItemsQuery({ view: '', asin: '', shopName: '', country: '', site: '', dateFrom: '', dateTo: '' }, 1, 999)
|
||
assert.equal(query.page_size, 100)
|
||
})
|
||
|
||
test('test_task_117_duplicate_items_invalid_input_rejected', () => {
|
||
// 异常输入:success=false 抛后端 message。
|
||
assert.throws(() => parseDuplicateItemsPage({ success: false, message: '暂无权限查看' }), /暂无权限/)
|
||
})
|
||
|
||
test('test_task_117_duplicate_items_dependency_failure_returns_actionable_message', () => {
|
||
// 依赖失败/加载走 adapter:GET /duplicate-check-items + 解析。
|
||
const api = readSource('src/pages/tasks/duplicate-api.ts')
|
||
assert.match(api, /\/duplicate-check-items/)
|
||
assert.match(api, /fetchDuplicateItems/)
|
||
const model = readSource('src/pages/tasks/duplicate-model.ts')
|
||
assert.equal(/axios|http\./.test(model), false, '明细解析保持纯逻辑')
|
||
})
|