342 lines
8.4 KiB
TypeScript
342 lines
8.4 KiB
TypeScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
|
|
import {
|
|
AFFILIATE_DASH_BIND_REFRESH_FRESH_MS,
|
|
AFFILIATE_DASH_ORDER_SYNC_FRESH_MS,
|
|
canReuseAffiliateDashBindSnapshot,
|
|
isAffiliateDashBindSnapshotStale,
|
|
isAffiliateDashSnapshotFresh,
|
|
isRockAffiliateDashSku,
|
|
shouldRefuseRockRebind,
|
|
shouldRefreshAffiliateDashBindStateForSnapshot,
|
|
} from './kuaishou-cloud-claim-service.js'
|
|
|
|
test('isAffiliateDashBindSnapshotStale detects bind uuid that belongs to old uid', () => {
|
|
assert.equal(
|
|
isAffiliateDashBindSnapshotStale(
|
|
{
|
|
bindUuid: 'bind-old',
|
|
bindUrl: 'https://dash.example/bind-old',
|
|
expectedGameAccount: '111',
|
|
gameAccount: '111',
|
|
},
|
|
'222',
|
|
),
|
|
true,
|
|
)
|
|
})
|
|
|
|
test('isAffiliateDashBindSnapshotStale treats unknown bind uid as stale', () => {
|
|
assert.equal(
|
|
isAffiliateDashBindSnapshotStale(
|
|
{
|
|
bindUuid: 'bind-unknown',
|
|
bindUrl: 'https://dash.example/bind-unknown',
|
|
},
|
|
'222',
|
|
),
|
|
true,
|
|
)
|
|
})
|
|
|
|
test('isAffiliateDashBindSnapshotStale keeps current uid bind snapshot', () => {
|
|
assert.equal(
|
|
isAffiliateDashBindSnapshotStale(
|
|
{
|
|
bindUuid: 'bind-current',
|
|
bindUrl: 'https://dash.example/bind-current',
|
|
expectedGameAccount: '222',
|
|
gameAccount: '222',
|
|
},
|
|
'222',
|
|
),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('canReuseAffiliateDashBindSnapshot reuses pending current uid bind', () => {
|
|
assert.equal(
|
|
canReuseAffiliateDashBindSnapshot(
|
|
{
|
|
bindUuid: 'bind-current',
|
|
bindUrl: 'https://dash.example/bind-current',
|
|
expectedGameAccount: '222',
|
|
gameAccount: '222',
|
|
bound: false,
|
|
bindMismatch: false,
|
|
},
|
|
'222',
|
|
),
|
|
true,
|
|
)
|
|
})
|
|
|
|
test('canReuseAffiliateDashBindSnapshot refuses old uid bind', () => {
|
|
assert.equal(
|
|
canReuseAffiliateDashBindSnapshot(
|
|
{
|
|
bindUuid: 'bind-old',
|
|
bindUrl: 'https://dash.example/bind-old',
|
|
expectedGameAccount: '111',
|
|
gameAccount: '111',
|
|
bound: false,
|
|
bindMismatch: false,
|
|
},
|
|
'222',
|
|
),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('canReuseAffiliateDashBindSnapshot refuses bound snapshot without bound account', () => {
|
|
assert.equal(
|
|
canReuseAffiliateDashBindSnapshot(
|
|
{
|
|
bindUuid: 'bind-current',
|
|
bindUrl: 'https://dash.example/bind-current',
|
|
expectedGameAccount: '222',
|
|
gameAccount: '222',
|
|
bound: true,
|
|
boundAccount: '',
|
|
bindMismatch: false,
|
|
},
|
|
'222',
|
|
),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('canReuseAffiliateDashBindSnapshot reuses verified matching bound account', () => {
|
|
assert.equal(
|
|
canReuseAffiliateDashBindSnapshot(
|
|
{
|
|
bindUuid: 'bind-current',
|
|
bindUrl: 'https://dash.example/bind-current',
|
|
expectedGameAccount: '222',
|
|
gameAccount: '222',
|
|
bound: true,
|
|
boundAccount: '222',
|
|
bindMismatch: false,
|
|
},
|
|
'222',
|
|
),
|
|
true,
|
|
)
|
|
})
|
|
|
|
test('rock rebind is refused after mismatch or after a successful bind changes uid', () => {
|
|
assert.equal(isRockAffiliateDashSku('rock_black_tshirt'), true)
|
|
assert.equal(isRockAffiliateDashSku('top_black_elite_trainer'), false)
|
|
assert.equal(
|
|
shouldRefuseRockRebind({
|
|
sku: 'rock_black_tshirt',
|
|
bindUuid: 'bind-1',
|
|
bindMismatch: true,
|
|
}),
|
|
true,
|
|
)
|
|
// 方案 B:买家改回扫码真实账号时放行自愈,改第三个账号时拒绝
|
|
assert.equal(
|
|
shouldRefuseRockRebind(
|
|
{
|
|
sku: 'rock_black_tshirt',
|
|
bindUuid: 'bind-1',
|
|
boundAccount: '3454648872',
|
|
bindMismatch: true,
|
|
},
|
|
'3454648872',
|
|
),
|
|
false,
|
|
)
|
|
assert.equal(
|
|
shouldRefuseRockRebind(
|
|
{
|
|
sku: 'rock_black_tshirt',
|
|
bindUuid: 'bind-1',
|
|
boundAccount: '3454648872',
|
|
bindMismatch: true,
|
|
},
|
|
'9999999999',
|
|
),
|
|
true,
|
|
)
|
|
assert.equal(
|
|
shouldRefuseRockRebind(
|
|
{
|
|
sku: 'rock_black_tshirt',
|
|
bindUuid: 'bind-1',
|
|
bound: true,
|
|
boundAccount: '111',
|
|
expectedGameAccount: '111',
|
|
},
|
|
'222',
|
|
),
|
|
true,
|
|
)
|
|
assert.equal(
|
|
shouldRefuseRockRebind(
|
|
{
|
|
sku: 'rock_black_tshirt',
|
|
bindUuid: 'bind-1',
|
|
bound: false,
|
|
bindMismatch: false,
|
|
expectedGameAccount: '111',
|
|
},
|
|
'222',
|
|
),
|
|
false,
|
|
)
|
|
assert.equal(
|
|
shouldRefuseRockRebind(
|
|
{
|
|
sku: 'skin_other',
|
|
bindUuid: 'bind-1',
|
|
bindMismatch: true,
|
|
},
|
|
'222',
|
|
),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('canReuseAffiliateDashBindSnapshot refuses mismatched bound account', () => {
|
|
assert.equal(
|
|
canReuseAffiliateDashBindSnapshot(
|
|
{
|
|
bindUuid: 'bind-current',
|
|
bindUrl: 'https://dash.example/bind-current',
|
|
expectedGameAccount: '222',
|
|
gameAccount: '222',
|
|
bound: true,
|
|
boundAccount: '333',
|
|
bindMismatch: false,
|
|
},
|
|
'222',
|
|
),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('isAffiliateDashSnapshotFresh treats missing or future timestamps as stale', () => {
|
|
const now = Date.parse('2026-10-01T06:00:00.000Z')
|
|
assert.equal(isAffiliateDashSnapshotFresh(null, AFFILIATE_DASH_ORDER_SYNC_FRESH_MS, now), false)
|
|
assert.equal(isAffiliateDashSnapshotFresh('', AFFILIATE_DASH_ORDER_SYNC_FRESH_MS, now), false)
|
|
assert.equal(
|
|
isAffiliateDashSnapshotFresh('not-a-date', AFFILIATE_DASH_ORDER_SYNC_FRESH_MS, now),
|
|
false,
|
|
)
|
|
assert.equal(
|
|
isAffiliateDashSnapshotFresh(
|
|
'2026-10-01T06:00:01.000Z',
|
|
AFFILIATE_DASH_ORDER_SYNC_FRESH_MS,
|
|
now,
|
|
),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('order snapshot stays fresh for 45s and bind snapshot only for 15s', () => {
|
|
const now = Date.parse('2026-10-01T06:00:45.000Z')
|
|
assert.equal(
|
|
isAffiliateDashSnapshotFresh(
|
|
'2026-10-01T06:00:00.000Z',
|
|
AFFILIATE_DASH_ORDER_SYNC_FRESH_MS,
|
|
now,
|
|
),
|
|
false,
|
|
)
|
|
assert.equal(
|
|
isAffiliateDashSnapshotFresh(
|
|
'2026-10-01T06:00:01.000Z',
|
|
AFFILIATE_DASH_ORDER_SYNC_FRESH_MS,
|
|
now,
|
|
),
|
|
true,
|
|
)
|
|
assert.equal(
|
|
isAffiliateDashSnapshotFresh(
|
|
'2026-10-01T06:00:30.000Z',
|
|
AFFILIATE_DASH_BIND_REFRESH_FRESH_MS,
|
|
now,
|
|
),
|
|
false,
|
|
)
|
|
assert.equal(
|
|
isAffiliateDashSnapshotFresh(
|
|
'2026-10-01T06:00:31.000Z',
|
|
AFFILIATE_DASH_BIND_REFRESH_FRESH_MS,
|
|
now,
|
|
),
|
|
true,
|
|
)
|
|
})
|
|
|
|
test('claim detail skips affiliate-dash sync while the snapshot is fresh', async () => {
|
|
const { readFile } = await import('node:fs/promises')
|
|
const src = await readFile(new URL('./kuaishou-cloud-claim-service.ts', import.meta.url), 'utf8')
|
|
const detail = src.slice(
|
|
src.indexOf('export async function getKuaishouCloudClaimDetail'),
|
|
src.indexOf('export async function submitClaimUid'),
|
|
)
|
|
assert.ok(detail.includes('flow.mock?.enabled'))
|
|
assert.ok(detail.includes('isAffiliateDashSnapshotFresh(flow.lastSyncedAt'))
|
|
assert.ok(detail.includes('bindFlow.lastBindSyncedAt'))
|
|
assert.ok(
|
|
!detail.includes('snapshotOnly'),
|
|
'新鲜快照必须直接不调用同步;snapshotOnly 仍会 updateTask',
|
|
)
|
|
const refresh = src.slice(
|
|
src.indexOf('async function refreshAffiliateDashBindState'),
|
|
src.indexOf('function normalizeUid'),
|
|
)
|
|
assert.ok(
|
|
refresh.includes('lastBindSyncedAt: now'),
|
|
'成功拉取绑定结果后才记时间,失败不能挡住下一次',
|
|
)
|
|
})
|
|
|
|
test('shouldRefreshAffiliateDashBindStateForSnapshot keeps polling before submit', () => {
|
|
assert.equal(
|
|
shouldRefreshAffiliateDashBindStateForSnapshot({
|
|
taskStatus: 'waiting_binding',
|
|
orderStatus: 'paid',
|
|
submitStatus: '',
|
|
}),
|
|
true,
|
|
)
|
|
})
|
|
|
|
test('shouldRefreshAffiliateDashBindStateForSnapshot stops after submit starts', () => {
|
|
assert.equal(
|
|
shouldRefreshAffiliateDashBindStateForSnapshot({
|
|
taskStatus: 'redeeming',
|
|
orderStatus: 'delivering',
|
|
submitStatus: 'delivering',
|
|
}),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('shouldRefreshAffiliateDashBindStateForSnapshot stops after delivered', () => {
|
|
assert.equal(
|
|
shouldRefreshAffiliateDashBindStateForSnapshot({
|
|
taskStatus: 'redeemed',
|
|
orderStatus: 'delivered',
|
|
submitStatus: 'delivered',
|
|
}),
|
|
false,
|
|
)
|
|
})
|
|
|
|
test('shouldRefreshAffiliateDashBindStateForSnapshot stops for failed platform result', () => {
|
|
assert.equal(
|
|
shouldRefreshAffiliateDashBindStateForSnapshot({
|
|
taskStatus: 'retry_pending',
|
|
orderStatus: 'ship_failed',
|
|
submitStatus: '',
|
|
}),
|
|
false,
|
|
)
|
|
})
|