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
@@ -0,0 +1,26 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { mockDesktopApi } from '../setup'
|
||||
import { useAiProviderStore } from '../../src/stores/aiProviderStore'
|
||||
|
||||
describe('AI provider store secret boundary', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
useAiProviderStore.setState({
|
||||
providers: [],
|
||||
activeProviderId: '',
|
||||
isLoaded: true,
|
||||
catalogProviders: [],
|
||||
catalogUpdatedAt: null,
|
||||
})
|
||||
})
|
||||
|
||||
it('saves API keys through Rust and never writes them to normal settings', async () => {
|
||||
const providerId = await useAiProviderStore.getState().addPreset('deepseek')
|
||||
const provider = useAiProviderStore.getState().providers.find((item) => item.id === providerId)!
|
||||
await useAiProviderStore.getState().saveProvider(provider, 'sk-very-secret')
|
||||
|
||||
expect(mockDesktopApi.aiProviderSaveKey).toHaveBeenCalledWith(providerId, 'sk-very-secret')
|
||||
const settingsPayloads = vi.mocked(mockDesktopApi.settingsSet).mock.calls.map((call) => call[1])
|
||||
expect(JSON.stringify(settingsPayloads)).not.toContain('sk-very-secret')
|
||||
})
|
||||
})
|
||||
@@ -35,14 +35,14 @@ describe('KeybindingStore', () => {
|
||||
expect(state.isLoaded).toBe(false)
|
||||
})
|
||||
|
||||
it('loadFromSettings 应从 electronAPI 加载自定义快捷键', async () => {
|
||||
it('loadFromSettings 应从 opsxApi 加载自定义快捷键', async () => {
|
||||
const customData = {
|
||||
[KeybindingAction.TAB_CLOSE]: 'Ctrl+Q',
|
||||
[KeybindingAction.TAB_NEW]: 'Ctrl+T',
|
||||
}
|
||||
|
||||
// Mock electronAPI 返回自定义快捷键
|
||||
vi.mocked(window.electronAPI.settingsGet).mockResolvedValueOnce({
|
||||
// Mock opsxApi 返回自定义快捷键
|
||||
vi.mocked(window.opsxApi.settingsGet).mockResolvedValueOnce({
|
||||
success: true,
|
||||
value: customData,
|
||||
})
|
||||
@@ -55,7 +55,7 @@ describe('KeybindingStore', () => {
|
||||
})
|
||||
|
||||
it('loadFromSettings 无保存数据时应使用空自定义', async () => {
|
||||
vi.mocked(window.electronAPI.settingsGet).mockResolvedValueOnce({
|
||||
vi.mocked(window.opsxApi.settingsGet).mockResolvedValueOnce({
|
||||
success: false,
|
||||
})
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('KeybindingStore', () => {
|
||||
})
|
||||
|
||||
it('loadFromSettings API 报错时应安全降级', async () => {
|
||||
vi.mocked(window.electronAPI.settingsGet).mockRejectedValueOnce(new Error('API error'))
|
||||
vi.mocked(window.opsxApi.settingsGet).mockRejectedValueOnce(new Error('API error'))
|
||||
|
||||
await useKeybindingStore.getState().loadFromSettings()
|
||||
|
||||
@@ -121,7 +121,7 @@ describe('KeybindingStore', () => {
|
||||
expect(state.customKeybindings[KeybindingAction.TAB_CLOSE]).toBe('Ctrl+Q')
|
||||
|
||||
// 应调用 settingsSet 持久化
|
||||
expect(window.electronAPI.settingsSet).toHaveBeenCalledWith(
|
||||
expect(window.opsxApi.settingsSet).toHaveBeenCalledWith(
|
||||
'keybindings',
|
||||
{ [KeybindingAction.TAB_CLOSE]: 'Ctrl+Q' }
|
||||
)
|
||||
@@ -142,7 +142,7 @@ describe('KeybindingStore', () => {
|
||||
expect(state.customKeybindings[KeybindingAction.TAB_NEW]).toBe('Ctrl+T')
|
||||
|
||||
// 第二次调用应包含两个
|
||||
const lastCall = vi.mocked(window.electronAPI.settingsSet).mock.calls.at(-1)
|
||||
const lastCall = vi.mocked(window.opsxApi.settingsSet).mock.calls.at(-1)
|
||||
expect(lastCall?.[1]).toEqual({
|
||||
[KeybindingAction.TAB_CLOSE]: 'Ctrl+Q',
|
||||
[KeybindingAction.TAB_NEW]: 'Ctrl+T',
|
||||
@@ -190,7 +190,7 @@ describe('KeybindingStore', () => {
|
||||
|
||||
const state = useKeybindingStore.getState()
|
||||
expect(state.customKeybindings).toEqual({})
|
||||
expect(window.electronAPI.settingsSet).toHaveBeenCalledWith('keybindings', {})
|
||||
expect(window.opsxApi.settingsSet).toHaveBeenCalledWith('keybindings', {})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { usePoolStore } from '../../src/stores/connection/poolStore'
|
||||
import type { PooledConnection } from '../../src/stores/connection/types'
|
||||
|
||||
function connection(connectionId: string): PooledConnection {
|
||||
return {
|
||||
connectionId,
|
||||
config: { host: 'opsbase.cn', port: 55555, username: 'root' },
|
||||
state: 'connected',
|
||||
refCount: 1,
|
||||
tabIds: new Set(['tab-a']),
|
||||
activeTabId: 'tab-a',
|
||||
shellIds: new Set(['shell-a']),
|
||||
sftpIds: new Set(),
|
||||
stats: { connectedAt: Date.now(), lastActivityAt: Date.now(), bytesTransferred: 0, commandsExecuted: 0 },
|
||||
keepaliveInterval: 1,
|
||||
reconnectAttempts: 0,
|
||||
maxReconnectAttempts: 3,
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => usePoolStore.setState({ connections: new Map() }))
|
||||
|
||||
describe('native connection close', () => {
|
||||
it('removes the stale renderer connection without another SSH disconnect', () => {
|
||||
const clearIntervalSpy = vi.spyOn(window, 'clearInterval')
|
||||
usePoolStore.setState({ connections: new Map([['native-gone', connection('native-gone')]]) })
|
||||
|
||||
usePoolStore.getState().forgetNativeConnection('native-gone')
|
||||
|
||||
expect(usePoolStore.getState().connections.has('native-gone')).toBe(false)
|
||||
expect(clearIntervalSpy).toHaveBeenCalled()
|
||||
clearIntervalSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { normalizeAppSettings } from '../../src/stores/settingsStore'
|
||||
|
||||
describe('settings migration', () => {
|
||||
it('drops obsolete legacy settings while preserving supported values', () => {
|
||||
const settings = normalizeAppSettings({
|
||||
theme: 'light',
|
||||
timeout: 45,
|
||||
language: 'en-US',
|
||||
showNotifications: true,
|
||||
encryptPasswords: false,
|
||||
lockOnSleep: true,
|
||||
})
|
||||
|
||||
expect(settings.theme).toBe('light')
|
||||
expect(settings.timeout).toBe(45)
|
||||
expect(settings).not.toHaveProperty('language')
|
||||
expect(settings).not.toHaveProperty('showNotifications')
|
||||
expect(settings).not.toHaveProperty('encryptPasswords')
|
||||
expect(settings).not.toHaveProperty('lockOnSleep')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user