219 lines
7.7 KiB
JavaScript
219 lines
7.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Integration tests for toggle+apply idempotency
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { exec } = require('child_process');
|
|
const { promisify } = require('util');
|
|
|
|
const execAsync = promisify(exec);
|
|
|
|
// Change to project directory for tests
|
|
process.chdir(__dirname);
|
|
|
|
const TEST_CONFIG = 'test-integration.yml';
|
|
const TEST_OUTPUT_DIR = '.test-awesome-copilot';
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) {
|
|
throw new Error(`Assertion failed: ${message}`);
|
|
}
|
|
}
|
|
|
|
function cleanup() {
|
|
// Remove test files
|
|
if (fs.existsSync(TEST_CONFIG)) fs.unlinkSync(TEST_CONFIG);
|
|
if (fs.existsSync(TEST_OUTPUT_DIR)) {
|
|
fs.rmSync(TEST_OUTPUT_DIR, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
async function runCommand(command) {
|
|
try {
|
|
const { stdout, stderr } = await execAsync(command);
|
|
return { success: true, stdout, stderr };
|
|
} catch (error) {
|
|
return { success: false, stdout: error.stdout, stderr: error.stderr, error };
|
|
}
|
|
}
|
|
|
|
function getFilesList(dir) {
|
|
if (!fs.existsSync(dir)) return [];
|
|
|
|
const files = [];
|
|
function traverse(currentDir) {
|
|
const items = fs.readdirSync(currentDir);
|
|
for (const item of items) {
|
|
const fullPath = path.join(currentDir, item);
|
|
if (fs.statSync(fullPath).isDirectory()) {
|
|
traverse(fullPath);
|
|
} else {
|
|
files.push(path.relative(dir, fullPath));
|
|
}
|
|
}
|
|
}
|
|
traverse(dir);
|
|
return files.sort();
|
|
}
|
|
|
|
function setTestOutputDir(configFile) {
|
|
let configContent = fs.readFileSync(configFile, 'utf8');
|
|
configContent = configContent.replace('output_directory: ".awesome-copilot"', `output_directory: "${TEST_OUTPUT_DIR}"`);
|
|
fs.writeFileSync(configFile, configContent);
|
|
}
|
|
|
|
async function runTests() {
|
|
console.log('Running integration tests for toggle+apply idempotency...\n');
|
|
|
|
let passedTests = 0;
|
|
let totalTests = 0;
|
|
|
|
async function test(name, testFn) {
|
|
totalTests++;
|
|
cleanup(); // Clean up before each test
|
|
|
|
try {
|
|
await testFn();
|
|
console.log(`✅ ${name}`);
|
|
passedTests++;
|
|
} catch (error) {
|
|
console.log(`❌ ${name}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
// Test 1: Basic toggle+apply idempotency
|
|
await test("Basic toggle+apply idempotency", async () => {
|
|
// Create initial config
|
|
const result1 = await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
assert(result1.success, 'Should create initial config');
|
|
setTestOutputDir(TEST_CONFIG);
|
|
|
|
// Enable a collection
|
|
const result2 = await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
assert(result2.success, 'Should enable collection');
|
|
|
|
// First apply
|
|
const result3 = await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
assert(result3.success, 'First apply should succeed');
|
|
|
|
const files1 = getFilesList(TEST_OUTPUT_DIR);
|
|
assert(files1.length > 0, 'Should have copied files');
|
|
|
|
// Second apply (idempotency test)
|
|
const result4 = await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
assert(result4.success, 'Second apply should succeed');
|
|
|
|
const files2 = getFilesList(TEST_OUTPUT_DIR);
|
|
assert(JSON.stringify(files1) === JSON.stringify(files2), 'File lists should be identical');
|
|
});
|
|
|
|
// Test 2: Toggle collection off then on restores same state
|
|
await test("Toggle collection off then on restores same state", async () => {
|
|
// Create initial config and enable collection
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
|
|
// First apply
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
const files1 = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Toggle collection off
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation off --config ${TEST_CONFIG}`);
|
|
|
|
// Apply (should remove files)
|
|
fs.rmSync(TEST_OUTPUT_DIR, { recursive: true, force: true });
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
const files2 = getFilesList(TEST_OUTPUT_DIR);
|
|
assert(files2.length === 0, 'Should have no files when collection disabled');
|
|
|
|
// Toggle collection back on
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
|
|
// Apply again
|
|
fs.rmSync(TEST_OUTPUT_DIR, { recursive: true, force: true });
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
const files3 = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
assert(JSON.stringify(files1) === JSON.stringify(files3), 'File lists should be restored');
|
|
});
|
|
|
|
// Test 3: Explicit overrides are maintained across collection toggles
|
|
await test("Explicit overrides are maintained across collection toggles", async () => {
|
|
// Create initial config and enable collection
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
|
|
// Add explicit override
|
|
await runCommand(`node awesome-copilot.js toggle prompts playwright-generate-test off --config ${TEST_CONFIG}`);
|
|
|
|
// Apply and count files
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
const files1 = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Toggle collection off and on
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation off --config ${TEST_CONFIG}`);
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
|
|
// Apply again
|
|
fs.rmSync(TEST_OUTPUT_DIR, { recursive: true, force: true });
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
const files2 = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
assert(JSON.stringify(files1) === JSON.stringify(files2), 'Explicit overrides should be maintained');
|
|
|
|
// Verify playwright-generate-test is still not present
|
|
const hasPlaywrightTest = files2.some(f => f.includes('playwright-generate-test'));
|
|
assert(!hasPlaywrightTest, 'Explicitly disabled item should stay disabled');
|
|
});
|
|
|
|
// Test 4: Multiple apply operations are truly idempotent
|
|
await test("Multiple apply operations are truly idempotent", async () => {
|
|
// Setup
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
await runCommand(`node awesome-copilot.js toggle prompts create-readme on --config ${TEST_CONFIG}`);
|
|
|
|
// Apply multiple times
|
|
for (let i = 0; i < 3; i++) {
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
}
|
|
|
|
const files1 = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Apply once more
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
const files2 = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
assert(JSON.stringify(files1) === JSON.stringify(files2), 'Multiple applies should be idempotent');
|
|
});
|
|
|
|
console.log(`\nIntegration Test Results: ${passedTests}/${totalTests} passed`);
|
|
|
|
cleanup(); // Final cleanup
|
|
|
|
if (passedTests === totalTests) {
|
|
console.log('🎉 All integration tests passed!');
|
|
return true;
|
|
} else {
|
|
console.log('💥 Some integration tests failed!');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (require.main === module) {
|
|
runTests().then(success => {
|
|
process.exit(success ? 0 : 1);
|
|
}).catch(error => {
|
|
console.error('Test runner error:', error);
|
|
cleanup();
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
module.exports = { runTests }; |