/** * Platform / protocol contract patrol — catches missing commands or broken defaults. */ import { describe, expect, it } from 'vitest' import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { mockDesktopApi } from '../setup' import { buildOpenTabPayload, defaultPortForProtocol, isSshSession, sessionProtocol, sessionToRdpConfig, sessionToVncConfig, tabTypeForProtocol, } from '../../src/utils/sessionProtocol' import { RDP_SESSION, VNC_SESSION, SSH_SESSION } from '../helpers/patrol' import * as rdp from '../../src/platform/rdp' import * as vnc from '../../src/platform/vnc' import * as sftpPlatform from '../../src/platform/sftp' const REQUIRED_SSH_KEYS = [ 'sshConnect', 'sshDisconnect', 'sshCreateShell', 'sshShellWrite', 'sshShellResize', 'sshCloseShell', 'sshForwardLocal', 'sshForwardRemote', 'sshForwardDynamic', 'sshForwardStop', ] as const const REQUIRED_SFTP_KEYS = [ 'sftpConnect', 'sftpDisconnect', 'sftpListDirectory', 'sftpUpload', 'sftpUploadDir', 'sftpDownload', 'sftpDownloadDir', 'sftpMkdir', 'sftpRename', 'sftpDelete', 'sftpStat', 'sftpChmod', ] as const describe('patrol / contracts', () => { it('leaves HTML5 drag-and-drop available to the SFTP panes', () => { const config = JSON.parse( readFileSync(resolve(process.cwd(), 'src-tauri/tauri.conf.json'), 'utf8') ) as { app?: { windows?: Array<{ dragDropEnabled?: boolean }> } } expect(config.app?.windows?.[0]?.dragDropEnabled).toBe(false) }) it('exposes SSH + SFTP native commands on the desktop mock contract', () => { for (const key of REQUIRED_SSH_KEYS) { expect(typeof mockDesktopApi[key], key).toBe('function') } for (const key of REQUIRED_SFTP_KEYS) { expect(typeof mockDesktopApi[key], key).toBe('function') } }) it('keeps protocol defaults for SSH / RDP / VNC', () => { expect(defaultPortForProtocol('ssh')).toBe(22) expect(defaultPortForProtocol('rdp')).toBe(3389) expect(defaultPortForProtocol('vnc')).toBe(5900) expect(tabTypeForProtocol('ssh')).toBe('terminal') expect(tabTypeForProtocol('rdp')).toBe('rdp') expect(tabTypeForProtocol('vnc')).toBe('vnc') expect(isSshSession(SSH_SESSION)).toBe(true) expect(isSshSession(RDP_SESSION)).toBe(false) expect(sessionProtocol(VNC_SESSION)).toBe('vnc') }) it('builds open-tab payloads with desktop configs for RDP/VNC', () => { const rdpTab = buildOpenTabPayload(RDP_SESSION) expect(rdpTab.type).toBe('rdp') expect(rdpTab.rdpConfig).toEqual( expect.objectContaining({ host: 'win.example.com', port: 3389, username: 'Administrator', }) ) const vncTab = buildOpenTabPayload(VNC_SESSION) expect(vncTab.type).toBe('vnc') expect(vncTab.vncConfig).toEqual( expect.objectContaining({ host: '192.168.1.50', port: 5900, }) ) const sshTab = buildOpenTabPayload(SSH_SESSION) expect(sshTab.type).toBe('terminal') expect(sshTab.rdpConfig).toBeUndefined() expect(sshTab.vncConfig).toBeUndefined() }) it('maps session credentials into RDP/VNC engine configs', () => { expect(sessionToRdpConfig(RDP_SESSION).password).toBe('secret') expect(sessionToVncConfig(VNC_SESSION).password).toBe('vnc-pass') }) it('exports RDP / VNC / SFTP platform adapters', () => { expect(typeof rdp.rdpConnect).toBe('function') expect(typeof rdp.rdpDisconnect).toBe('function') expect(typeof rdp.rdpResize).toBe('function') expect(typeof vnc.vncConnect).toBe('function') expect(typeof vnc.vncDisconnect).toBe('function') expect(typeof sftpPlatform.uploadRemoteFile).toBe('function') expect(typeof sftpPlatform.downloadRemoteFile).toBe('function') }) it('refuses RDP/VNC connect outside Tauri runtime', async () => { await expect(rdp.rdpConnect(sessionToRdpConfig(RDP_SESSION))).rejects.toThrow(/原生|native|Tauri|RDP/i) await expect(vnc.vncConnect(sessionToVncConfig(VNC_SESSION))).rejects.toThrow(/原生|native|Tauri|VNC/i) }) })