224 lines
6.6 KiB
TypeScript
224 lines
6.6 KiB
TypeScript
/**
|
|
* 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);
|
|
});
|
|
});
|
|
});
|