testify-universal-cli
Version:
Universal interactive CLI tool for scanning and executing tests across multiple programming languages
216 lines (196 loc) • 6.22 kB
JavaScript
import { execa } from 'execa';
import path from 'node:path';
/**
* Get a Python test runner
*
* @param {string} customRunner - Custom test runner
* @returns {object} - Python test runner
*/
export function getPythonRunner(customRunner) {
return {
/**
* Run all tests
*
* @param {Array<{filePath: string, relativePath: string, markers: string[]}>} testFiles - Test files
* @param {string} cwd - Current working directory
* @param {string[]} markers - Test markers
* @returns {Promise<{stdout: string, failed: boolean}>} - Test results
*/
async runAll(testFiles, cwd, markers = []) {
// Check if pytest is available
const hasPytest = await checkCommand('pytest');
if (!hasPytest) {
throw new Error('pytest is not installed or not available in PATH');
}
let args = ['-v'];
// Add markers if provided
if (markers.length > 0) {
args.push('-m', markers.join(' or '));
}
try {
// Use platform-specific command execution
if (global.pytestCommand && global.pytestCommand.includes(' ')) {
// Using python -m pytest on Windows
const [cmd, ...cmdArgs] = global.pytestCommand.split(' ');
// Combine the command args with our args
const fullArgs = [...cmdArgs, ...args];
const { stdout, stderr, exitCode } = await execa(cmd, fullArgs, {
cwd,
all: true,
reject: false,
});
return {
stdout: stdout || stderr,
failed: exitCode !== 0,
};
} else {
// Regular pytest command
const { stdout, stderr, exitCode } = await execa('pytest', args, {
cwd,
all: true,
reject: false,
});
return {
stdout: stdout || stderr,
failed: exitCode !== 0,
};
}
} catch (error) {
return {
stdout: error.message,
failed: true,
};
}
},
/**
* Run a single test file
*
* @param {object} testFile - Test file
* @param {string} testFile.filePath - Path to test file
* @param {string[]} testFile.markers - Test markers
* @param {string} cwd - Current working directory
* @returns {Promise<{stdout: string, failed: boolean}>} - Test results
*/
async runFile(testFile, cwd) {
// Check if pytest is available
const hasPytest = await checkCommand('pytest');
if (!hasPytest) {
throw new Error('pytest is not installed or not available in PATH');
}
try {
// Normalize path for cross-platform compatibility
const testPath = path.normalize(testFile.filePath);
const fileArgs = [testPath, '-v'];
// Use platform-specific command execution
if (global.pytestCommand && global.pytestCommand.includes(' ')) {
// Using python -m pytest on Windows
const [cmd, ...cmdArgs] = global.pytestCommand.split(' ');
// Combine the command args with our file args
const fullArgs = [...cmdArgs, ...fileArgs];
const { stdout, stderr, exitCode } = await execa(cmd, fullArgs, {
cwd,
all: true,
reject: false,
});
return {
stdout: stdout || stderr,
failed: exitCode !== 0,
};
} else {
// Regular pytest command
const { stdout, stderr, exitCode } = await execa('pytest', fileArgs, {
cwd,
all: true,
reject: false,
});
return {
stdout: stdout || stderr,
failed: exitCode !== 0,
};
}
} catch (error) {
return {
stdout: error.message,
failed: true,
};
}
},
};
}
/**
* Check if a command is available
*
* @param {string} command - Command to check
* @returns {Promise<boolean>} - Whether the command is available
*/
async function checkCommand(command) {
try {
// Handle Windows-specific command issues
if (process.platform === 'win32') {
// On Windows, the command might have a different name
// Check common variations for Python commands
if (command === 'python' || command === 'python3') {
// Try python, python3, and py (Windows Python launcher)
try {
await execa('python', ['--version']);
return true;
} catch (e) {
try {
await execa('py', ['--version']);
// If py works, replace the global command for future uses
global.pythonCommand = 'py';
return true;
} catch (e2) {
return false;
}
}
} else if (command === 'pytest') {
// Try various ways pytest might be installed on Windows
try {
await execa('pytest', ['--version']);
return true;
} catch (e) {
try {
// Try with python -m pytest
const pythonCmd = global.pythonCommand || 'python';
await execa(pythonCmd, ['-m', 'pytest', '--version']);
// If this works, update the global pytest command
global.pytestCommand = `${pythonCmd} -m pytest`;
return true;
} catch (e2) {
return false;
}
}
}
}
// Default approach for non-Windows platforms
await execa(command, ['--version']);
return true;
} catch (error) {
return false;
}
}
/**
* Get all available pytest markers
*
* @param {string} cwd - Current working directory
* @returns {Promise<string[]>} - Available markers
*/
export async function getPytestMarkers(cwd) {
try {
const { stdout } = await execa('pytest', ['--markers'], {
cwd,
reject: false,
});
// Parse markers from output
const markers = [];
const markerRegex = /@pytest\.mark\.([a-zA-Z0-9_]+)/g;
let match;
while ((match = markerRegex.exec(stdout)) !== null) {
markers.push(match[1]);
}
return markers;
} catch (error) {
return [];
}
}