feat: harden local shell, SFTP, and desktop session reliability
Finder-launched terminals now inherit a login PATH so tools like ollama resolve, destructive SFTP/editor actions require confirmation, and terminal search plus window dragging work again. SSH forwards and RDP sessions keep listeners and survive reconnect without FastPath crashes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
188f3556ed
commit
08696896f9
223 files changed
+13493
-3423
No files matched your search
@@ -0,0 +1,72 @@
|
||||
import { act, renderHook, waitFor } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useSFTP } from '../../src/hooks/useSFTP'
|
||||
import { usePoolStore } from '../../src/stores/connection/poolStore'
|
||||
import { useSessionStore } from '../../src/stores/sessionStore'
|
||||
import { useTabStore } from '../../src/stores/tabStore'
|
||||
import { mockDesktopApi } from '../setup'
|
||||
|
||||
const session = {
|
||||
id: 'transfer-host',
|
||||
name: 'Transfer host',
|
||||
host: 'host.example.com',
|
||||
port: 22,
|
||||
username: 'root',
|
||||
authType: 'agent' as const,
|
||||
}
|
||||
|
||||
describe('useSFTP transfer lifecycle', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
window.opsxApi = mockDesktopApi
|
||||
usePoolStore.setState({ connections: new Map() })
|
||||
useSessionStore.setState({ sessions: [session] })
|
||||
useTabStore.setState({
|
||||
tabs: [{ id: 'sftp-tab', title: 'SFTP', type: 'sftp', sessionId: session.id, isActive: true }],
|
||||
activeTabId: 'sftp-tab',
|
||||
})
|
||||
vi.mocked(mockDesktopApi.sshConnect).mockResolvedValue({ success: true, connectionId: 'connection-1' })
|
||||
vi.mocked(mockDesktopApi.sessionGetById).mockResolvedValue({ success: true, session })
|
||||
vi.mocked(mockDesktopApi.sftpConnect).mockResolvedValue({ success: true, sftpId: 'sftp-1' })
|
||||
vi.mocked(mockDesktopApi.sftpListDirectory).mockResolvedValue({ success: true, files: [] })
|
||||
vi.mocked(mockDesktopApi.getHomePath).mockResolvedValue({ success: true, path: '/Users/test' })
|
||||
vi.mocked(mockDesktopApi.localReadDir).mockResolvedValue({ success: true, files: [] })
|
||||
})
|
||||
|
||||
it('settles a canceled transfer even when its visible row is removed before native completion', async () => {
|
||||
let finishNativeUpload: ((value: { success: boolean }) => void) | undefined
|
||||
vi.mocked(mockDesktopApi.sftpUpload).mockImplementationOnce(
|
||||
() => new Promise((resolve) => {
|
||||
finishNativeUpload = resolve
|
||||
})
|
||||
)
|
||||
|
||||
const { result } = renderHook(() => useSFTP({ tabId: 'sftp-tab' }))
|
||||
await act(async () => {
|
||||
await result.current.connect(session.id)
|
||||
})
|
||||
|
||||
let batchPromise: ReturnType<typeof result.current.uploadFiles>
|
||||
act(() => {
|
||||
batchPromise = result.current.uploadFiles([
|
||||
{ path: '/Users/test/large.bin', name: 'large.bin', size: 1024 },
|
||||
])
|
||||
})
|
||||
|
||||
await waitFor(() => expect(mockDesktopApi.sftpUpload).toHaveBeenCalledTimes(1))
|
||||
const taskId = result.current.transferQueue[0]?.id
|
||||
expect(taskId).toBeTruthy()
|
||||
|
||||
act(() => {
|
||||
result.current.cancelTransfer(taskId!)
|
||||
result.current.removeTransfer(taskId!)
|
||||
})
|
||||
expect(result.current.transferQueue).toHaveLength(0)
|
||||
expect(mockDesktopApi.sftpCancelTransfer).toHaveBeenCalledWith('sftp-1')
|
||||
|
||||
await act(async () => {
|
||||
finishNativeUpload?.({ success: true })
|
||||
await expect(batchPromise!).resolves.toEqual({ completed: 0, failed: 0, errors: [] })
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user