import { describe, expect, it } from 'vitest'; import type { SavedConnection, SecurityUpdateIssue, SecurityUpdateStatus } from '../types'; import { hasSecurityUpdateRecentResult, resolveSecurityUpdateFocusState, resolveSecurityUpdateRepairEntry, resolveSecurityUpdateSettingsFocusTarget, shouldRefreshSecurityUpdateDetailsFocus, shouldReopenSecurityUpdateDetails, shouldRetrySecurityUpdateAfterRepairSave, } from './securityUpdateRepairFlow'; const createConnection = (id: string): SavedConnection => ({ id, name: `连接-${id}`, config: { id, type: 'postgres', host: 'db.local', port: 5432, user: 'postgres', }, }); const createStatus = (overrides: Partial = {}): SecurityUpdateStatus => ({ overallStatus: 'needs_attention', summary: { total: 1, updated: 0, pending: 1, skipped: 0, failed: 0, }, issues: [], ...overrides, }); describe('securityUpdateRepairFlow', () => { it('opens the matching connection and preserves the return source for security update repairs', () => { const target = createConnection('conn-1'); const issue: SecurityUpdateIssue = { id: 'issue-1', action: 'open_connection', refId: 'conn-1', }; expect(resolveSecurityUpdateRepairEntry(issue, [target])).toEqual({ type: 'connection', connection: target, repairSource: 'connection', }); }); it('returns a user-facing warning when the target connection no longer exists', () => { const issue: SecurityUpdateIssue = { id: 'issue-1', action: 'open_connection', refId: 'missing-conn', }; expect(resolveSecurityUpdateRepairEntry(issue, [createConnection('conn-1')])).toEqual({ type: 'warning', message: '未找到对应连接,请先重新检查最新状态', }); }); it('maps proxy, ai and retry actions to the expected repair entry', () => { expect(resolveSecurityUpdateRepairEntry({ id: 'proxy', action: 'open_proxy_settings' }, [])).toEqual({ type: 'proxy', repairSource: 'proxy', }); expect(resolveSecurityUpdateRepairEntry({ id: 'ai', action: 'open_ai_settings', refId: 'provider-1' }, [])).toEqual({ type: 'ai', providerId: 'provider-1', repairSource: 'ai', }); expect(resolveSecurityUpdateRepairEntry({ id: 'retry', action: 'retry_update' }, [])).toEqual({ type: 'retry', }); }); it('routes view_details actions to the latest result section when a recent result exists', () => { const status = createStatus({ backupPath: '/tmp/gonavi-backup.json', lastError: '写入新密钥失败', }); expect(hasSecurityUpdateRecentResult(status)).toBe(true); expect(resolveSecurityUpdateSettingsFocusTarget(status)).toBe('recent_result'); expect(resolveSecurityUpdateRepairEntry({ id: 'details', action: 'view_details' }, [], status)).toEqual({ type: 'details', focusTarget: 'recent_result', }); }); it('falls back to the status section when no recent result is available yet', () => { const status = createStatus(); expect(hasSecurityUpdateRecentResult(status)).toBe(false); expect(resolveSecurityUpdateSettingsFocusTarget(status)).toBe('status'); expect(resolveSecurityUpdateRepairEntry({ id: 'details', action: 'view_details' }, [], status)).toEqual({ type: 'details', focusTarget: 'status', }); }); it('builds a fresh focus pulse for repeated details clicks and clears it when the modal closes', () => { expect(resolveSecurityUpdateFocusState(true, 'status', 1)).toEqual({ target: 'status', pulseKey: 'status:1', }); expect(resolveSecurityUpdateFocusState(true, 'status', 2)).toEqual({ target: 'status', pulseKey: 'status:2', }); expect(resolveSecurityUpdateFocusState(false, 'status', 2)).toEqual({ target: null, pulseKey: null, }); expect(resolveSecurityUpdateFocusState(true, null, 3)).toEqual({ target: null, pulseKey: null, }); }); it('reopens security update details after closing a repair entry opened from that page', () => { expect(shouldReopenSecurityUpdateDetails('connection')).toBe(true); expect(shouldReopenSecurityUpdateDetails('proxy')).toBe(true); expect(shouldReopenSecurityUpdateDetails('ai')).toBe(true); expect(shouldReopenSecurityUpdateDetails(null)).toBe(false); }); it('retries the current round automatically after saving a connection from the repair flow', () => { expect(shouldRetrySecurityUpdateAfterRepairSave('connection')).toBe(true); expect(shouldRetrySecurityUpdateAfterRepairSave('proxy')).toBe(false); expect(shouldRetrySecurityUpdateAfterRepairSave('ai')).toBe(false); expect(shouldRetrySecurityUpdateAfterRepairSave(null)).toBe(false); }); it('does not force a new focus pulse when the details modal is already open and only the round result is refreshing', () => { expect(shouldRefreshSecurityUpdateDetailsFocus({ requestedOpen: true, wasOpen: true, })).toBe(false); expect(shouldRefreshSecurityUpdateDetailsFocus({ requestedOpen: true, wasOpen: false, })).toBe(true); expect(shouldRefreshSecurityUpdateDetailsFocus({ requestedOpen: false, wasOpen: true, })).toBe(false); }); });