209 lines
6.0 KiB
JavaScript
209 lines
6.0 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
|
|
import {
|
|
normalizeLoginType,
|
|
parseViewportSpec,
|
|
} from './session-browser-config.js'
|
|
import { normalizeTencentCookieMap } from './session-cookie-map.js'
|
|
import {
|
|
buildArtifactsPayload,
|
|
buildRedeemPayload,
|
|
} from './session-payload.js'
|
|
import { ensureReviewScreenshot } from './session-review.js'
|
|
import { resolveInitialQrSessionState } from './session-state.js'
|
|
import {
|
|
REDEEM_SUCCESS_AUTO_CLOSE_MS,
|
|
resolveTencentSessionExpiresAt,
|
|
} from './session.js'
|
|
|
|
test('resolveTencentSessionExpiresAt uses normal ttl when no auto-close is armed', () => {
|
|
const nowMs = Date.UTC(2026, 3, 14, 9, 30, 0)
|
|
assert.equal(
|
|
resolveTencentSessionExpiresAt({ autoCloseAt: 0 }, nowMs),
|
|
nowMs + (30 * 60 * 1000),
|
|
)
|
|
})
|
|
|
|
test('resolveTencentSessionExpiresAt keeps redeemed auto-close deadline once armed', () => {
|
|
const nowMs = Date.UTC(2026, 3, 14, 9, 30, 0)
|
|
const autoCloseAt = nowMs + REDEEM_SUCCESS_AUTO_CLOSE_MS
|
|
|
|
assert.equal(
|
|
resolveTencentSessionExpiresAt({ autoCloseAt }, nowMs + 60_000),
|
|
autoCloseAt,
|
|
)
|
|
})
|
|
|
|
test('normalizeLoginType collapses aliases and falls back to qq', () => {
|
|
assert.equal(normalizeLoginType(' qc '), 'qq')
|
|
assert.equal(normalizeLoginType('wechat'), 'wx')
|
|
assert.equal(normalizeLoginType('unknown'), 'qq')
|
|
assert.equal(normalizeLoginType(''), 'qq')
|
|
})
|
|
|
|
test('parseViewportSpec accepts valid viewport strings and rejects invalid values', () => {
|
|
assert.deepEqual(parseViewportSpec('1920x1080'), { width: 1920, height: 1080 })
|
|
assert.deepEqual(parseViewportSpec('1920x1080x24'), { width: 1920, height: 1080 })
|
|
assert.equal(parseViewportSpec('799x600'), null)
|
|
assert.equal(parseViewportSpec('broken'), null)
|
|
})
|
|
|
|
test('buildRedeemPayload strips internal paths unless explicitly requested', () => {
|
|
const redeem = {
|
|
code: 'ABC123',
|
|
area: '微信区',
|
|
proofMode: 'basic',
|
|
attempts: [
|
|
{
|
|
attempt: 1,
|
|
redeem: { success: false, message: '验证码错误' },
|
|
},
|
|
],
|
|
final: {
|
|
attempt: 2,
|
|
redeem: { success: true, message: '兑换成功' },
|
|
},
|
|
finishedAt: '2026-04-14T09:40:00.000Z',
|
|
screenshotPath: '/tmp/redeem.png',
|
|
htmlPath: '/tmp/redeem.html',
|
|
resultPath: '/tmp/redeem.json',
|
|
}
|
|
|
|
assert.deepEqual(buildRedeemPayload(redeem), {
|
|
code: 'ABC123',
|
|
area: '微信区',
|
|
proofMode: 'basic',
|
|
attempts: [
|
|
{
|
|
attempt: 1,
|
|
redeem: { success: false, message: '验证码错误' },
|
|
},
|
|
],
|
|
final: {
|
|
attempt: 2,
|
|
redeem: { success: true, message: '兑换成功' },
|
|
},
|
|
finishedAt: '2026-04-14T09:40:00.000Z',
|
|
})
|
|
|
|
assert.deepEqual(buildRedeemPayload(redeem, { includeInternalPaths: true }), {
|
|
code: 'ABC123',
|
|
area: '微信区',
|
|
proofMode: 'basic',
|
|
attempts: [
|
|
{
|
|
attempt: 1,
|
|
redeem: { success: false, message: '验证码错误' },
|
|
},
|
|
],
|
|
final: {
|
|
attempt: 2,
|
|
redeem: { success: true, message: '兑换成功' },
|
|
},
|
|
finishedAt: '2026-04-14T09:40:00.000Z',
|
|
screenshotPath: '/tmp/redeem.png',
|
|
htmlPath: '/tmp/redeem.html',
|
|
resultPath: '/tmp/redeem.json',
|
|
})
|
|
})
|
|
|
|
test('buildArtifactsPayload only exposes internal artifact paths in debug mode', () => {
|
|
const session = {
|
|
sessionDir: '/tmp/session',
|
|
qrImagePath: '/tmp/session/qq-qr.png',
|
|
qrImageBase64: 'base64data',
|
|
lastReview: {
|
|
screenshotPath: '/tmp/session/review.png',
|
|
},
|
|
lastRedeem: {
|
|
screenshotPath: '/tmp/session/redeem.png',
|
|
htmlPath: '/tmp/session/redeem.html',
|
|
resultPath: '/tmp/session/redeem.json',
|
|
},
|
|
}
|
|
|
|
assert.deepEqual(buildArtifactsPayload(session), {
|
|
hasQrImage: true,
|
|
hasReviewScreenshot: true,
|
|
hasScreenshot: true,
|
|
})
|
|
|
|
assert.deepEqual(buildArtifactsPayload(session, { includeInternalPaths: true }), {
|
|
hasQrImage: true,
|
|
hasReviewScreenshot: true,
|
|
hasScreenshot: true,
|
|
sessionDir: '/tmp/session',
|
|
qrImagePath: '/tmp/session/qq-qr.png',
|
|
screenshotPath: '/tmp/session/redeem.png',
|
|
htmlPath: '/tmp/session/redeem.html',
|
|
resultPath: '/tmp/session/redeem.json',
|
|
reviewScreenshotPath: '/tmp/session/review.png',
|
|
})
|
|
})
|
|
|
|
test('normalizeTencentCookieMap fills required defaults and derived proxy cookie', () => {
|
|
assert.deepEqual(
|
|
normalizeTencentCookieMap([
|
|
{ name: 'openid', value: 'openid-1' },
|
|
{ name: 'access_token', value: 'token-1' },
|
|
{ name: '', value: 'ignored' },
|
|
]),
|
|
{
|
|
openid: 'openid-1',
|
|
access_token: 'token-1',
|
|
acctype: 'qc',
|
|
appid: '101491592',
|
|
iegams_milo_proxylogin_qc: '101491592_$$_openid-1_$$_token-1',
|
|
},
|
|
)
|
|
})
|
|
|
|
test('resolveInitialQrSessionState creates waiting-scan snapshot with ttl', () => {
|
|
assert.deepEqual(
|
|
resolveInitialQrSessionState('wx', {
|
|
updatedAt: '2026-04-14T09:30:00.000Z',
|
|
nowMs: 1_700_000_000_000,
|
|
sessionTtlMs: 1_800_000,
|
|
}),
|
|
{
|
|
status: 'waiting_scan',
|
|
notice: '请使用微信扫码登录',
|
|
updatedAt: '2026-04-14T09:30:00.000Z',
|
|
expiresAt: 1_700_001_800_000,
|
|
},
|
|
)
|
|
})
|
|
|
|
test('ensureReviewScreenshot writes screenshot state and skips unchanged signature', async () => {
|
|
const screenshotCalls = []
|
|
const session = {
|
|
sessionId: 'txbs-demo',
|
|
loginType: 'qq',
|
|
sessionDir: '/tmp/session-demo',
|
|
page: {
|
|
async screenshot(options) {
|
|
screenshotCalls.push(options)
|
|
},
|
|
},
|
|
lastReview: null,
|
|
}
|
|
|
|
const activityInfo = {
|
|
role: {
|
|
roleId: '1001',
|
|
roleName: '测试角色',
|
|
},
|
|
}
|
|
|
|
assert.equal(await ensureReviewScreenshot(session, activityInfo), true)
|
|
assert.equal(screenshotCalls.length, 1)
|
|
assert.equal(session.lastReview.roleId, '1001')
|
|
assert.equal(session.lastReview.roleName, '测试角色')
|
|
assert.equal(session.lastReview.signature, 'qq|1001|测试角色')
|
|
assert.match(session.lastReview.screenshotPath, /role-review\.png$/)
|
|
|
|
assert.equal(await ensureReviewScreenshot(session, activityInfo), false)
|
|
assert.equal(screenshotCalls.length, 1)
|
|
})
|