Files
huangzd1997 119095a57b task-83(店铺中心): 实现店铺密钥筛选和分页
新增 shop-keys-list-state.ts:密钥页本地关键词过滤(备注名/紫鸟账号)与分页
信息派生(页码钳制/首末/前后页)。Java 密钥接口无服务端筛选,搜索在已加载
当前页行上本地过滤,纯逻辑可测。

TDD: task-83.test.ts 8 用例先 RED 后 GREEN。
2026-09-05 16:36:19 +08:00

105 lines
4.5 KiB
TypeScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import {
filterShopKeyRows,
normalizeShopKeyFilter,
shopKeyFilterActive,
shopKeyPageInfo,
type ShopKeyPageInfo,
} from '../src/pages/shop/shop-keys-list-state.ts'
import type { ShopKeyItem } from '../src/pages/shop/shop-dto.ts'
function key(id: number, remarkName: string, ziniaoAccountName = ''): ShopKeyItem {
return { id, remarkName, ziniaoAccountName, ziniaoToken: '', ipWhitelistStatus: 'UNKNOWN' }
}
test('test_task_083_shop_key_filter_page_normal_primary_path', () => {
// 正常主路径:关键词过滤加载行 + 分页信息派生。
const rows = [key(1, '主店'), key(2, '副店'), key(3, 'blue_agent 备用')]
const filtered = filterShopKeyRows(rows, normalizeShopKeyFilter({ keyword: ' 副店 ' }))
assert.equal(filtered.length, 1)
assert.equal(filtered[0].id, 2)
const info: ShopKeyPageInfo = shopKeyPageInfo(2, 15, 30)
assert.equal(info.page, 2)
assert.equal(info.pageSize, 15)
assert.equal(info.totalPages, 2)
assert.equal(info.from, 16)
assert.equal(info.to, 30)
assert.equal(info.hasPrev, true)
assert.equal(info.hasNext, false)
})
test('test_task_083_shop_key_filter_page_normal_variant_input', () => {
// 正常变体:关键词可命中紫鸟账号名,大小写不敏感。
const rows = [key(1, 'A店', 'BlueAgent'), key(2, 'B店', 'red')]
const filtered = filterShopKeyRows(rows, { keyword: 'blue' })
assert.equal(filtered.length, 1)
assert.equal(filtered[0].id, 1)
assert.equal(shopKeyFilterActive({ keyword: 'blue' }), true)
})
test('test_task_083_shop_key_filter_page_normal_repeated_is_idempotent', () => {
// 正常重复:过滤不修改原列表、输入状态稳定。
const rows = [key(1, '主店'), key(2, '副店')]
const filter = { keyword: ' 主 店 ' }
const first = filterShopKeyRows(rows, normalizeShopKeyFilter(filter))
const second = filterShopKeyRows(rows, normalizeShopKeyFilter(filter))
assert.deepEqual(first, second)
assert.equal(filter.keyword, ' 主 店 ', '不改调用方状态')
assert.equal(rows.length, 2, '不改原列表')
const info = shopKeyPageInfo(2, 15, 45)
assert.deepEqual(info, shopKeyPageInfo(2, 15, 45))
})
test('test_task_083_shop_key_filter_page_boundary_empty_input', () => {
// 边界空值:空关键词不过滤(返回全部加载行);空状态分页信息不崩溃。
const rows = [key(1, 'A'), key(2, 'B')]
const all = filterShopKeyRows(rows, normalizeShopKeyFilter({}))
assert.equal(all.length, 2)
const info = shopKeyPageInfo(1, 15, 0)
assert.equal(info.totalPages, 1)
assert.equal(info.page, 1)
assert.equal(info.from, 0)
assert.equal(info.to, 0)
assert.equal(info.hasPrev, false)
assert.equal(info.hasNext, false)
})
test('test_task_083_shop_key_filter_page_boundary_single_item', () => {
// 边界单元素:单行列表与单页总数。
const rows = [key(1, '唯一店')]
const filtered = filterShopKeyRows(rows, { keyword: '唯一' })
assert.equal(filtered.length, 1)
const info = shopKeyPageInfo(1, 15, 1)
assert.equal(info.totalPages, 1)
assert.equal(info.to, 1)
})
test('test_task_083_shop_key_filter_page_boundary_limit_or_missing_field', () => {
// 边界上限/缺字段:页码/页大小钳制;页大小越界归上限;关键字空白视为无筛选。
const info = shopKeyPageInfo(0, 999, 50)
assert.equal(info.page, 1)
assert.equal(info.pageSize, 100)
assert.equal(info.totalPages, 1)
const late = shopKeyPageInfo(99, 15, 30)
assert.equal(late.page, 2, '请求页码超过末页应钳到末页')
assert.equal(filterShopKeyRows([key(1, 'A')], normalizeShopKeyFilter({ keyword: ' ' })).length, 1)
})
test('test_task_083_shop_key_filter_page_invalid_input_rejected', () => {
// 异常输入:非数字/NaN 页码回默认;非字符串关键词按无筛选处理。
const info = shopKeyPageInfo(Number.NaN, Number.NaN, 10)
assert.equal(info.page, 1)
assert.equal(info.pageSize, 15)
assert.equal(shopKeyFilterActive(normalizeShopKeyFilter({ keyword: 3 as never })), false)
})
test('test_task_083_shop_key_filter_page_dependency_failure_returns_actionable_message', () => {
// 依赖失败/可操作:列表状态为纯逻辑、无框架/http;复用 DTO 常量与类型。
const mod = readSource('src/pages/shop/shop-keys-list-state.ts')
assert.equal(/axios|http\.|vue/.test(mod), false, '列表状态保持纯逻辑')
assert.match(mod, /SHOP_PAGE_DEFAULT_SIZE/)
assert.match(mod, /ShopKeyItem/)
})