#!/bin/bash # # Setup Jest for CLI Testing (Node.js/TypeScript) # # This script installs and configures Jest for testing CLI applications # Includes TypeScript support, coverage reporting, and CLI testing utilities set -e echo "🔧 Setting up Jest for CLI testing..." # Check if npm is available if ! command -v npm &> /dev/null; then echo "❌ Error: npm is not installed" exit 1 fi # Install Jest and related dependencies echo "📦 Installing Jest and dependencies..." npm install --save-dev \ jest \ @types/jest \ ts-jest \ @types/node # Create Jest configuration echo "⚙️ Creating Jest configuration..." cat > jest.config.js << 'EOF' module.exports = { preset: 'ts-jest', testEnvironment: 'node', roots: ['/tests'], testMatch: [ '**/__tests__/**/*.ts', '**/?(*.)+(spec|test).ts' ], collectCoverageFrom: [ 'src/**/*.{ts,js}', '!src/**/*.d.ts', '!src/**/*.test.ts', '!src/**/__tests__/**' ], coverageDirectory: 'coverage', coverageReporters: ['text', 'lcov', 'html'], coverageThresholds: { global: { branches: 70, functions: 70, lines: 70, statements: 70 } }, verbose: true, testTimeout: 10000 }; EOF # Create tests directory structure echo "📁 Creating test directory structure..." mkdir -p tests/{unit,integration,helpers} # Create test helper file echo "📝 Creating test helpers..." cat > tests/helpers/cli-helpers.ts << 'EOF' import { execSync } from 'child_process'; import path from 'path'; export interface CLIResult { stdout: string; stderr: string; code: number; } export const CLI_PATH = path.join(__dirname, '../../bin/cli'); export function runCLI(args: string): CLIResult { try { const stdout = execSync(`${CLI_PATH} ${args}`, { encoding: 'utf8', stdio: 'pipe', }); return { stdout, stderr: '', code: 0 }; } catch (error: any) { return { stdout: error.stdout || '', stderr: error.stderr || '', code: error.status || 1, }; } } EOF # Create sample test file echo "📝 Creating sample test file..." cat > tests/unit/cli.test.ts << 'EOF' import { runCLI } from '../helpers/cli-helpers'; describe('CLI Tests', () => { test('should display version', () => { const { stdout, code } = runCLI('--version'); expect(code).toBe(0); expect(stdout).toMatch(/\d+\.\d+\.\d+/); }); test('should display help', () => { const { stdout, code } = runCLI('--help'); expect(code).toBe(0); expect(stdout).toContain('Usage:'); }); }); EOF # Create TypeScript configuration for tests echo "⚙️ Creating TypeScript configuration..." if [ ! -f tsconfig.json ]; then cat > tsconfig.json << 'EOF' { "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "tests"] } EOF fi # Update package.json scripts echo "⚙️ Updating package.json scripts..." if [ -f package.json ]; then # Check if jq is available for JSON manipulation if command -v jq &> /dev/null; then # Add test scripts using jq tmp=$(mktemp) jq '.scripts.test = "jest" | .scripts["test:watch"] = "jest --watch" | .scripts["test:coverage"] = "jest --coverage" | .scripts["test:ci"] = "jest --ci --coverage --maxWorkers=2"' \ package.json > "$tmp" mv "$tmp" package.json else echo "⚠️ jq not found. Please manually add test scripts to package.json:" echo ' "test": "jest"' echo ' "test:watch": "jest --watch"' echo ' "test:coverage": "jest --coverage"' echo ' "test:ci": "jest --ci --coverage --maxWorkers=2"' fi fi # Create .gitignore entries echo "📝 Updating .gitignore..." if [ -f .gitignore ]; then grep -qxF 'coverage/' .gitignore || echo 'coverage/' >> .gitignore grep -qxF '*.log' .gitignore || echo '*.log' >> .gitignore else cat > .gitignore << 'EOF' node_modules/ dist/ coverage/ *.log .env .env.local EOF fi # Create README for tests echo "📝 Creating test documentation..." cat > tests/README.md << 'EOF' # CLI Tests ## Running Tests ```bash # Run all tests npm test # Run tests in watch mode npm run test:watch # Run tests with coverage npm run test:coverage # Run tests in CI mode npm run test:ci ``` ## Test Structure - `unit/` - Unit tests for individual functions - `integration/` - Integration tests for complete workflows - `helpers/` - Test helper functions and utilities ## Writing Tests Use the `runCLI` helper to execute CLI commands: ```typescript import { runCLI } from '../helpers/cli-helpers'; test('should execute command', () => { const { stdout, stderr, code } = runCLI('command --flag'); expect(code).toBe(0); expect(stdout).toContain('expected output'); }); ``` ## Coverage Coverage reports are generated in the `coverage/` directory. Target: 70% coverage for branches, functions, lines, and statements. EOF echo "✅ Jest setup complete!" echo "" echo "Next steps:" echo " 1. Run 'npm test' to execute tests" echo " 2. Add more tests in tests/unit/ and tests/integration/" echo " 3. Run 'npm run test:coverage' to see coverage report" echo "" echo "📚 Test files created:" echo " - jest.config.js" echo " - tests/helpers/cli-helpers.ts" echo " - tests/unit/cli.test.ts" echo " - tests/README.md"