Files
opsxshell/test/components/connection/forwardRules.test.ts
T
Logan.Li b0d0e3a5f3 feat(i18n): add multi-language support (ja/ko/vi/ru/zh-TW) with system auto-detection
- Extend AppLanguage to 7 locales: zh-CN, zh-TW, en, ja, ko, vi, ru
- Auto-detect system language via navigator.languages; fallback to English
- Add BCP47 locale mapping for date formatting and sorting
- Create 50 translation JSON files (5 languages × 10 namespaces, 1137 keys each)
- Update language selector with native language names
- Extend locale key parity test to cover all 7 languages (70 assertions)
- Add VNC/RDP desktop, serial terminal, AI agent, port forwarding, and SFTP features
- Add credential encryption, host metrics, session backup crypto, and zmodem bridge
- Update Rust backend: desktop services, host metrics, SSH/SFTP enhancements
2026-08-12 00:07:48 +08:00

63 lines
2.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
duplicateForwardRule,
formatTransferBytes,
parseForwardRules,
portForwardStorageKey,
runtimeMap,
} from '../../../src/components/connection/forwardRules'
describe('forward rule persistence', () => {
it('uses stable session ids instead of runtime connection ids', () => {
expect(portForwardStorageKey('saved-1', 'tab-1')).toBe('portForwards_session_saved-1')
expect(portForwardStorageKey(undefined, 'tab-1', 'conn-9')).toBe('portForwards_conn_conn-9')
expect(portForwardStorageKey(undefined, 'tab-1')).toBe('portForwards_tab_tab-1')
})
it('migrates JSON strings and drops runtime state', () => {
const rules = parseForwardRules(
JSON.stringify([
{
id: 'proxy-1',
type: 'dynamic',
name: 'SOCKS5',
localPort: 1080,
isActive: true,
},
])
)
expect(rules).toEqual([{ id: 'proxy-1', type: 'dynamic', name: 'SOCKS5', localPort: 1080 }])
expect(rules[0]).not.toHaveProperty('isActive')
})
it('indexes process-local tunnel status independently', () => {
const map = runtimeMap([
{
forwardId: 'proxy-1',
connectionId: 'conn-1',
kind: 'dynamic',
bindHost: '127.0.0.1',
boundPort: 1080,
startedAt: 1,
running: true,
activeConnections: 2,
bytesUp: 1024,
bytesDown: 2048,
},
])
expect(map.get('proxy-1')?.activeConnections).toBe(2)
expect(formatTransferBytes(1536)).toBe('1.5 KB')
})
it('duplicates configuration with a fresh id and no runtime state', () => {
const original = { id: 'proxy-1', type: 'dynamic' as const, name: 'SOCKS5', localPort: 1080 }
const first = duplicateForwardRule(original, [original], 'proxy-2')
const second = duplicateForwardRule(original, [original, first], 'proxy-3')
expect(first).toEqual({ ...original, id: 'proxy-2', name: 'SOCKS5 副本' })
expect(second.name).toBe('SOCKS5 副本 2')
expect(second).not.toHaveProperty('isActive')
})
})