Files
order_site/apps/frontend/tests/redeem.test.ts
T
yml2213 8c33ff62ec feat(redeem): 固定兑换链接 /redeem(输入订单号 → 状态分流 → 兑换)
- 路径式入口 `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、无 @ 别名),可直接跑单测
2026-10-09 12:01:35 +08:00

68 lines
2.5 KiB
TypeScript
Raw 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 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}$/)
})