/** * Jest Integration Test Template * * Test complete CLI workflows with multiple commands and state persistence */ import { execSync } from 'child_process'; import fs from 'fs'; import path from 'path'; import os from 'os'; describe('CLI Integration Tests', () => { const CLI_PATH = path.join(__dirname, '../bin/mycli'); const TEST_WORKSPACE = path.join(os.tmpdir(), 'cli-integration-test'); function runCLI(args: string, cwd: string = TEST_WORKSPACE): { stdout: string; stderr: string; code: number; } { try { const stdout = execSync(`${CLI_PATH} ${args}`, { encoding: 'utf8', stdio: 'pipe', cwd, }); return { stdout, stderr: '', code: 0 }; } catch (error: any) { return { stdout: error.stdout || '', stderr: error.stderr || '', code: error.status || 1, }; } } beforeEach(() => { // Create clean test workspace if (fs.existsSync(TEST_WORKSPACE)) { fs.rmSync(TEST_WORKSPACE, { recursive: true, force: true }); } fs.mkdirSync(TEST_WORKSPACE, { recursive: true }); }); afterEach(() => { // Clean up test workspace if (fs.existsSync(TEST_WORKSPACE)) { fs.rmSync(TEST_WORKSPACE, { recursive: true, force: true }); } }); describe('complete deployment workflow', () => { test('should initialize, configure, and deploy', () => { // Step 1: Initialize project const init = runCLI('init my-project'); expect(init.code).toBe(0); expect(init.stdout).toContain('Project initialized'); // Step 2: Configure deployment const config = runCLI('config set api_key test_key_123'); expect(config.code).toBe(0); // Step 3: Build project const build = runCLI('build --production'); expect(build.code).toBe(0); expect(build.stdout).toContain('Build successful'); // Step 4: Deploy const deploy = runCLI('deploy production'); expect(deploy.code).toBe(0); expect(deploy.stdout).toContain('Deployed successfully'); // Verify deployment artifacts const deployFile = path.join(TEST_WORKSPACE, '.deploy'); expect(fs.existsSync(deployFile)).toBe(true); }); test('should fail deployment without configuration', () => { runCLI('init my-project'); // Try to deploy without configuring API key const { stderr, code } = runCLI('deploy production'); expect(code).toBe(1); expect(stderr).toContain('API key not configured'); }); }); describe('multi-environment workflow', () => { test('should manage multiple environments', () => { // Initialize project runCLI('init my-project'); // Configure development environment runCLI('config set api_key dev_key_123 --env development'); runCLI('config set base_url https://dev.example.com --env development'); // Configure production environment runCLI('config set api_key prod_key_123 --env production'); runCLI('config set base_url https://api.example.com --env production'); // Deploy to development const devDeploy = runCLI('deploy development'); expect(devDeploy.code).toBe(0); expect(devDeploy.stdout).toContain('dev.example.com'); // Deploy to production const prodDeploy = runCLI('deploy production'); expect(prodDeploy.code).toBe(0); expect(prodDeploy.stdout).toContain('api.example.com'); }); }); describe('state persistence workflow', () => { test('should persist and restore state', () => { // Create initial state runCLI('state set counter 0'); // Increment counter multiple times runCLI('increment'); runCLI('increment'); runCLI('increment'); // Verify final state const { stdout } = runCLI('state get counter'); expect(stdout).toContain('3'); }); test('should handle state file corruption', () => { runCLI('state set key value'); // Corrupt state file const stateFile = path.join(TEST_WORKSPACE, '.state'); fs.writeFileSync(stateFile, 'invalid json {[}'); // Should recover gracefully const { stderr, code } = runCLI('state get key'); expect(code).toBe(1); expect(stderr).toContain('Corrupted state file'); }); }); describe('plugin workflow', () => { test('should install and use plugins', () => { // Initialize project runCLI('init my-project'); // Install plugin const install = runCLI('plugin install my-plugin'); expect(install.code).toBe(0); // Verify plugin is listed const list = runCLI('plugin list'); expect(list.stdout).toContain('my-plugin'); // Use plugin command const usePlugin = runCLI('my-plugin:command'); expect(usePlugin.code).toBe(0); // Uninstall plugin const uninstall = runCLI('plugin uninstall my-plugin'); expect(uninstall.code).toBe(0); // Verify plugin is removed const listAfter = runCLI('plugin list'); expect(listAfter.stdout).not.toContain('my-plugin'); }); }); describe('error recovery workflow', () => { test('should recover from partial failure', () => { runCLI('init my-project'); // Simulate partial deployment failure runCLI('deploy staging --force'); // Should be able to rollback const rollback = runCLI('rollback'); expect(rollback.code).toBe(0); expect(rollback.stdout).toContain('Rollback successful'); // Should be able to retry const retry = runCLI('deploy staging --retry'); expect(retry.code).toBe(0); }); }); describe('concurrent operations', () => { test('should handle file locking', async () => { runCLI('init my-project'); // Start long-running operation const longOp = execSync(`${CLI_PATH} long-running-task &`, { cwd: TEST_WORKSPACE, }); // Try to run another operation that needs lock const { stderr, code } = runCLI('another-task'); expect(code).toBe(1); expect(stderr).toContain('Another operation in progress'); }); }); describe('data migration workflow', () => { test('should migrate data between versions', () => { // Create old version data const oldData = { version: 1, data: 'legacy format' }; fs.writeFileSync( path.join(TEST_WORKSPACE, 'data.json'), JSON.stringify(oldData) ); // Run migration const migrate = runCLI('migrate --to 2.0'); expect(migrate.code).toBe(0); // Verify new format const newData = JSON.parse( fs.readFileSync(path.join(TEST_WORKSPACE, 'data.json'), 'utf8') ); expect(newData.version).toBe(2); }); }); });