227 lines
8.8 KiB
JavaScript
227 lines
8.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Test to verify that apply operations always use effective states
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const { exec } = require('child_process');
|
|
const { promisify } = require('util');
|
|
const path = require('path');
|
|
|
|
const execAsync = promisify(exec);
|
|
|
|
// Change to project directory for tests
|
|
process.chdir(__dirname);
|
|
|
|
const TEST_CONFIG = 'test-apply-effective.yml';
|
|
const TEST_OUTPUT_DIR = '.test-apply-effective';
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) {
|
|
throw new Error(`Assertion failed: ${message}`);
|
|
}
|
|
}
|
|
|
|
function cleanup() {
|
|
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.basename(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('Testing that apply operations use effective states...\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: Apply respects explicit false overrides
|
|
await test("Apply respects explicit false overrides", async () => {
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
|
|
// Enable collection
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
|
|
// Explicitly disable one item from the collection
|
|
await runCommand(`node awesome-copilot.js toggle prompts playwright-generate-test off --config ${TEST_CONFIG}`);
|
|
|
|
// Apply
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
|
|
const files = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Should have files from collection but NOT the explicitly disabled one
|
|
assert(files.includes('csharp-nunit.prompt.md'), 'Should include collection items');
|
|
assert(!files.includes('playwright-generate-test.prompt.md'), 'Should NOT include explicitly disabled items');
|
|
});
|
|
|
|
// Test 2: Apply includes collection items that are undefined
|
|
await test("Apply includes collection items that are undefined", async () => {
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
|
|
// Enable collection (items remain undefined - no explicit settings)
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
|
|
// Apply
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
|
|
const files = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Should include all collection items since none are explicitly overridden
|
|
assert(files.includes('playwright-generate-test.prompt.md'), 'Should include undefined collection items');
|
|
assert(files.includes('csharp-nunit.prompt.md'), 'Should include all collection items');
|
|
assert(files.includes('tdd-red.chatmode.md'), 'Should include collection chatmodes');
|
|
});
|
|
|
|
// Test 3: Apply respects explicit true overrides over disabled collections
|
|
await test("Apply respects explicit true overrides over disabled collections", async () => {
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
|
|
// Collection remains disabled, but explicitly enable one item
|
|
await runCommand(`node awesome-copilot.js toggle prompts playwright-generate-test on --config ${TEST_CONFIG}`);
|
|
|
|
// Apply
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
|
|
const files = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Should only have the explicitly enabled item
|
|
assert(files.includes('playwright-generate-test.prompt.md'), 'Should include explicitly enabled items');
|
|
assert(!files.includes('csharp-nunit.prompt.md'), 'Should NOT include collection items when collection disabled');
|
|
assert(files.length === 1, 'Should only have one file');
|
|
});
|
|
|
|
// Test 4: Multiple collections work together through effective states
|
|
await test("Multiple collections work together through effective states", async () => {
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
|
|
// Enable multiple collections
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
await runCommand(`node awesome-copilot.js toggle collections frontend-web-dev on --config ${TEST_CONFIG}`);
|
|
|
|
// Apply
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
|
|
const files = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Should have items from both collections
|
|
assert(files.length > 11, 'Should have items from multiple collections'); // testing-automation has 11 items
|
|
assert(files.includes('playwright-generate-test.prompt.md'), 'Should include testing items');
|
|
});
|
|
|
|
// Test 5: Apply output matches effective state computation
|
|
await test("Apply output matches effective state computation", async () => {
|
|
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
|
setTestOutputDir(TEST_CONFIG);
|
|
|
|
// Complex scenario: collection + explicit override + individual enable
|
|
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
|
await runCommand(`node awesome-copilot.js toggle prompts playwright-generate-test off --config ${TEST_CONFIG}`);
|
|
await runCommand(`node awesome-copilot.js toggle prompts create-readme on --config ${TEST_CONFIG}`);
|
|
|
|
// Get list of what should be enabled according to CLI (only individual items, not collections)
|
|
const listResult = await runCommand(`node awesome-copilot.js list prompts --config ${TEST_CONFIG}`);
|
|
const enabledPrompts = (listResult.stdout.match(/\[✓\] (\S+)/g) || []).map(m => m.replace('[✓] ', '').split(' ')[0]);
|
|
|
|
const instructionsResult = await runCommand(`node awesome-copilot.js list instructions --config ${TEST_CONFIG}`);
|
|
const enabledInstructions = (instructionsResult.stdout.match(/\[✓\] (\S+)/g) || []).map(m => m.replace('[✓] ', '').split(' ')[0]);
|
|
|
|
const chatmodesResult = await runCommand(`node awesome-copilot.js list chatmodes --config ${TEST_CONFIG}`);
|
|
const enabledChatmodes = (chatmodesResult.stdout.match(/\[✓\] (\S+)/g) || []).map(m => m.replace('[✓] ', '').split(' ')[0]);
|
|
|
|
const allEnabledItems = [...enabledPrompts, ...enabledInstructions, ...enabledChatmodes];
|
|
|
|
// Apply and get actual files
|
|
await runCommand(`node awesome-copilot.js apply ${TEST_CONFIG}`);
|
|
const actualFiles = getFilesList(TEST_OUTPUT_DIR);
|
|
|
|
// Extract base names for comparison
|
|
const actualBaseNames = actualFiles.map(f => f.replace(/\.(prompt|instructions|chatmode)\.md$/, ''));
|
|
|
|
// Every enabled item in list should have a corresponding file
|
|
allEnabledItems.forEach(item => {
|
|
assert(actualBaseNames.includes(item), `Item ${item} shown as enabled should have corresponding file`);
|
|
});
|
|
|
|
// Every file should correspond to an enabled item
|
|
actualBaseNames.forEach(fileName => {
|
|
assert(allEnabledItems.includes(fileName), `File ${fileName} should correspond to an enabled item`);
|
|
});
|
|
});
|
|
|
|
console.log(`\nEffective States Apply Test Results: ${passedTests}/${totalTests} passed`);
|
|
|
|
cleanup(); // Final cleanup
|
|
|
|
if (passedTests === totalTests) {
|
|
console.log('🎉 All effective states apply tests passed!');
|
|
return true;
|
|
} else {
|
|
console.log('💥 Some effective states apply 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 }; |