UNPKG

ctrlshiftleft

Version:

AI-powered toolkit for embedding QA and security testing into development workflows

129 lines 5.61 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TestGenerator = void 0; const promises_1 = __importDefault(require("fs/promises")); const path_1 = __importDefault(require("path")); const glob_1 = require("glob"); const llmService_1 = require("./llmService"); const fileUtils_1 = require("../utils/fileUtils"); const playwrightTemplate_1 = require("../templates/playwrightTemplate"); const seleniumTemplate_1 = require("../templates/seleniumTemplate"); class TestGenerator { constructor(options) { this.options = { format: options.format || 'playwright', timeout: options.timeout || 60 }; this.llmService = new llmService_1.LLMService(); } /** * Generates end-to-end tests from source code * @param sourcePath Path to source file or directory * @param outputDir Output directory for generated tests * @returns Generation result containing test count and file paths */ async generateTests(sourcePath, outputDir) { // Ensure output directory exists await (0, fileUtils_1.ensureDirectoryExists)(outputDir); // Get all source files if sourcePath is a directory const sourceFiles = await this.getSourceFiles(sourcePath); const result = { testCount: 0, files: [] }; // Generate tests for each source file for (const sourceFile of sourceFiles) { const sourceCode = await promises_1.default.readFile(sourceFile, 'utf8'); const relativeSourcePath = path_1.default.relative(process.cwd(), sourceFile); // Skip files that don't need tests (like test files themselves) if (this.shouldSkipFile(sourceFile)) { continue; } // Analyze source code with LLM to extract test scenarios const testScenarios = await this.llmService.extractTestScenarios(sourceCode, relativeSourcePath); if (testScenarios.length === 0) { continue; } // Generate test file path const testFileName = await this.getTestFileName(sourceFile, outputDir); // Generate test template based on format const testTemplate = this.generateTestTemplate(testScenarios, relativeSourcePath); // Write test file await promises_1.default.writeFile(testFileName, testTemplate.content, 'utf8'); result.testCount += testScenarios.length; result.files.push(path_1.default.relative(process.cwd(), testFileName)); } return result; } /** * Get all source files from a path (file or directory) */ async getSourceFiles(sourcePath) { const stats = await promises_1.default.stat(sourcePath); if (stats.isFile()) { return [sourcePath]; } if (stats.isDirectory()) { // Find all JS/TS files but exclude test files and node_modules return (0, glob_1.glob)(`${sourcePath}/**/*.{js,jsx,ts,tsx}`, { ignore: [ '**/node_modules/**', '**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}', '**/test/**', '**/tests/**', '**/dist/**', '**/build/**' ] }); } return []; } /** * Determine if a file should be skipped for test generation */ shouldSkipFile(filePath) { const filename = path_1.default.basename(filePath).toLowerCase(); return filename.includes('.test.') || filename.includes('.spec.') || filename.endsWith('.d.ts'); } /** * Generate test file name based on source file */ async getTestFileName(sourceFile, outputDir) { // Check if outputDir is actually a file path rather than a directory if (path_1.default.extname(outputDir) !== '') { // If outputDir has a file extension, use it directly as the test file await (0, fileUtils_1.ensureDirectoryExists)(path_1.default.dirname(outputDir)); return outputDir; } const sourceFileName = path_1.default.basename(sourceFile); const sourceDir = path_1.default.dirname(sourceFile); // Keep subdirectory structure relative to source root const relativeDir = path_1.default.relative(process.cwd(), sourceDir); const targetDir = path_1.default.join(outputDir, relativeDir); // Replace extension with .test.ts or .test.js let testFileName = sourceFileName.replace(/\.(js|jsx|ts|tsx)$/, ''); testFileName = `${testFileName}.test.${this.options.format === 'playwright' ? 'ts' : 'js'}`; // Create subdirectory if needed await (0, fileUtils_1.ensureDirectoryExists)(targetDir); return path_1.default.join(targetDir, testFileName); } /** * Generate test template based on format */ generateTestTemplate(testScenarios, sourcePath) { if (this.options.format === 'playwright') { return (0, playwrightTemplate_1.generatePlaywrightTest)(testScenarios, sourcePath); } else { return (0, seleniumTemplate_1.generateSeleniumTest)(testScenarios, sourcePath); } } } exports.TestGenerator = TestGenerator; //# sourceMappingURL=testGenerator.js.map