feat(finance): add customer recharge account
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import test from 'node:test'
|
||||
|
||||
const apiSource = readFileSync(new URL('../api/account.ts', import.meta.url), 'utf8')
|
||||
const viewSource = readFileSync(new URL('./FinanceAccountView.vue', import.meta.url), 'utf8')
|
||||
const routesSource = readFileSync(new URL('../routes.ts', import.meta.url), 'utf8')
|
||||
const permissionsSource = readFileSync(new URL('../../tenant-management/contracts.ts', import.meta.url), 'utf8')
|
||||
|
||||
test('uses only authenticated client finance account endpoints without customer scope', () => {
|
||||
for (const path of ['/client/finance/v1/account', '/client/finance/v1/account/ledger', '/client/finance/v1/recharge-requests', '/client/finance/v1/recharge-channels']) {
|
||||
assert.match(apiSource, new RegExp(path.replaceAll('/', '\\/')))
|
||||
}
|
||||
assert.match(apiSource, /headers: \{ 'Idempotency-Key': idempotencyKey \}/)
|
||||
assert.match(apiSource, /formData\.append\('amount', amount\)/)
|
||||
assert.match(apiSource, /formData\.append\('paymentMethod', paymentMethod\)/)
|
||||
assert.match(apiSource, /formData\.append\('file', file, file\.name\)/)
|
||||
assert.doesNotMatch(apiSource, /customerId|tenantId|mock|fallback/i)
|
||||
})
|
||||
|
||||
test('activates the account route and maps read and recharge permissions independently', () => {
|
||||
assert.match(routesSource, /path: 'finance\/account'[\s\S]*FinanceAccountView\.vue[\s\S]*release: 'active'[\s\S]*permission: 'merchant:finance:account:view'/)
|
||||
assert.match(permissionsSource, /'merchant:finance:account:view': \['merchant:finance:account:view'\]/)
|
||||
assert.match(permissionsSource, /'merchant:finance:recharge:create': \['merchant:finance:recharge:create'\]/)
|
||||
assert.match(viewSource, /auth\.hasPermission\('merchant:finance:recharge:create'\)/)
|
||||
assert.match(viewSource, /<el-button v-if="canRecharge"/)
|
||||
})
|
||||
|
||||
test('renders server balances, ledger and recharge states without internal identifiers', () => {
|
||||
for (const field of ['actualBalance', 'frozenBalance', 'availableBalance']) assert.match(viewSource, new RegExp(`account\\?\\.${field}`))
|
||||
assert.match(viewSource, /row-key="businessNo"/)
|
||||
assert.match(viewSource, /row-key="requestNo"/)
|
||||
assert.match(viewSource, /empty-text="暂无资金流水"/)
|
||||
assert.match(viewSource, /empty-text="暂无充值申请"/)
|
||||
assert.match(viewSource, /account-state--error/)
|
||||
assert.match(viewSource, /v-loading="pageLoading"/)
|
||||
assert.doesNotMatch(viewSource, /requestId|ledgerId|customerId|tenantId/)
|
||||
})
|
||||
|
||||
test('matches the frozen recharge workflow and preserves an idempotency key for failed retries', () => {
|
||||
assert.match(viewSource, /title="账户充值" width="760px"/)
|
||||
for (const amount of ['50.00', '100.00', '200.00', '500.00']) assert.match(viewSource, new RegExp(amount.replace('.', '\\.')))
|
||||
assert.match(viewSource, /\['WECHAT', 'ALIPAY'\]/)
|
||||
assert.match(viewSource, /selectedChannel\.value\?\.enabled && selectedChannel\.value\.qrCodeUrl/)
|
||||
assert.match(viewSource, /accept="\.jpg,\.jpeg,\.png,image\/jpeg,image\/png"/)
|
||||
assert.match(viewSource, /if \(!pendingIdempotencyKey\)[\s\S]*globalThis\.crypto\?\.randomUUID\?\.\(\)/)
|
||||
assert.match(viewSource, /pendingIdempotencyKey = ''[\s\S]*rechargeVisible\.value = false/)
|
||||
assert.match(viewSource, /:disabled="!canSubmit"/)
|
||||
assert.match(viewSource, /await loadAccountData\(\)/)
|
||||
assert.doesNotMatch(viewSource, /payment SDK|支付成功|模拟成功/)
|
||||
})
|
||||
Reference in New Issue
Block a user