@labnex/cli
Version:
CLI for Labnex, an AI-Powered Testing Automation Platform
226 lines ⢠11.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeCommand = void 0;
const commander_1 = require("commander");
const inquirer_1 = __importDefault(require("inquirer"));
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const client_1 = require("../api/client");
exports.analyzeCommand = new commander_1.Command('analyze')
.description('Analyze test execution results and pinpoint failure causes.')
.addCommand(new commander_1.Command('failure')
.description('Analyze a specific test failure from a run ID using AI for insights.')
.option('--run-id <runId>', 'Test run ID to analyze failures from')
.action(async (options) => {
try {
let { runId } = options;
// Prompt for run ID if not provided
if (!runId) {
const runIdPrompt = await inquirer_1.default.prompt([
{
type: 'input',
name: 'runId',
message: 'Enter test run ID:',
validate: (input) => input.length > 0 || 'Test run ID is required'
}
]);
runId = runIdPrompt.runId;
}
console.log(chalk_1.default.cyan('š Analyzing test failure...'));
console.log(chalk_1.default.gray(`š Test Run ID: ${runId}`));
const spinner = (0, ora_1.default)('Fetching failure details...').start();
try {
// Get test run results to find failures
const resultsResponse = await client_1.apiClient.getTestRunResults(runId);
if (!resultsResponse.success) {
spinner.fail(chalk_1.default.red('Failed to fetch test run results: ' + resultsResponse.error));
return;
}
const results = resultsResponse.data;
// Find failed test cases
const failedTests = results.testCases.filter((testCase) => testCase.status === 'FAIL' || testCase.status === 'FAILED' || testCase.status === 'fail');
if (failedTests.length === 0) {
spinner.succeed(chalk_1.default.green('No failed tests found in this test run'));
console.log(chalk_1.default.gray('⨠All tests passed successfully!'));
return;
}
spinner.succeed(`Found ${failedTests.length} failed test(s)`);
let selectedFailure;
if (failedTests.length === 1) {
// Auto-select the single failure
selectedFailure = failedTests[0];
console.log(chalk_1.default.gray(`š Analyzing: ${selectedFailure.title}`));
}
else {
// Let user choose which failure to analyze
console.log(chalk_1.default.yellow(`\nFound ${failedTests.length} failed tests:`));
failedTests.forEach((test, index) => {
console.log(` ${index + 1}. ${test.title} - ${test.error || 'Unknown error'}`);
});
const selectionPrompt = await inquirer_1.default.prompt([
{
type: 'list',
name: 'failure',
message: 'Select which failure to analyze:',
choices: failedTests.map((test, index) => ({
name: `${test.title} - ${test.error || 'Unknown error'}`,
value: test
}))
}
]);
selectedFailure = selectionPrompt.failure;
}
const analysisSpinner = (0, ora_1.default)('Analyzing failure with AI...').start();
try {
// Use the test case ID as the failure ID for the AI analysis
const response = await client_1.apiClient.analyzeFailure(runId, selectedFailure._id);
if (response.success) {
analysisSpinner.succeed(chalk_1.default.green('Failure analysis completed'));
console.log(chalk_1.default.cyan('\nš¤ AI Failure Analysis:'));
console.log(chalk_1.default.gray('ā'.repeat(60)));
console.log(`${chalk_1.default.bold('Test Case:')} ${selectedFailure.title}`);
console.log(`${chalk_1.default.bold('Status:')} ${chalk_1.default.red(selectedFailure.status)}`);
console.log(`${chalk_1.default.bold('Duration:')} ${selectedFailure.duration}ms`);
if (selectedFailure.error) {
console.log(`${chalk_1.default.bold('Error:')} ${chalk_1.default.red(selectedFailure.error)}`);
}
console.log(`\n${chalk_1.default.bold('š Analysis:')}`);
console.log(chalk_1.default.white(response.data.analysis));
if (response.data.suggestions.length > 0) {
console.log(`\n${chalk_1.default.bold('š” Suggestions:')}`);
response.data.suggestions.forEach((suggestion, index) => {
console.log(` ${chalk_1.default.green(index + 1)}. ${suggestion}`);
});
}
console.log(chalk_1.default.gray('\nā'.repeat(60)));
console.log(chalk_1.default.gray('š” Tip: Fix the issues above and re-run your tests!'));
}
else {
analysisSpinner.fail(chalk_1.default.red('Analysis failed: ' + response.error));
}
}
catch (error) {
analysisSpinner.fail(chalk_1.default.red('Analysis failed: ' + error.message));
}
}
catch (error) {
spinner.fail(chalk_1.default.red('Failed to analyze failure: ' + error.message));
console.log(chalk_1.default.gray('Please check the test run ID and try again.'));
}
}
catch (error) {
console.error(chalk_1.default.red('Error:'), error.message);
}
}))
.addCommand(new commander_1.Command('interactive')
.description('Start an interactive AI session to analyze a failed test run.')
.option('--run-id <runId>', 'The ID of the test run to analyze interactively')
.action(async (options) => {
let { runId } = options;
if (!runId) {
// Prompt for run ID if not provided
const answers = await inquirer_1.default.prompt([{ type: 'input', name: 'runId', message: 'Enter the test run ID to analyze:' }]);
runId = answers.runId;
}
console.log(chalk_1.default.cyan(`š Starting interactive analysis for run ID: ${runId}`));
const initialSpinner = (0, ora_1.default)('Fetching initial failure data...').start();
try {
const resultsResponse = await client_1.apiClient.getTestRunResults(runId);
if (!resultsResponse.success || !resultsResponse.data) {
initialSpinner.fail(chalk_1.default.red('Could not fetch test run results.'));
return;
}
const failedTests = resultsResponse.data.testCases.filter((tc) => tc.status.toLowerCase() === 'failed' || tc.status.toLowerCase() === 'fail');
if (failedTests.length === 0) {
initialSpinner.succeed(chalk_1.default.green('ā
No failed tests found in this run!'));
return;
}
initialSpinner.succeed(chalk_1.default.green('Found failed tests. Launching AI session...'));
// For simplicity, we'll start with the first failed test.
// This could be expanded to let the user choose.
const testToAnalyze = failedTests[0];
// This will be our conversational loop
await conversationalAnalysisLoop(runId, testToAnalyze);
}
catch (error) {
initialSpinner.fail(chalk_1.default.red(`An error occurred: ${error.message}`));
}
}));
async function conversationalAnalysisLoop(runId, testCase) {
let conversationHistory = [];
let continueConversation = true;
console.log(chalk_1.default.yellow(`\n\n--- Analyzing Failure: ${testCase.title} ---`));
// Initial analysis call
const initialAnalysisSpinner = (0, ora_1.default)('Performing initial AI analysis...').start();
try {
const initialResponse = await client_1.apiClient.analyzeFailure(runId, testCase._id);
if (initialResponse.success) {
initialAnalysisSpinner.succeed('Initial analysis complete.');
console.log(chalk_1.default.blue.bold('\nš¤ Initial AI Analysis:'));
console.log(chalk_1.default.white(initialResponse.data.analysis));
if (initialResponse.data.suggestions.length > 0) {
console.log(chalk_1.default.green.bold('\nš” Suggestions:'));
initialResponse.data.suggestions.forEach((s) => console.log(chalk_1.default.green(`- ${s}`)));
}
// Add AI response to history
conversationHistory.push({ role: 'assistant', content: initialResponse.data.analysis });
}
else {
initialAnalysisSpinner.fail(chalk_1.default.red('Initial analysis failed.'));
return;
}
}
catch (e) {
initialAnalysisSpinner.fail(chalk_1.default.red(`An error occurred during analysis: ${e.message}`));
return;
}
while (continueConversation) {
const { action } = await inquirer_1.default.prompt([
{
type: 'list',
name: 'action',
message: '\nWhat would you like to do next?',
choices: [
{ name: 'Ask a follow-up question', value: 'ask' },
{ name: 'Suggest a code fix (coming soon)', value: 'fix', disabled: true },
new inquirer_1.default.Separator(),
{ name: 'Exit interactive session', value: 'exit' },
],
},
]);
if (action === 'exit') {
continueConversation = false;
}
else if (action === 'ask') {
const { question } = await inquirer_1.default.prompt([
{ type: 'input', name: 'question', message: 'Your question for the AI:' }
]);
const followUpSpinner = (0, ora_1.default)('Thinking...').start();
conversationHistory.push({ role: 'user', content: question });
try {
const response = await client_1.apiClient.analyzeFailureConversational(runId, testCase._id, conversationHistory, question);
if (response.success) {
followUpSpinner.succeed('AI responded.');
console.log(chalk_1.default.blue.bold('\nš¤ AI:'));
console.log(chalk_1.default.white(response.data.analysis));
conversationHistory.push({ role: 'assistant', content: response.data.analysis });
}
else {
followUpSpinner.fail(chalk_1.default.red(`The AI could not respond: ${response.error}`));
// Remove the failed user question from history
conversationHistory.pop();
}
}
catch (error) {
followUpSpinner.fail(chalk_1.default.red(`An error occurred: ${error.message}`));
// Remove the failed user question from history
conversationHistory.pop();
}
}
}
console.log(chalk_1.default.cyan('\nā
Exited interactive analysis session.'));
}
//# sourceMappingURL=analyze.js.map