Files
opencode-openai-codex-auth/test/config.test.ts
T
Numman AliandHanzo Dev 7dae285752 feat: Major TypeScript rewrite with enhanced configuration and OAuth UI
## 🎯 Overview

Complete TypeScript rewrite with comprehensive testing, modular architecture,
and enhanced user experience. Adds 9 pre-configured model variants matching
Codex CLI presets and a beautiful OAuth success page.

## ✨ New Features

### Configuration System
- **9 Model Variants**: Pre-configured reasoning levels (Low/Medium/High) for
  both gpt-5-codex and gpt-5, plus Minimal variants
- **Full Config Example**: `config/full-opencode.json` with all variants ready
  to use
- **Minimal Config Example**: `config/minimal-opencode.json` for basic setup
- **Config Documentation**: Comprehensive guide in `config/README.md`

### OAuth Enhancement
- **Animated Success Page**: Beautiful terminal-style UI with matrix rain
  effect, animated checkmark, and glowing effects
- **Interactive Elements**: Mouse-responsive matrix rain and parallax effects
- **Professional Branding**: OpenCode logo with pulse animations

### Developer Experience
- **TypeScript Rewrite**: Complete migration from .mjs to .ts with strict typing
- **93 Comprehensive Tests**: Full test coverage using Vitest
- **Modular Architecture**: 10 focused helper functions, each < 40 lines
- **Centralized Constants**: All magic values in `lib/constants.ts`
- **CI/CD Pipeline**: GitHub Actions workflow for automated testing

### Documentation
- **AGENTS.md**: Complete guide for AI assistants maintaining the codebase
- **Enhanced README**: Updated with new configuration options and examples
- **Inline JSDoc**: Comprehensive documentation for all public functions

## 🏗️ Technical Changes

### Architecture Improvements
- Extracted 10 focused helper functions from monolithic fetch()
- Centralized all constants and error messages
- Separated concerns: auth, browser, codex, server, etc.
- Type-safe discriminated unions for result types

### Build System
- TypeScript compilation with declarations and source maps
- Automatic HTML asset copying in build process
- Test files excluded from distribution bundle
- Clean dist/ output with only production code

### Testing Infrastructure
- Vitest test runner with UI mode
- 93 tests across 7 test files
- Mock-based testing for external dependencies
- Coverage reporting capability

## 📁 New Structure

```
opencode-openai-codex-auth/
├── index.ts                     # Main plugin (TypeScript)
├── lib/
│   ├── auth.ts                 # OAuth logic
│   ├── browser.ts              # Platform-specific browser opening
│   ├── codex.ts                # Codex instructions
│   ├── server.ts               # OAuth callback server
│   ├── fetch-helpers.ts        # 10 focused helpers
│   ├── constants.ts            # All magic values
│   ├── types.ts                # TypeScript types
│   ├── oauth-success.html      # Animated success page
│   └── ...
├── config/
│   ├── full-opencode.json      # Complete config with variants
│   ├── minimal-opencode.json   # Basic config
│   └── README.md               # Config docs
├── test/                        # 93 comprehensive tests
├── AGENTS.md                    # AI maintenance guide
└── tsconfig.json               # TypeScript config
```

## 🔄 Migration Notes

### Breaking Changes
- Plugin now requires TypeScript compilation (dist/ folder)
- Configuration structure enhanced (backward compatible)
- OAuth success page replaces plain HTML response

### Upgrade Path
1. Use new config from `config/full-opencode.json` for best experience
2. Or continue with minimal config (uses plugin defaults)
3. Rebuild plugin: `npm run build`

## 📊 Metrics

- **Lines of Code**: Modular design with functions < 70 lines
- **Test Coverage**: 93 tests covering all functionality
- **Type Safety**: Strict TypeScript with no `any` types
- **Dependencies**: Still minimal (only @openauthjs/openauth)
- **Model Variants**: 9 pre-configured options for users

## 🎨 User Experience

- **Codex CLI Parity**: Match official CLI reasoning presets
- **Beautiful OAuth**: Professional animated success page
- **Clear Documentation**: Step-by-step guides and examples
- **Flexible Config**: From minimal to comprehensive setups

Co-authored-by: Hanzo Dev <[email protected]>
2025-10-03 21:51:59 +01:00

