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) })