import { tmpdir } from 'node:os' import { join } from 'node:path' import { beforeEach, describe, expect, it, vi } from 'vitest' import type { AuthProbeResult } from './auth-types' const probeAIAccountSession = vi.fn() const probePublishAccountSession = vi.fn() const silentRefreshAIAccountSession = vi.fn() const silentRefreshPublishAccountSession = vi.fn() const createSessionHandleForPartition = vi.fn() const resolveStoredSessionPartition = vi.fn() const emitRuntimeInvalidated = vi.fn() vi.mock('electron/main', () => ({ app: { getPath: () => join(tmpdir(), 'geo-rankly-account-health-test'), }, })) vi.mock('./account-binder', () => ({ probeAIAccountSession, probePublishAccountSession, silentRefreshAIAccountSession, silentRefreshPublishAccountSession, })) vi.mock('./session-registry', () => ({ createSessionHandleForPartition, resolveStoredSessionPartition, })) vi.mock('./runtime-events', () => ({ emitRuntimeInvalidated, })) const account = { id: 'account-1', platform: 'doubao', platformUid: 'doubao-session:demo', displayName: '豆包账号', } function challenge(reason: AuthProbeResult['reason'] = 'captcha_gate'): AuthProbeResult { return { verdict: 'challenge_required', reason, profile: null, sessionFingerprint: null, } } function active(): AuthProbeResult { return { verdict: 'active', reason: 'probe_success', profile: { displayName: '豆包账号', avatarUrl: null, subjectUid: 'doubao-session:demo', }, sessionFingerprint: 'fingerprint-live', } } describe('account health challenge recheck', () => { beforeEach(() => { vi.resetModules() vi.clearAllMocks() resolveStoredSessionPartition.mockReturnValue('persist:test') createSessionHandleForPartition.mockReturnValue({ partition: 'persist:test' }) silentRefreshAIAccountSession.mockResolvedValue(true) silentRefreshPublishAccountSession.mockResolvedValue(true) }) it('hides a first challenge result when the automatic recheck succeeds', async () => { probeAIAccountSession.mockResolvedValueOnce(challenge()).mockResolvedValueOnce(active()) const { probeTrackedAccount } = await import('./account-health') const snapshot = await probeTrackedAccount(account, { trigger: 'manual', allowSilentRefresh: true, force: true, }) expect(probeAIAccountSession).toHaveBeenCalledTimes(2) expect(snapshot.authState).toBe('active') expect(snapshot.authReason).toBe('probe_success') }) it('shows manual verification only after the automatic recheck still needs it', async () => { probeAIAccountSession .mockResolvedValueOnce(challenge('risk_control')) .mockResolvedValueOnce(challenge('risk_control')) const { probeTrackedAccount } = await import('./account-health') const snapshot = await probeTrackedAccount(account, { trigger: 'manual', allowSilentRefresh: true, force: true, }) expect(probeAIAccountSession).toHaveBeenCalledTimes(2) expect(snapshot.authState).toBe('challenge_required') expect(snapshot.authReason).toBe('risk_control') }) it('probes restored default partitions instead of marking restarted accounts expired', async () => { resolveStoredSessionPartition.mockReturnValue('persist:acc-account-1') probeAIAccountSession.mockResolvedValueOnce(active()) const { probeTrackedAccount } = await import('./account-health') const snapshot = await probeTrackedAccount(account, { trigger: 'manual', allowSilentRefresh: true, force: true, }) expect(createSessionHandleForPartition).toHaveBeenCalledWith( 'account-1', 'persist:acc-account-1', ) expect(probeAIAccountSession).toHaveBeenCalledWith(account, 'persist:acc-account-1') expect(snapshot.authState).toBe('active') }) })