mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 20:17:45 +00:00
Add 26 new unit tests covering: - isFirstTimeInstall() legacy config detection (8 tests) - loadSettingsFromFile() path expansion (5 tests) - ProfileDetector detectProfileType() (4 tests) - expandPath() cross-platform handling (10 tests) Test coverage for issue #195: - Legacy config.json/profiles.json detection - Tilde expansion to home directory - Environment variable expansion (${VAR}, $VAR, %VAR%) - Mixed path separator normalization - Corrupted config graceful handling Files: - tests/unit/commands/setup-command.test.ts - tests/unit/auth/profile-detector.test.ts - tests/unit/utils/expand-path.test.ts
134 lines
4.5 KiB
TypeScript
134 lines
4.5 KiB
TypeScript
/**
|
|
* Unit tests for setup-command.ts - isFirstTimeInstall() function
|
|
*
|
|
* Issue #195: GLM auth regression - isFirstTimeInstall() was ignoring legacy configs
|
|
*/
|
|
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as os from 'os';
|
|
|
|
// Create temp directory for test isolation
|
|
let testDir: string;
|
|
|
|
beforeEach(() => {
|
|
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-test-'));
|
|
});
|
|
|
|
afterEach(() => {
|
|
fs.rmSync(testDir, { recursive: true, force: true });
|
|
});
|
|
|
|
// Helper to create config files
|
|
function createConfigYaml(content: string): void {
|
|
fs.writeFileSync(path.join(testDir, 'config.yaml'), content, 'utf8');
|
|
}
|
|
|
|
function createConfigJson(content: object): void {
|
|
fs.writeFileSync(path.join(testDir, 'config.json'), JSON.stringify(content, null, 2), 'utf8');
|
|
}
|
|
|
|
function createProfilesJson(content: object): void {
|
|
fs.writeFileSync(path.join(testDir, 'profiles.json'), JSON.stringify(content, null, 2), 'utf8');
|
|
}
|
|
|
|
describe('isFirstTimeInstall logic', () => {
|
|
describe('legacy config detection', () => {
|
|
it('should detect legacy config.json with profiles', () => {
|
|
createConfigYaml('version: 2\nprofiles: {}\naccounts: {}');
|
|
createConfigJson({ profiles: { glm: '~/.ccs/glm.settings.json' } });
|
|
|
|
const legacyConfig = JSON.parse(fs.readFileSync(path.join(testDir, 'config.json'), 'utf8'));
|
|
const hasLegacyProfiles = legacyConfig.profiles && Object.keys(legacyConfig.profiles).length > 0;
|
|
|
|
expect(hasLegacyProfiles).toBe(true);
|
|
});
|
|
|
|
it('should detect legacy profiles.json with accounts', () => {
|
|
createConfigYaml('version: 2\nprofiles: {}\naccounts: {}');
|
|
createProfilesJson({ profiles: { work: { path: '/some/path' } } });
|
|
|
|
const legacyProfiles = JSON.parse(fs.readFileSync(path.join(testDir, 'profiles.json'), 'utf8'));
|
|
const hasLegacyAccounts = legacyProfiles.profiles && Object.keys(legacyProfiles.profiles).length > 0;
|
|
|
|
expect(hasLegacyAccounts).toBe(true);
|
|
});
|
|
|
|
it('should return true when no configs exist', () => {
|
|
const hasConfigYaml = fs.existsSync(path.join(testDir, 'config.yaml'));
|
|
const hasConfigJson = fs.existsSync(path.join(testDir, 'config.json'));
|
|
const hasProfilesJson = fs.existsSync(path.join(testDir, 'profiles.json'));
|
|
|
|
expect(hasConfigYaml).toBe(false);
|
|
expect(hasConfigJson).toBe(false);
|
|
expect(hasProfilesJson).toBe(false);
|
|
});
|
|
|
|
it('should detect unified config with profiles', () => {
|
|
createConfigYaml(`
|
|
version: 2
|
|
profiles:
|
|
glm:
|
|
type: api
|
|
settings: ~/.ccs/glm.settings.json
|
|
accounts: {}
|
|
`);
|
|
|
|
const content = fs.readFileSync(path.join(testDir, 'config.yaml'), 'utf8');
|
|
const hasProfiles = content.includes('glm:') && content.includes('type: api');
|
|
|
|
expect(hasProfiles).toBe(true);
|
|
});
|
|
|
|
it('should detect unified config with remote proxy', () => {
|
|
createConfigYaml(`
|
|
version: 2
|
|
profiles: {}
|
|
accounts: {}
|
|
cliproxy_server:
|
|
remote:
|
|
enabled: true
|
|
host: my-server.example.com
|
|
`);
|
|
|
|
const content = fs.readFileSync(path.join(testDir, 'config.yaml'), 'utf8');
|
|
const hasRemoteProxy = content.includes('enabled: true') && content.includes('host:');
|
|
|
|
expect(hasRemoteProxy).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('empty config handling', () => {
|
|
it('should treat empty configs as first-time', () => {
|
|
createConfigYaml('version: 2\nprofiles: {}\naccounts: {}');
|
|
createConfigJson({ profiles: {} });
|
|
createProfilesJson({ profiles: {} });
|
|
|
|
const legacyConfig = JSON.parse(fs.readFileSync(path.join(testDir, 'config.json'), 'utf8'));
|
|
const legacyProfiles = JSON.parse(fs.readFileSync(path.join(testDir, 'profiles.json'), 'utf8'));
|
|
|
|
const hasLegacyProfiles = Object.keys(legacyConfig.profiles || {}).length > 0;
|
|
const hasLegacyAccounts = Object.keys(legacyProfiles.profiles || {}).length > 0;
|
|
|
|
expect(hasLegacyProfiles).toBe(false);
|
|
expect(hasLegacyAccounts).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('corrupted config handling', () => {
|
|
it('should handle corrupted config.json gracefully', () => {
|
|
fs.writeFileSync(path.join(testDir, 'config.json'), 'not valid json{{{', 'utf8');
|
|
|
|
let hasLegacyProfiles = false;
|
|
try {
|
|
const legacyConfig = JSON.parse(fs.readFileSync(path.join(testDir, 'config.json'), 'utf8'));
|
|
hasLegacyProfiles = legacyConfig.profiles && Object.keys(legacyConfig.profiles).length > 0;
|
|
} catch {
|
|
hasLegacyProfiles = false;
|
|
}
|
|
|
|
expect(hasLegacyProfiles).toBe(false);
|
|
});
|
|
});
|
|
});
|