0a1e778ef6
新增 shop-credential-reveal.ts:复用 secret-mask 会话,店铺密码读取后默认 5 秒短时展示,读取失败/离开即清空,明文不写持久化/日志。 TDD: task-94.test.ts 8 用例先 RED 后 GREEN。
73 lines
3.5 KiB
TypeScript
73 lines
3.5 KiB
TypeScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readSource } from './helpers.ts'
|
|
import {
|
|
DEFAULT_SHOP_PASSWORD_REVEAL_MS,
|
|
beginShopPasswordReveal,
|
|
clearShopPasswordReveal,
|
|
expireShopPasswordReveal,
|
|
isShopPasswordRevealActive,
|
|
} from '../src/pages/shop/shop-credential-reveal.ts'
|
|
|
|
test('test_task_094_credential_reveal_normal_primary_path', () => {
|
|
// 正常主路径:主动揭示后短时(默认 5 秒)拿到明文,超时自动清空。
|
|
const session = beginShopPasswordReveal(clearShopPasswordReveal(), 5, 'plain-pw', 1000)
|
|
assert.equal(isShopPasswordRevealActive(session, 1000), true)
|
|
assert.equal(session.token, 'plain-pw')
|
|
const expired = expireShopPasswordReveal(session, 1000 + DEFAULT_SHOP_PASSWORD_REVEAL_MS + 1)
|
|
assert.equal(expired.token, undefined, '超时明文被清空')
|
|
assert.equal(isShopPasswordRevealActive(expired, 7000), false)
|
|
})
|
|
|
|
test('test_task_094_credential_reveal_normal_variant_input', () => {
|
|
// 正常变体:多个店铺各自揭示互不串扰,切换记录即替换明文。
|
|
const first = beginShopPasswordReveal(clearShopPasswordReveal(), 1, 'pw1', 0)
|
|
const second = beginShopPasswordReveal(first, 2, 'pw2', 0)
|
|
assert.equal(second.keyId, 2)
|
|
assert.equal(second.token, 'pw2')
|
|
})
|
|
|
|
test('test_task_094_credential_reveal_repeated_is_idempotent', () => {
|
|
// 正常重复:同一时刻重复揭示结果稳定。
|
|
const a = beginShopPasswordReveal(clearShopPasswordReveal(), 3, 'pw', 2000)
|
|
assert.deepEqual(beginShopPasswordReveal(a, 3, 'pw', 2000), a)
|
|
})
|
|
|
|
test('test_task_094_credential_reveal_boundary_empty_input', () => {
|
|
// 边界空值:清空后无活动揭示、无明文残留。
|
|
const session = clearShopPasswordReveal()
|
|
assert.equal(session.keyId, null)
|
|
assert.equal(isShopPasswordRevealActive(session, 0), false)
|
|
})
|
|
|
|
test('test_task_094_credential_reveal_boundary_single_item', () => {
|
|
// 边界单元素:单次揭示在窗口内有效,离开(调用清空)立即释放。
|
|
const session = beginShopPasswordReveal(clearShopPasswordReveal(), 9, 'pw9', 0, 0 + DEFAULT_SHOP_PASSWORD_REVEAL_MS)
|
|
assert.equal(isShopPasswordRevealActive(session, DEFAULT_SHOP_PASSWORD_REVEAL_MS - 1), true)
|
|
const gone = clearShopPasswordReveal()
|
|
assert.equal(isShopPasswordRevealActive(gone, 0), false)
|
|
})
|
|
|
|
test('test_task_094_credential_reveal_boundary_limit_or_missing_field', () => {
|
|
// 边界上限:跨记录的揭示不会在离开/失败后残留在其它状态里。
|
|
const session = beginShopPasswordReveal(clearShopPasswordReveal(), 4, 'x'.repeat(600), 0)
|
|
assert.equal(session.token!.length, 600)
|
|
assert.equal(clearShopPasswordReveal().token, undefined)
|
|
})
|
|
|
|
test('test_task_094_credential_reveal_invalid_input_rejected', () => {
|
|
// 异常输入:读取失败路径调用清空后不残留明文。
|
|
const session = beginShopPasswordReveal(clearShopPasswordReveal(), 7, 'pw7', 0)
|
|
const afterFailure = clearShopPasswordReveal()
|
|
assert.equal(isShopPasswordRevealActive(afterFailure, 0), false)
|
|
assert.equal(afterFailure.token, undefined, '失败后无明文残留')
|
|
assert.equal(isShopPasswordRevealActive(session, 0), true, '原会话不受影响(每次新会话)')
|
|
})
|
|
|
|
test('test_task_094_credential_reveal_dependency_failure_returns_actionable_message', () => {
|
|
// 依赖失败/可操作:揭示会话纯逻辑复用短时语义;不写持久化/日志。
|
|
const mod = readSource('src/pages/shop/shop-credential-reveal.ts')
|
|
assert.equal(/axios|http\.|vue|console\./.test(mod), false, '揭示会话保持纯逻辑')
|
|
assert.match(mod, /DEFAULT_SHOP_PASSWORD_REVEAL_MS/)
|
|
})
|