feat: release OpsXShell 2.1.0 native Tauri edition
This commit is contained in:
1 parent
e9a0d21758
commit
a3dba0c6ed
311 files changed
+31748
-14897
No files matched your search
+94
-25
@@ -4,18 +4,33 @@
|
||||
|
||||
import '@testing-library/jest-dom'
|
||||
import { vi } from 'vitest'
|
||||
import type { DesktopApiContract } from '../src/desktop'
|
||||
|
||||
// Mock Electron API
|
||||
const mockElectronAPI = {
|
||||
// Mock native desktop API
|
||||
export const mockDesktopApi: DesktopApiContract = {
|
||||
takePendingSshLinks: vi.fn().mockResolvedValue([]),
|
||||
appRuntimeInfo: vi.fn().mockResolvedValue({
|
||||
appVersion: '2.0.0',
|
||||
os: 'macos',
|
||||
arch: 'aarch64',
|
||||
nativeBackend: 'Tauri 2 / Rust',
|
||||
sshBackend: 'libssh2 / ssh2 0.9',
|
||||
dataPath: '/tmp/opsxshell-data.json',
|
||||
credentialPath: '/tmp/.opsxshsell/master.key',
|
||||
}),
|
||||
// SSH
|
||||
sshConnect: vi.fn().mockResolvedValue({ success: true, connectionId: 'test-conn-1' }),
|
||||
sshDisconnect: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshExec: vi.fn().mockResolvedValue({ success: true, stdout: '', stderr: '' }),
|
||||
sshKeepalive: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshCreateShell: vi.fn().mockResolvedValue({ success: true, shellId: 'test-shell-1' }),
|
||||
sshShellWrite: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshShellResize: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshForwardLocal: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshForwardRemote: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshForwardDynamic: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshForwardStop: vi.fn().mockResolvedValue({ success: true }),
|
||||
sshForwardList: vi.fn().mockResolvedValue({ success: true, tunnels: [] }),
|
||||
|
||||
// SFTP
|
||||
sftpConnect: vi.fn().mockResolvedValue({ success: true, sftpId: 'test-sftp-1' }),
|
||||
@@ -25,20 +40,35 @@ const mockElectronAPI = {
|
||||
sftpRename: vi.fn().mockResolvedValue({ success: true }),
|
||||
sftpDelete: vi.fn().mockResolvedValue({ success: true }),
|
||||
sftpMkdir: vi.fn().mockResolvedValue({ success: true }),
|
||||
sftpStat: vi.fn().mockResolvedValue({ success: true, stats: undefined }),
|
||||
sftpChmod: vi.fn().mockResolvedValue({ success: true }),
|
||||
sftpReadText: vi.fn().mockResolvedValue({ success: true, content: '' }),
|
||||
sftpWriteText: vi.fn().mockResolvedValue({ success: true }),
|
||||
onSFTPProgress: vi.fn(),
|
||||
|
||||
// Session
|
||||
getSessions: vi.fn().mockResolvedValue({ success: true, sessions: [] }),
|
||||
getSession: vi.fn().mockResolvedValue({ success: true, session: null }),
|
||||
createSession: vi.fn().mockResolvedValue({ success: true, id: 'test-session-1' }),
|
||||
updateSession: vi.fn().mockResolvedValue({ success: true }),
|
||||
deleteSession: vi.fn().mockResolvedValue({ success: true }),
|
||||
sessionGetAll: vi.fn().mockResolvedValue({ success: true, sessions: [] }),
|
||||
sessionGetById: vi.fn().mockResolvedValue({ success: true, session: undefined }),
|
||||
sessionCreate: vi.fn().mockImplementation(async (session) => ({
|
||||
success: true,
|
||||
session: { ...session, id: 'test-session-1' },
|
||||
})),
|
||||
sessionUpdate: vi.fn().mockImplementation(async (id, updates) => ({
|
||||
success: true,
|
||||
session: { id, ...updates },
|
||||
})),
|
||||
sessionDelete: vi.fn().mockResolvedValue({ success: true }),
|
||||
|
||||
// Settings
|
||||
getSettings: vi.fn().mockResolvedValue({ success: true, settings: {} }),
|
||||
setSettings: vi.fn().mockResolvedValue({ success: true }),
|
||||
settingsGet: vi.fn().mockResolvedValue({ success: true, value: undefined }),
|
||||
settingsSet: vi.fn().mockResolvedValue({ success: true }),
|
||||
aiProviderSaveKey: vi.fn().mockResolvedValue({ success: true }),
|
||||
aiProviderHasKey: vi.fn().mockResolvedValue(false),
|
||||
aiProviderDeleteKey: vi.fn().mockResolvedValue({ success: true }),
|
||||
aiListModels: vi.fn().mockResolvedValue({ success: true, models: [] }),
|
||||
aiComplete: vi.fn().mockResolvedValue({ success: true, text: '建议', model: 'test-model', redactedCount: 0 }),
|
||||
aiTestProvider: vi.fn().mockResolvedValue({ success: true, status: 200, model: 'test-model', latencyMs: 88, answer: 'OK' }),
|
||||
aiCatalogFetch: vi.fn().mockResolvedValue({ success: false, documents: [], errors: ['offline'] }),
|
||||
|
||||
// Dialog
|
||||
showSaveDialog: vi.fn().mockResolvedValue({ success: true, canceled: false, filePath: '/tmp/test' }),
|
||||
@@ -46,32 +76,66 @@ const mockElectronAPI = {
|
||||
|
||||
// File
|
||||
localReadDir: vi.fn().mockResolvedValue({ success: true, files: [] }),
|
||||
localReadFile: vi.fn().mockResolvedValue({ success: true, content: '' }),
|
||||
localWriteFile: vi.fn().mockResolvedValue({ success: true }),
|
||||
readFile: vi.fn().mockResolvedValue({ success: true, data: '' }),
|
||||
writeFile: vi.fn().mockResolvedValue({ success: true }),
|
||||
localGetStats: vi.fn().mockResolvedValue({ success: true }),
|
||||
localRename: vi.fn().mockResolvedValue({ success: true }),
|
||||
localDelete: vi.fn().mockResolvedValue({ success: true }),
|
||||
localMkdir: vi.fn().mockResolvedValue({ success: true }),
|
||||
getHomePath: vi.fn().mockResolvedValue({ success: true, path: '/Users/test' }),
|
||||
getDownloadsPath: vi.fn().mockResolvedValue({ success: true, path: '/Users/test/Downloads' }),
|
||||
|
||||
// Zmodem
|
||||
onZmodemSend: vi.fn(),
|
||||
getDownloadsPath: vi.fn().mockResolvedValue('/Users/test/Downloads'),
|
||||
|
||||
// App
|
||||
getVersion: vi.fn().mockResolvedValue('1.0.0'),
|
||||
getPlatform: vi.fn().mockReturnValue('darwin'),
|
||||
openExternal: vi.fn().mockResolvedValue(undefined),
|
||||
clipboardReadText: vi.fn().mockResolvedValue(''),
|
||||
clipboardWriteText: vi.fn().mockResolvedValue(undefined),
|
||||
toggleMaximize: vi.fn().mockResolvedValue(undefined),
|
||||
|
||||
// Local terminal
|
||||
localListShells: vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
shells: [
|
||||
{ path: '/bin/zsh', name: 'Zsh', kind: 'zsh', isDefault: true },
|
||||
{ path: '/bin/bash', name: 'Bash', kind: 'bash', isDefault: false },
|
||||
],
|
||||
}),
|
||||
localCreateShell: vi.fn().mockResolvedValue({
|
||||
success: true,
|
||||
shellId: 'local-test-1',
|
||||
shellPath: '/bin/zsh',
|
||||
shellName: 'zsh',
|
||||
}),
|
||||
localWrite: vi.fn().mockResolvedValue({ success: true }),
|
||||
localResize: vi.fn().mockResolvedValue({ success: true }),
|
||||
localKill: vi.fn().mockResolvedValue({ success: true }),
|
||||
onLocalData: vi.fn(),
|
||||
|
||||
// Event listeners
|
||||
onShellData: vi.fn(),
|
||||
onConnectionClosed: vi.fn(),
|
||||
onHostKeyPrompt: vi.fn(),
|
||||
onMenuNewSession: vi.fn(),
|
||||
onMenuQuickConnect: vi.fn(),
|
||||
onMenuLocalTerminal: vi.fn(),
|
||||
onMenuImportSessions: vi.fn(),
|
||||
onMenuExportSessions: vi.fn(),
|
||||
onMenuOpenSettings: vi.fn(),
|
||||
onSshLinkAvailable: vi.fn(),
|
||||
respondHostKeyPrompt: vi.fn(),
|
||||
knownHostsList: vi.fn().mockResolvedValue({ success: true, entries: [] }),
|
||||
knownHostsRemove: vi.fn().mockResolvedValue({ success: true }),
|
||||
knownHostsClear: vi.fn().mockResolvedValue({ success: true }),
|
||||
removeListener: vi.fn(),
|
||||
removeAllListeners: vi.fn(),
|
||||
}
|
||||
|
||||
window.electronAPI = mockElectronAPI as unknown as typeof window.electronAPI
|
||||
window.opsxApi = mockDesktopApi
|
||||
|
||||
// Mock navigator
|
||||
Object.defineProperty(window, 'navigator', {
|
||||
value: { platform: 'MacIntel' },
|
||||
writable: true
|
||||
Object.defineProperty(window.navigator, 'platform', {
|
||||
configurable: true,
|
||||
value: 'MacIntel',
|
||||
})
|
||||
|
||||
// Mock ResizeObserver
|
||||
@@ -82,10 +146,18 @@ class ResizeObserverMock {
|
||||
}
|
||||
window.ResizeObserver = ResizeObserverMock
|
||||
|
||||
// XTerm probes canvas support during component smoke tests. jsdom intentionally
|
||||
// does not implement a rendering context, so provide the same null fallback
|
||||
// browsers expose when a context type is unavailable.
|
||||
Object.defineProperty(HTMLCanvasElement.prototype, 'getContext', {
|
||||
configurable: true,
|
||||
value: vi.fn(() => null),
|
||||
})
|
||||
|
||||
// Mock matchMedia
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: vi.fn().mockImplementation(query => ({
|
||||
value: vi.fn().mockImplementation((query) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
@@ -101,10 +173,7 @@ Object.defineProperty(window, 'matchMedia', {
|
||||
const originalError = console.error
|
||||
beforeAll(() => {
|
||||
console.error = (...args: unknown[]) => {
|
||||
if (
|
||||
typeof args[0] === 'string' &&
|
||||
(args[0].includes('Warning:') || args[0].includes('ReactDOM.render'))
|
||||
) {
|
||||
if (typeof args[0] === 'string' && (args[0].includes('Warning:') || args[0].includes('ReactDOM.render'))) {
|
||||
return
|
||||
}
|
||||
originalError.call(console, ...args)
|
||||
|
||||
Reference in new issue
Block a user