testify-universal-cli
Version:
Universal interactive CLI tool for scanning and executing tests across multiple programming languages
162 lines (146 loc) • 4.54 kB
JavaScript
import { execa } from 'execa';
import fs from 'node:fs/promises';
/**
* Get a Go test runner
*
* @param {string} customRunner - Custom test runner
* @returns {object} - Go test runner
*/
export function getGoRunner(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 = []) {
try {
// Build command for Go tests
const args = ['test', './...', '-v'];
// Add marker/tag filtering if provided
if (markers.length > 0) {
// Go tests use -run to filter by pattern
args.push('-run', markers.map(m => `Test.*${m}.*`).join('|'));
}
const { stdout, stderr, exitCode } = await execa('go', 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) {
try {
// Get the package directory from file path
const packageDir = getPackageDir(testFile.filePath, cwd);
// Run the tests for that package
const { stdout, stderr, exitCode } = await execa('go', ['test', packageDir, '-v'], {
cwd,
all: true,
reject: false,
});
return {
stdout: stdout || stderr,
failed: exitCode !== 0,
};
} catch (error) {
return {
stdout: error.message,
failed: true,
};
}
},
};
}
/**
* Get the package directory from a file path
*
* @param {string} filePath - Path to test file
* @param {string} cwd - Current working directory
* @returns {string} - Go package path
*/
function getPackageDir(filePath, cwd) {
// Get the directory containing the test file
const relativePath = filePath.replace(cwd, '').replace(/^\//, '');
const packageDir = relativePath.split('/').slice(0, -1).join('/');
// If it's in the current directory, use "."
return packageDir || './';
}
/**
* Extract test markers from Go test files
*
* @param {string} filePath - Path to test file
* @returns {Promise<string[]>} - Extracted markers
*/
export async function extractGoMarkers(filePath) {
try {
const content = await fs.readFile(filePath, 'utf8');
const markers = new Set();
// Common Go test patterns
const patterns = [
// Find test functions
/func\s+(Test[A-Za-z0-9_]+)/g,
// Find test that use t.Run
/t\.Run\(["']([A-Za-z0-9_]+)["']/g,
// Check for parallel tests
/t\.Parallel\(\)/g
];
// Extract test names
let match;
for (const pattern of patterns) {
while ((match = pattern.exec(content)) !== null) {
if (match[1]) {
// Get individual components from camel case test name
const parts = match[1].replace(/Test/, '')
.replace(/([A-Z])/g, ' $1')
.trim()
.toLowerCase()
.split(' ');
// Add each part as a marker
parts.forEach(part => {
if (part && part.length > 2) { // Only add meaningful parts
markers.add(part);
}
});
} else if (pattern.toString().includes('Parallel')) {
markers.add('parallel');
}
}
}
// Check for benchmarks
if (content.includes('func Benchmark')) {
markers.add('benchmark');
}
// Look for common test categories
const categories = ['unit', 'integration', 'e2e', 'api', 'ui', 'smoke', 'regression'];
categories.forEach(category => {
if (content.toLowerCase().includes(category)) {
markers.add(category);
}
});
return [...markers];
} catch (error) {
return [];
}
}