- 路径式入口 `https://<域名>/redeem`(不带 #):主站是 HashRouter, 故在 App.tsx 里早于 isWorkerSite() 插入独立 BrowserRouter 分支, 主站与打手站路由均不受影响;Caddy 已有 try_files 兜底,无需改部署 - 页面按 7 种状态渲染:not_found / unpaid / cancelled / refunded / pending_certificate / redeemable / verified - not_found 保留用户输入的订单号,不清空 - pending_certificate 只给显式「刷新」,不做自动轮询(公开限流接口,避免空转) - verified 只展示后端已掩码的券码,绝不渲染明文 certNo - confirm 不假设成功:一律按返回的 status 重渲染 - 纯函数抽到 utils/redeem.ts(无 React/antd、无 @ 别名),可直接跑单测
68 lines
2.5 KiB
TypeScript
68 lines
2.5 KiB
TypeScript
import assert from 'node:assert/strict'
|
||
import test from 'node:test'
|
||
|
||
import {
|
||
formatRedeemAmount,
|
||
formatRedeemTime,
|
||
isRedeemPath,
|
||
resolveRedeemStatusView,
|
||
} from '../src/utils/redeem.ts'
|
||
import type { RedeemOrderStatus } from '../src/types/redeem.ts'
|
||
|
||
/** 故意构造后端未来可能新增的状态,验证未知状态不会崩 */
|
||
const FUTURE_STATUS = 'reviewing' as unknown as RedeemOrderStatus
|
||
|
||
test('isRedeemPath:只认路径式 /redeem,容忍结尾斜杠', () => {
|
||
assert.equal(isRedeemPath('/redeem'), true)
|
||
assert.equal(isRedeemPath('/redeem/'), true)
|
||
assert.equal(isRedeemPath('/redeem//'), true)
|
||
})
|
||
|
||
test('isRedeemPath:/redeemx、/、空串都不算兑换路径', () => {
|
||
assert.equal(isRedeemPath('/redeemx'), false)
|
||
assert.equal(isRedeemPath('/'), false)
|
||
assert.equal(isRedeemPath('/admin/redeem'), false)
|
||
assert.equal(isRedeemPath(''), false)
|
||
assert.equal(isRedeemPath(null), false)
|
||
})
|
||
|
||
test('formatRedeemAmount:分转元保留两位小数', () => {
|
||
assert.equal(formatRedeemAmount(1990), '¥19.90')
|
||
assert.equal(formatRedeemAmount(0), '¥0.00')
|
||
assert.equal(formatRedeemAmount(5), '¥0.05')
|
||
})
|
||
|
||
test('resolveRedeemStatusView:7 个状态各有标题与色调', () => {
|
||
assert.deepEqual(resolveRedeemStatusView('not_found'), {
|
||
tone: 'warning',
|
||
title: '未找到订单',
|
||
})
|
||
assert.deepEqual(resolveRedeemStatusView('unpaid'), { tone: 'warning', title: '订单未支付' })
|
||
assert.deepEqual(resolveRedeemStatusView('cancelled'), { tone: 'error', title: '订单已取消' })
|
||
assert.deepEqual(resolveRedeemStatusView('refunded'), { tone: 'error', title: '订单已退款' })
|
||
assert.deepEqual(resolveRedeemStatusView('pending_certificate'), {
|
||
tone: 'info',
|
||
title: '兑换券准备中',
|
||
})
|
||
assert.deepEqual(resolveRedeemStatusView('redeemable'), {
|
||
tone: 'success',
|
||
title: '可以兑换',
|
||
})
|
||
assert.deepEqual(resolveRedeemStatusView('verified'), { tone: 'success', title: '已兑换' })
|
||
})
|
||
|
||
test('resolveRedeemStatusView:未知状态回退为中性提示', () => {
|
||
assert.deepEqual(resolveRedeemStatusView(FUTURE_STATUS), {
|
||
tone: 'info',
|
||
title: '订单状态未知',
|
||
})
|
||
})
|
||
|
||
test('formatRedeemTime:空值或非法时间返回空串,合法时间格式化为 YYYY-MM-DD HH:mm', () => {
|
||
assert.equal(formatRedeemTime(''), '')
|
||
assert.equal(formatRedeemTime(null), '')
|
||
assert.equal(formatRedeemTime(' '), '')
|
||
assert.equal(formatRedeemTime('不是时间'), '')
|
||
assert.match(formatRedeemTime('2026-09-17T10:00:00'), /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/)
|
||
})
|