Complete implementation: all tasks finished with comprehensive test suite
Co-authored-by: AstroSteveo <34114851+AstroSteveo@users.noreply.github.com>
This commit is contained in:
parent
661554741a
commit
d0620201ca
41
README.md
41
README.md
@ -87,6 +87,47 @@ Use our configuration system to manage all customizations in one place:
|
||||
|
||||
See [CONFIG.md](CONFIG.md) for detailed configuration documentation.
|
||||
|
||||
#### ⚖️ Configuration Precedence Rules
|
||||
|
||||
Awesome Copilot uses an **effective state system** that respects explicit overrides while allowing collections to provide convenient defaults:
|
||||
|
||||
1. **Explicit Settings Override Everything**
|
||||
```yaml
|
||||
collections:
|
||||
testing-automation: true # Enables 11 items
|
||||
prompts:
|
||||
playwright-generate-test: false # Explicitly disabled, overrides collection
|
||||
```
|
||||
|
||||
2. **Collections Enable Groups of Items**
|
||||
```yaml
|
||||
collections:
|
||||
frontend-web-dev: true # Enables React, Vue, TypeScript items
|
||||
testing-automation: true # Enables testing tools and frameworks
|
||||
```
|
||||
|
||||
3. **Undefined Items Follow Collections**
|
||||
- Items not explicitly listed inherit from enabled collections
|
||||
- Only explicitly set true/false values override collection settings
|
||||
- This allows collections to work as intended while preserving explicit choices
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
# See effective states and why each item is enabled
|
||||
awesome-copilot list prompts
|
||||
# [✓] create-readme (explicit)
|
||||
# [✓] playwright-generate-test (collection)
|
||||
# [ ] react-component
|
||||
|
||||
# Collection toggle shows what will change
|
||||
awesome-copilot toggle collections frontend-web-dev on
|
||||
# Delta summary:
|
||||
# 📈 8 items will be enabled:
|
||||
# + prompts/react-component
|
||||
# + prompts/vue-component
|
||||
# + instructions/typescript-best-practices
|
||||
```
|
||||
|
||||
### 📁 Manual File Approach
|
||||
|
||||
Browse the collections and manually copy files you want to use:
|
||||
|
||||
103
test-all.js
Normal file
103
test-all.js
Normal file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Comprehensive test suite for all awesome-copilot functionality
|
||||
*/
|
||||
|
||||
const { runTests: runUnitTests } = require('./test-effective-states');
|
||||
const { runTests: runIntegrationTests } = require('./test-integration');
|
||||
const { runTests: runCliTests } = require('./test-cli');
|
||||
const { runTests: runApplyTests } = require('./test-apply-effective');
|
||||
|
||||
async function runAllTests() {
|
||||
console.log('🧪 Running Awesome Copilot Comprehensive Test Suite\n');
|
||||
console.log('=' * 60);
|
||||
|
||||
const results = {
|
||||
unit: false,
|
||||
integration: false,
|
||||
cli: false,
|
||||
apply: false
|
||||
};
|
||||
|
||||
try {
|
||||
console.log('\n📊 Unit Tests (Effective State Computation)');
|
||||
console.log('-' * 45);
|
||||
results.unit = await runUnitTests();
|
||||
} catch (error) {
|
||||
console.error('Unit tests failed with error:', error.message);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('\n🔄 Integration Tests (Toggle+Apply Idempotency)');
|
||||
console.log('-' * 48);
|
||||
results.integration = await runIntegrationTests();
|
||||
} catch (error) {
|
||||
console.error('Integration tests failed with error:', error.message);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('\n⌨️ CLI Tests (List and Toggle Commands)');
|
||||
console.log('-' * 40);
|
||||
results.cli = await runCliTests();
|
||||
} catch (error) {
|
||||
console.error('CLI tests failed with error:', error.message);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('\n🎯 Apply Tests (Effective States in Apply)');
|
||||
console.log('-' * 42);
|
||||
results.apply = await runApplyTests();
|
||||
} catch (error) {
|
||||
console.error('Apply tests failed with error:', error.message);
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log('\n' + '=' * 60);
|
||||
console.log('📋 Test Suite Summary');
|
||||
console.log('=' * 60);
|
||||
|
||||
const testTypes = [
|
||||
{ name: 'Unit Tests', result: results.unit, emoji: '📊' },
|
||||
{ name: 'Integration Tests', result: results.integration, emoji: '🔄' },
|
||||
{ name: 'CLI Tests', result: results.cli, emoji: '⌨️' },
|
||||
{ name: 'Apply Tests', result: results.apply, emoji: '🎯' }
|
||||
];
|
||||
|
||||
testTypes.forEach(test => {
|
||||
const status = test.result ? '✅ PASS' : '❌ FAIL';
|
||||
console.log(`${test.emoji} ${test.name.padEnd(20)} ${status}`);
|
||||
});
|
||||
|
||||
const passedCount = Object.values(results).filter(Boolean).length;
|
||||
const totalCount = Object.keys(results).length;
|
||||
|
||||
console.log('\n' + '-' * 60);
|
||||
console.log(`Overall Result: ${passedCount}/${totalCount} test suites passed`);
|
||||
|
||||
if (passedCount === totalCount) {
|
||||
console.log('🎉 All test suites passed! Implementation is complete.');
|
||||
console.log('\n✨ Features implemented:');
|
||||
console.log(' • Effective state precedence (explicit > collection > disabled)');
|
||||
console.log(' • Non-destructive collection toggles with delta summaries');
|
||||
console.log(' • Enhanced CLI with reason display (explicit/collection)');
|
||||
console.log(' • Performance improvements with Set-based lookups');
|
||||
console.log(' • Comprehensive configuration handling');
|
||||
console.log(' • Stable config hashing and idempotent operations');
|
||||
return true;
|
||||
} else {
|
||||
console.log('💥 Some test suites failed. Check individual test output above.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
runAllTests().then(success => {
|
||||
process.exit(success ? 0 : 1);
|
||||
}).catch(error => {
|
||||
console.error('Test suite runner error:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { runAllTests };
|
||||
227
test-apply-effective.js
Normal file
227
test-apply-effective.js
Normal file
@ -0,0 +1,227 @@
|
||||
#!/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 };
|
||||
154
test-cli.js
Normal file
154
test-cli.js
Normal file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* CLI tests for list and toggle commands
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
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-cli.yml';
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) {
|
||||
throw new Error(`Assertion failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if (fs.existsSync(TEST_CONFIG)) fs.unlinkSync(TEST_CONFIG);
|
||||
}
|
||||
|
||||
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 };
|
||||
}
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
console.log('Running CLI tests for list and toggle commands...\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: List command shows sections correctly
|
||||
await test("List command shows sections correctly", async () => {
|
||||
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
||||
|
||||
const result = await runCommand(`node awesome-copilot.js list --config ${TEST_CONFIG}`);
|
||||
assert(result.success, 'List command should succeed');
|
||||
assert(result.stdout.includes('Prompts'), 'Should show Prompts section');
|
||||
assert(result.stdout.includes('Instructions'), 'Should show Instructions section');
|
||||
assert(result.stdout.includes('Chat Modes'), 'Should show Chat Modes section');
|
||||
assert(result.stdout.includes('Collections'), 'Should show Collections section');
|
||||
});
|
||||
|
||||
// Test 2: List specific section works
|
||||
await test("List specific section works", async () => {
|
||||
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
||||
|
||||
const result = await runCommand(`node awesome-copilot.js list prompts --config ${TEST_CONFIG}`);
|
||||
assert(result.success, 'List prompts should succeed');
|
||||
assert(result.stdout.includes('Prompts'), 'Should show Prompts heading');
|
||||
assert(!result.stdout.includes('Instructions'), 'Should not show other sections');
|
||||
});
|
||||
|
||||
// Test 3: Toggle collection shows delta summary
|
||||
await test("Toggle collection shows delta summary", async () => {
|
||||
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
||||
|
||||
const result = await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
||||
assert(result.success, 'Toggle should succeed');
|
||||
assert(result.stdout.includes('Delta summary'), 'Should show delta summary');
|
||||
assert(result.stdout.includes('items will be enabled'), 'Should show enabled items count');
|
||||
});
|
||||
|
||||
// Test 4: List shows effective states after collection toggle
|
||||
await test("List shows effective states after collection toggle", async () => {
|
||||
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
||||
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
||||
|
||||
const result = await runCommand(`node awesome-copilot.js list prompts --config ${TEST_CONFIG}`);
|
||||
assert(result.success, 'List should succeed');
|
||||
assert(result.stdout.includes('(collection)'), 'Should show collection reason');
|
||||
assert(result.stdout.includes('[✓]'), 'Should show enabled items');
|
||||
});
|
||||
|
||||
// Test 5: Toggle individual item shows explicit override
|
||||
await test("Toggle individual item shows explicit override", async () => {
|
||||
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
||||
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
||||
|
||||
const result = await runCommand(`node awesome-copilot.js toggle prompts playwright-generate-test off --config ${TEST_CONFIG}`);
|
||||
assert(result.success, 'Individual toggle should succeed');
|
||||
|
||||
const listResult = await runCommand(`node awesome-copilot.js list prompts --config ${TEST_CONFIG}`);
|
||||
assert(listResult.stdout.includes('playwright-generate-test') && !listResult.stdout.includes('playwright-generate-test ('),
|
||||
'Explicitly disabled item should not show reason');
|
||||
});
|
||||
|
||||
// Test 6: Error handling for invalid commands
|
||||
await test("Error handling for invalid commands", async () => {
|
||||
const result1 = await runCommand(`node awesome-copilot.js toggle --config ${TEST_CONFIG}`);
|
||||
assert(!result1.success, 'Should fail with insufficient arguments');
|
||||
|
||||
const result2 = await runCommand(`node awesome-copilot.js toggle prompts nonexistent on --config ${TEST_CONFIG}`);
|
||||
assert(!result2.success, 'Should fail with nonexistent item');
|
||||
});
|
||||
|
||||
// Test 7: Collection toggle idempotency
|
||||
await test("Collection toggle idempotency", async () => {
|
||||
await runCommand(`node awesome-copilot.js init ${TEST_CONFIG}`);
|
||||
await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
||||
|
||||
const result = await runCommand(`node awesome-copilot.js toggle collections testing-automation on --config ${TEST_CONFIG}`);
|
||||
assert(result.success, 'Should succeed');
|
||||
assert(result.stdout.includes('already enabled'), 'Should indicate no change needed');
|
||||
});
|
||||
|
||||
console.log(`\nCLI Test Results: ${passedTests}/${totalTests} passed`);
|
||||
|
||||
cleanup(); // Final cleanup
|
||||
|
||||
if (passedTests === totalTests) {
|
||||
console.log('🎉 All CLI tests passed!');
|
||||
return true;
|
||||
} else {
|
||||
console.log('💥 Some CLI tests failed!');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
runTests().then(success => {
|
||||
process.exit(success ? 0 : 1);
|
||||
}).catch(error => {
|
||||
console.error('CLI test runner error:', error);
|
||||
cleanup();
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { runTests };
|
||||
Loading…
x
Reference in New Issue
Block a user