Files
zclaw_openfang/desktop/tests/toml-utils.test.ts
iven 3e81bd3e50 feat(ui): Phase 8 UI/UX optimization and system documentation update
## Sidebar Enhancement
- Change tabs to icon + small label layout for better space utilization
- Add Teams tab with team collaboration entry point

## Settings Page Improvements
- Connect theme toggle to gatewayStore.saveQuickConfig for persistence
- Remove OpenFang backend download section, simplify UI
- Add time range filter to UsageStats (7d/30d/all)
- Add stat cards with icons (sessions, messages, input/output tokens)
- Add token usage overview bar chart
- Add 8 ZCLAW system skill definitions with categories

## Bug Fixes
- Fix ChannelList duplicate content with deduplication logic
- Integrate CreateTriggerModal in TriggersPanel
- Add independent SecurityStatusPanel with 12 default enabled layers
- Change workflow view to use SchedulerPanel as unified entry

## New Components
- CreateTriggerModal: Event trigger creation modal
- HandApprovalModal: Hand approval workflow dialog
- HandParamsForm: Enhanced Hand parameter form
- SecurityLayersPanel: 16-layer security status display

## Architecture
- Add TOML config parsing support (toml-utils.ts, config-parser.ts)
- Add request timeout and retry mechanism (request-helper.ts)
- Add secure token storage (secure-storage.ts, secure_storage.rs)

## Tests
- Add unit tests for config-parser, toml-utils, request-helper
- Add team-client and teamStore tests

## Documentation
- Update SYSTEM_ANALYSIS.md with Phase 8 completion
- UI completion: 100% (30/30 components)
- API coverage: 93% (63/68 endpoints)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 14:12:11 +08:00

170 lines
4.3 KiB
TypeScript

/**
* TOML Utility Tests
*
* Tests for TOML parsing and configuration handling.
*/
import { describe, it, expect } from 'vitest';
import { tomlUtils, TomlParseError, TomlStringifyError } from '../src/lib/toml-utils';
describe('tomlUtils', () => {
describe('parse', () => {
it('should parse basic TOML correctly', () => {
const toml = `
[server]
host = "127.0.0.1"
port = 4200
`;
const result = tomlUtils.parse(toml);
expect(result).toEqual({
server: {
host: '127.0.0.1',
port: 4200,
},
});
});
it('should parse nested tables correctly', () => {
const toml = `
[server]
host = "127.0.0.1"
[server.websocket]
port = 8080
path = "/ws"
`;
const result = tomlUtils.parse(toml);
expect(result).toEqual({
server: {
host: '127.0.0.1',
websocket: {
port: 8080,
path: '/ws',
},
},
});
});
it('should parse arrays correctly', () => {
const toml = `
[[servers]]
name = "primary"
port = 4200
[[servers]]
name = "secondary"
port = 4201
`;
const result = tomlUtils.parse(toml);
expect(result).toEqual({
servers: [
{ name: 'primary', port: 4200 },
{ name: 'secondary', port: 4201 },
],
});
});
it('should throw TomlParseError on invalid TOML', () => {
const invalidToml = `
[invalid
key = value
`;
expect(() => tomlUtils.parse(invalidToml)).toThrow(TomlParseError);
});
});
describe('stringify', () => {
it('should stringify basic objects correctly', () => {
const data = {
server: {
host: '127.0.0.1',
port: 4200,
},
};
const result = tomlUtils.stringify(data);
expect(result).toContain('host = "127.0.0.1"');
expect(result).toContain('port = 4200');
});
it('should throw TomlStringifyError on invalid data', () => {
const circularData: Record<string, unknown> = { self: {} };
circularData.self = circularData;
expect(() => tomlUtils.stringify(circularData)).toThrow(TomlStringifyError);
});
});
describe('resolveEnvVars', () => {
it('should resolve environment variables', () => {
const content = 'api_key = "${API_KEY}"';
const envVars = { API_KEY: 'secret-key-123' };
const result = tomlUtils.resolveEnvVars(content, envVars);
expect(result).toBe('api_key = "secret-key-123"');
});
it('should return empty string for missing env vars', () => {
const content = 'api_key = "${MISSING_VAR}"';
const result = tomlUtils.resolveEnvVars(content);
expect(result).toBe('api_key = ""');
});
it('should handle multiple env vars', () => {
const content = `
key1 = "${VAR1}"
key2 = "${VAR2}"
`;
const envVars = { VAR1: 'value1', VAR2: 'value2' };
const result = tomlUtils.resolveEnvVars(content, envVars);
expect(result).toContain('key1 = "value1"');
expect(result).toContain('key2 = "value2"');
});
});
describe('parseWithEnvVars', () => {
it('should parse TOML with env var resolution', () => {
const content = `
[config]
api_key = "${API_KEY}"
model = "gpt-4"
`;
const envVars = { API_KEY: 'test-key-456' };
const result = tomlUtils.parseWithEnvVars(content, envVars);
expect(result).toEqual({
config: {
api_key: 'test-key-456',
model: 'gpt-4',
},
});
});
});
describe('hasUnresolvedEnvVars', () => {
it('should return true when env vars are present', () => {
const content = 'api_key = "${API_KEY}"';
expect(tomlUtils.hasUnresolvedEnvVars(content)).toBe(true);
});
it('should return false when no env vars', () => {
const content = 'api_key = "hardcoded-key"';
expect(tomlUtils.hasUnresolvedEnvVars(content)).toBe(false);
});
});
describe('extractEnvVarNames', () => {
it('should extract all env var names', () => {
const content = `
key1 = "${VAR1}"
key2 = "${VAR2}"
key1 = "${VAR1}"
`;
const result = tomlUtils.extractEnvVarNames(content);
expect(result).toEqual(['VAR1', 'VAR2']);
});
it('should return empty array for no env vars', () => {
const content = 'key = "value"';
expect(tomlUtils.extractEnvVarNames(content)).toEqual([]);
});
});
});