mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
328 lines (323 loc) • 11.3 kB
JavaScript
import * as fs from 'fs';
import * as path from 'path';
import { execSync } from 'child_process';
import chalk from 'chalk';
export class TestDetector {
projectRoot;
constructor(projectRoot = process.cwd()) {
this.projectRoot = projectRoot;
}
/**
* Detect all available test configurations in the project
*/
async detectTests() {
const configs = [];
// Check for custom test hook first (highest priority)
const customHook = this.checkCustomHook();
if (customHook) {
configs.push(customHook);
}
// Check for various test frameworks
const dockerCompose = this.checkDockerCompose();
if (dockerCompose)
configs.push(dockerCompose);
const npm = this.checkNpm();
if (npm)
configs.push(npm);
const python = this.checkPython();
if (python)
configs.push(python);
const playwright = this.checkPlaywright();
if (playwright)
configs.push(playwright);
const rust = this.checkRust();
if (rust)
configs.push(rust);
const go = this.checkGo();
if (go)
configs.push(go);
const make = this.checkMake();
if (make)
configs.push(make);
const gradle = this.checkGradle();
if (gradle)
configs.push(gradle);
const maven = this.checkMaven();
if (maven)
configs.push(maven);
// Sort by priority (lower number = higher priority)
return configs.sort((a, b) => a.priority - b.priority);
}
/**
* Run the detected tests
*/
async runTests(configs) {
if (!configs) {
configs = await this.detectTests();
}
if (configs.length === 0) {
console.log(chalk.yellow('⚠️ No test configurations detected'));
console.log(chalk.gray('Create .mira-test-hook.sh to define custom test commands'));
return false;
}
console.log(chalk.blue(`\n🧪 Running tests (${configs.length} configurations detected)\n`));
let allPassed = true;
for (const config of configs) {
console.log(chalk.cyan(`Running ${config.type} tests: ${config.description}`));
try {
// Run setup command if needed
if (config.setupCommand) {
console.log(chalk.gray(`Setup: ${config.setupCommand}`));
execSync(config.setupCommand, {
cwd: this.projectRoot,
stdio: 'inherit'
});
}
// Run test command
console.log(chalk.gray(`Command: ${config.command}`));
execSync(config.command, {
cwd: this.projectRoot,
stdio: 'inherit'
});
console.log(chalk.green(`✅ ${config.type} tests passed\n`));
}
catch (error) {
console.log(chalk.red(`❌ ${config.type} tests failed\n`));
allPassed = false;
// Continue with other test suites even if one fails
if (configs.length > 1) {
console.log(chalk.yellow('Continuing with remaining test suites...\n'));
}
}
}
return allPassed;
}
checkCustomHook() {
const hookPath = path.join(this.projectRoot, '.mira-test-hook.sh');
if (fs.existsSync(hookPath)) {
// Make sure it's executable
try {
fs.chmodSync(hookPath, '755');
}
catch (e) {
// Ignore chmod errors on Windows
}
return {
type: 'Custom Hook',
command: 'bash .mira-test-hook.sh',
description: 'User-defined test script',
priority: 0 // Highest priority
};
}
return null;
}
checkDockerCompose() {
const composePath = path.join(this.projectRoot, 'docker-compose.yml');
const composeYamlPath = path.join(this.projectRoot, 'docker-compose.yaml');
if (fs.existsSync(composePath) || fs.existsSync(composeYamlPath)) {
return {
type: 'Docker Compose',
setupCommand: 'docker-compose up -d',
command: 'docker-compose ps',
description: 'Ensure Docker services are running',
priority: 1
};
}
return null;
}
checkNpm() {
const packagePath = path.join(this.projectRoot, 'package.json');
if (fs.existsSync(packagePath)) {
try {
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
if (packageJson.scripts?.test) {
// Check if using yarn
const yarnLock = path.join(this.projectRoot, 'yarn.lock');
const command = fs.existsSync(yarnLock) ? 'yarn test' : 'npm test';
return {
type: 'Node.js',
command,
description: 'Run npm/yarn test scripts',
priority: 2
};
}
}
catch (e) {
// Invalid package.json
}
}
return null;
}
checkPython() {
const pytestIni = path.join(this.projectRoot, 'pytest.ini');
const setupPy = path.join(this.projectRoot, 'setup.py');
const toxIni = path.join(this.projectRoot, 'tox.ini');
const requirements = path.join(this.projectRoot, 'requirements.txt');
if (fs.existsSync(pytestIni)) {
return {
type: 'Python (pytest)',
command: 'pytest',
description: 'Run pytest test suite',
priority: 3
};
}
else if (fs.existsSync(toxIni)) {
return {
type: 'Python (tox)',
command: 'tox',
description: 'Run tox test environments',
priority: 3
};
}
else if (fs.existsSync(setupPy) || fs.existsSync(requirements)) {
// Check if there's a test directory
const testDir = path.join(this.projectRoot, 'test');
const testsDir = path.join(this.projectRoot, 'tests');
if (fs.existsSync(testDir) || fs.existsSync(testsDir)) {
return {
type: 'Python (unittest)',
command: 'python -m unittest discover',
description: 'Run Python unittest discovery',
priority: 3
};
}
}
return null;
}
checkPlaywright() {
const playwrightConfigs = [
'playwright.config.js',
'playwright.config.ts',
'playwright.config.mjs'
];
for (const config of playwrightConfigs) {
if (fs.existsSync(path.join(this.projectRoot, config))) {
return {
type: 'Playwright',
command: 'npx playwright test',
description: 'Run Playwright E2E tests',
priority: 4
};
}
}
return null;
}
checkRust() {
const cargoToml = path.join(this.projectRoot, 'Cargo.toml');
if (fs.existsSync(cargoToml)) {
return {
type: 'Rust',
command: 'cargo test',
description: 'Run Rust test suite',
priority: 5
};
}
return null;
}
checkGo() {
const goMod = path.join(this.projectRoot, 'go.mod');
if (fs.existsSync(goMod)) {
return {
type: 'Go',
command: 'go test ./...',
description: 'Run Go test suite',
priority: 5
};
}
return null;
}
checkMake() {
const makefile = path.join(this.projectRoot, 'Makefile');
if (fs.existsSync(makefile)) {
// Check if makefile has a test target
try {
const content = fs.readFileSync(makefile, 'utf-8');
if (content.includes('test:')) {
return {
type: 'Make',
command: 'make test',
description: 'Run Makefile test target',
priority: 6
};
}
}
catch (e) {
// Unable to read Makefile
}
}
return null;
}
checkGradle() {
const buildGradle = path.join(this.projectRoot, 'build.gradle');
const buildGradleKts = path.join(this.projectRoot, 'build.gradle.kts');
const gradlew = path.join(this.projectRoot, 'gradlew');
if (fs.existsSync(buildGradle) || fs.existsSync(buildGradleKts)) {
const command = fs.existsSync(gradlew) ? './gradlew test' : 'gradle test';
return {
type: 'Gradle',
command,
description: 'Run Gradle test task',
priority: 7
};
}
return null;
}
checkMaven() {
const pomXml = path.join(this.projectRoot, 'pom.xml');
const mvnw = path.join(this.projectRoot, 'mvnw');
if (fs.existsSync(pomXml)) {
const command = fs.existsSync(mvnw) ? './mvnw test' : 'mvn test';
return {
type: 'Maven',
command,
description: 'Run Maven test phase',
priority: 8
};
}
return null;
}
/**
* Create a sample test hook file
*/
createSampleTestHook() {
const hookPath = path.join(this.projectRoot, '.mira-test-hook.sh');
if (!fs.existsSync(hookPath)) {
const content = `#!/bin/bash
# MIRA Custom Test Hook
# This script is executed when running tests through MIRA
# Customize it to match your project's testing needs
echo "🧪 Running custom test suite..."
# Example: Run multiple test commands
# npm test
# npm run e2e
# npm run lint
# Example: Run tests in specific order
# echo "Running unit tests..."
# npm run test:unit
#
# echo "Running integration tests..."
# npm run test:integration
#
# echo "Running E2E tests..."
# npm run test:e2e
# Example: Check test coverage
# npm run test:coverage
echo "✅ Custom test suite completed"
`;
fs.writeFileSync(hookPath, content);
// Make executable on Unix-like systems
try {
fs.chmodSync(hookPath, '755');
}
catch (e) {
// Ignore on Windows
}
console.log(chalk.green('✅ Created .mira-test-hook.sh'));
console.log(chalk.gray('Customize this file to define your test commands'));
}
else {
console.log(chalk.yellow('⚠️ .mira-test-hook.sh already exists'));
}
}
}
//# sourceMappingURL=TestDetector.js.map