feat: release OpsXShell 2.1.0 native Tauri edition

This commit is contained in:
Logan.Li committed 2026-07-30 23:32:51 +08:00
1 parent e9a0d21758
commit a3dba0c6ed
311 files changed
+31748 -14897

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
import { describe, expect, it, vi } from 'vitest'
const { listenMock } = vi.hoisted(() => ({
listenMock: vi.fn(),
}))
vi.mock('@tauri-apps/api/event', () => ({
listen: listenMock,
}))
import { desktopApi } from '../../src/platform/desktop'
function deferred<T>() {
let resolve!: (value: T) => void
const promise = new Promise<T>((resolvePromise) => {
resolve = resolvePromise
})
return { promise, resolve }
}
describe('Tauri event subscriptions', () => {
it('safely unregisters when React cleans up before listen resolves', async () => {
const pending = deferred<() => void>()
const unlisten = vi.fn()
listenMock.mockReturnValueOnce(pending.promise)
const listener = vi.fn()
desktopApi.onConnectionClosed(listener)
desktopApi.removeListener('ssh:connection-closed', listener as (...args: unknown[]) => void)
pending.resolve(unlisten)
await Promise.resolve()
await Promise.resolve()
expect(unlisten).toHaveBeenCalledTimes(1)
})
it('does not unregister an active listener more than once', async () => {
const unlisten = vi.fn()
listenMock.mockResolvedValueOnce(unlisten)
const listener = vi.fn()
desktopApi.onConnectionClosed(listener)
await Promise.resolve()
desktopApi.removeListener('ssh:connection-closed', listener as (...args: unknown[]) => void)
desktopApi.removeListener('ssh:connection-closed', listener as (...args: unknown[]) => void)
expect(unlisten).toHaveBeenCalledTimes(1)
})
})
+48
View File
@@ -0,0 +1,48 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import {
downloadRemoteFile,
localPath,
readRemoteTextFile,
remotePath,
uploadRemoteFile,
writeRemoteTextFile,
} from '../../src/platform/sftp'
describe('SFTP path semantics', () => {
beforeEach(() => vi.clearAllMocks())
it('always sends local then remote paths for upload', async () => {
await uploadRemoteFile({
sftpId: 'sftp-1',
localPath: localPath('/Users/me/app.log'),
remotePath: remotePath('/var/log/app.log'),
})
expect(window.opsxApi.sftpUpload).toHaveBeenCalledWith('sftp-1', '/Users/me/app.log', '/var/log/app.log')
})
it('always sends remote then local paths for download', async () => {
await downloadRemoteFile({
sftpId: 'sftp-1',
remotePath: remotePath('/var/log/app.log'),
localPath: localPath('/Users/me/app.log'),
})
expect(window.opsxApi.sftpDownload).toHaveBeenCalledWith('sftp-1', '/var/log/app.log', '/Users/me/app.log')
})
it('keeps remote editor reads and writes separate from transfers', async () => {
await readRemoteTextFile({ sftpId: 'sftp-1', remotePath: remotePath('/etc/hosts') })
await writeRemoteTextFile({
sftpId: 'sftp-1',
remotePath: remotePath('/etc/hosts'),
content: '127.0.0.1 localhost',
})
expect(window.opsxApi.sftpReadText).toHaveBeenCalledWith('sftp-1', '/etc/hosts')
expect(window.opsxApi.sftpWriteText).toHaveBeenCalledWith('sftp-1', '/etc/hosts', '127.0.0.1 localhost')
expect(window.opsxApi.sftpUpload).not.toHaveBeenCalled()
expect(window.opsxApi.sftpDownload).not.toHaveBeenCalled()
})
})