128 lines
4.3 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { getModelConfig, getReasoningConfig } from '../lib/request-transformer.js';
import type { UserConfig } from '../lib/types.js';
describe('Configuration Parsing', () => {
const providerConfig = {
options: {
reasoningEffort: 'medium' as const,
reasoningSummary: 'auto' as const,
textVerbosity: 'medium' as const,
},
models: {
'gpt-5-codex': {
options: {
reasoningSummary: 'concise' as const,
},
},
'gpt-5': {
options: {
reasoningEffort: 'high' as const,
},
},
},
};
const userConfig: UserConfig = {
global: providerConfig.options || {},
models: providerConfig.models || {},
};
describe('getModelConfig', () => {
it('should merge global and model-specific config for gpt-5-codex', () => {
const codexConfig = getModelConfig('gpt-5-codex', userConfig);
expect(codexConfig.reasoningEffort).toBe('medium'); // from global
expect(codexConfig.reasoningSummary).toBe('concise'); // from model override
expect(codexConfig.textVerbosity).toBe('medium'); // from global
});
it('should merge global and model-specific config for gpt-5', () => {
const gpt5Config = getModelConfig('gpt-5', userConfig);
expect(gpt5Config.reasoningEffort).toBe('high'); // from model override
expect(gpt5Config.reasoningSummary).toBe('auto'); // from global
expect(gpt5Config.textVerbosity).toBe('medium'); // from global
});
it('should return empty config when no config provided', () => {
const emptyConfig = getModelConfig('gpt-5-codex', { global: {}, models: {} });
expect(emptyConfig).toEqual({});
});
});
describe('getReasoningConfig', () => {
it('should use user settings from merged config for gpt-5-codex', () => {
const codexConfig = getModelConfig('gpt-5-codex', userConfig);
const reasoningConfig = getReasoningConfig('gpt-5-codex', codexConfig);
expect(reasoningConfig.effort).toBe('medium');
expect(reasoningConfig.summary).toBe('concise');
});
it('should return defaults when no config provided', () => {
const emptyConfig = getModelConfig('gpt-5-codex', { global: {}, models: {} });
const defaultReasoning = getReasoningConfig('gpt-5-codex', emptyConfig);
expect(defaultReasoning.effort).toBe('medium');
expect(defaultReasoning.summary).toBe('auto');
});
it('should use minimal effort for lightweight models (nano/mini)', () => {
const nanoReasoning = getReasoningConfig('gpt-5-nano', {});
expect(nanoReasoning.effort).toBe('minimal');
expect(nanoReasoning.summary).toBe('auto');
});
it('should normalize "minimal" to "low" for gpt-5-codex', () => {
const codexMinimalConfig = { reasoningEffort: 'minimal' as const };
const codexMinimalReasoning = getReasoningConfig('gpt-5-codex', codexMinimalConfig);
expect(codexMinimalReasoning.effort).toBe('low');
expect(codexMinimalReasoning.summary).toBe('auto');
});
it('should preserve "minimal" effort for non-codex models', () => {
const gpt5MinimalConfig = { reasoningEffort: 'minimal' as const };
const gpt5MinimalReasoning = getReasoningConfig('gpt-5', gpt5MinimalConfig);
expect(gpt5MinimalReasoning.effort).toBe('minimal');
});
it('should handle high effort setting', () => {
const highConfig = { reasoningEffort: 'high' as const };
const highReasoning = getReasoningConfig('gpt-5', highConfig);
expect(highReasoning.effort).toBe('high');
expect(highReasoning.summary).toBe('auto');
});
it('should respect custom summary setting', () => {
const detailedConfig = { reasoningSummary: 'detailed' as const };
const detailedReasoning = getReasoningConfig('gpt-5-codex', detailedConfig);
expect(detailedReasoning.summary).toBe('detailed');
});
});
describe('Model-specific behavior', () => {
it('should detect lightweight models correctly', () => {
const miniReasoning = getReasoningConfig('gpt-5-mini', {});
expect(miniReasoning.effort).toBe('minimal');
});
it('should detect codex models correctly', () => {
const codexConfig = { reasoningEffort: 'minimal' as const };
const codexReasoning = getReasoningConfig('gpt-5-codex', codexConfig);
expect(codexReasoning.effort).toBe('low'); // normalized
});
it('should handle standard gpt-5 model', () => {
const gpt5Reasoning = getReasoningConfig('gpt-5', {});
expect(gpt5Reasoning.effort).toBe('medium');
});
});
});