smartui-migration-tool
Version:
Enterprise-grade CLI tool for migrating visual testing platforms to LambdaTest SmartUI
289 lines • 14.7 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnalysisReporter = void 0;
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const ConfigTransformer_1 = require("./ConfigTransformer");
const CodeTransformer_1 = require("./CodeTransformer");
const JavaCodeTransformer_1 = require("./JavaCodeTransformer");
const PythonCodeTransformer_1 = require("./PythonCodeTransformer");
const ExecutionTransformer_1 = require("./ExecutionTransformer");
const StorybookTransformer_1 = require("./StorybookTransformer");
/**
* AnalysisReporter module for performing virtual migrations and generating pre-migration analysis reports
* This module orchestrates all transformers in read-only mode to preview proposed changes
*/
class AnalysisReporter {
constructor(projectPath) {
this.projectPath = projectPath;
}
/**
* Performs a virtual migration analysis to preview all proposed changes
* @param detectionResult - The result from the Scanner module
* @returns AnalysisResult containing all proposed changes and statistics
*/
async analyze(detectionResult) {
const changes = [];
const allWarnings = [];
let totalSnapshots = 0;
let filesToCreate = 0;
let filesToModify = 0;
try {
// Initialize transformers
const configTransformer = new ConfigTransformer_1.ConfigTransformer(this.projectPath);
const codeTransformer = new CodeTransformer_1.CodeTransformer(this.projectPath);
const javaCodeTransformer = new JavaCodeTransformer_1.JavaCodeTransformer(this.projectPath);
const pythonCodeTransformer = new PythonCodeTransformer_1.PythonCodeTransformer(this.projectPath);
const executionTransformer = new ExecutionTransformer_1.ExecutionTransformer(this.projectPath);
const storybookTransformer = new StorybookTransformer_1.StorybookTransformer(this.projectPath);
// Step 1: Analyze configuration transformation
const configAnalysis = await this.analyzeConfigurationTransformation(detectionResult, configTransformer, changes, allWarnings);
filesToCreate += configAnalysis.filesToCreate;
filesToModify += configAnalysis.filesToModify;
// Step 2: Analyze code transformation
const codeAnalysis = await this.analyzeCodeTransformation(detectionResult, codeTransformer, javaCodeTransformer, pythonCodeTransformer, changes, allWarnings);
filesToModify += codeAnalysis.filesToModify;
totalSnapshots += codeAnalysis.snapshotCount;
// Step 3: Analyze execution transformation
const executionAnalysis = await this.analyzeExecutionTransformation(detectionResult, executionTransformer, storybookTransformer, changes, allWarnings);
filesToModify += executionAnalysis.filesToModify;
// Add warnings as INFO changes
allWarnings.forEach(warning => {
changes.push({
filePath: 'Migration Analysis',
type: 'INFO',
description: warning.message
});
});
return {
filesToCreate,
filesToModify,
snapshotCount: totalSnapshots,
warnings: allWarnings,
changes
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error during analysis';
allWarnings.push({
message: `Analysis failed: ${errorMessage}`,
details: 'The migration analysis encountered an error and may be incomplete.'
});
return {
filesToCreate,
filesToModify,
snapshotCount: totalSnapshots,
warnings: allWarnings,
changes
};
}
}
/**
* Analyzes configuration transformation
* @param detectionResult - The detection result
* @param configTransformer - The config transformer instance
* @param changes - Array to collect proposed changes
* @param warnings - Array to collect warnings
* @returns Analysis statistics
*/
async analyzeConfigurationTransformation(detectionResult, configTransformer, changes, warnings) {
let filesToCreate = 0;
let filesToModify = 0;
// Analyze config files
for (const configFile of detectionResult.files.config) {
try {
const configFilePath = path_1.default.join(this.projectPath, configFile);
const configContent = await fs_1.promises.readFile(configFilePath, 'utf-8');
let configResult;
if (detectionResult.platform === 'Percy') {
configResult = configTransformer.transformPercyConfig(configContent);
}
else if (detectionResult.platform === 'Applitools') {
configResult = configTransformer.transformApplitoolsConfig(configContent);
}
else if (detectionResult.platform === 'Sauce Labs Visual') {
configResult = configTransformer.transformSauceLabsConfig(configContent, configFile);
}
else {
throw new Error(`Unsupported platform: ${detectionResult.platform}`);
}
// Add warnings
warnings.push(...configResult.warnings);
// Record the creation of .smartui.json
changes.push({
filePath: '.smartui.json',
type: 'CREATE',
description: `Generated SmartUI configuration from ${configFile}`
});
filesToCreate++;
// Record modification of original config file (if it would be modified)
if (configResult.warnings.length > 0) {
changes.push({
filePath: configFile,
type: 'MODIFY',
description: 'Configuration file will be updated with migration notes'
});
filesToModify++;
}
}
catch (error) {
warnings.push({
message: `Failed to analyze config file ${configFile}: ${error instanceof Error ? error.message : 'Unknown error'}`,
details: 'The configuration file may be inaccessible or malformed.'
});
}
}
return { filesToCreate, filesToModify };
}
/**
* Analyzes code transformation
* @param detectionResult - The detection result
* @param codeTransformer - The JS/TS code transformer
* @param javaCodeTransformer - The Java code transformer
* @param pythonCodeTransformer - The Python code transformer
* @param changes - Array to collect proposed changes
* @param warnings - Array to collect warnings
* @returns Analysis statistics
*/
async analyzeCodeTransformation(detectionResult, codeTransformer, javaCodeTransformer, pythonCodeTransformer, changes, warnings) {
let filesToModify = 0;
let totalSnapshots = 0;
// Analyze source files based on language
for (const sourceFile of detectionResult.files.source) {
try {
const sourceFilePath = path_1.default.join(this.projectPath, sourceFile);
const sourceContent = await fs_1.promises.readFile(sourceFilePath, 'utf-8');
let codeResult;
let transformerName;
// Choose appropriate transformer based on language
if (detectionResult.language === 'Java') {
codeResult = javaCodeTransformer.transform(sourceContent, detectionResult.platform);
transformerName = 'Java Code Transformer';
}
else if (detectionResult.language === 'Python') {
codeResult = pythonCodeTransformer.transform(sourceContent, sourceFile, detectionResult.platform);
transformerName = 'Python Code Transformer';
}
else {
// JavaScript/TypeScript
if (detectionResult.platform === 'Percy') {
codeResult = codeTransformer.transformPercy(sourceContent);
}
else if (detectionResult.platform === 'Applitools') {
const framework = detectionResult.framework === 'Cypress' ? 'Cypress' : 'Playwright';
codeResult = codeTransformer.transformApplitools(sourceContent, framework);
}
else if (detectionResult.platform === 'Sauce Labs Visual') {
codeResult = codeTransformer.transformSauceLabs(sourceContent);
}
else {
continue; // Skip unsupported platform
}
transformerName = 'JavaScript/TypeScript Code Transformer';
}
// Add warnings
warnings.push(...codeResult.warnings);
// Record file modification
if (codeResult.snapshotCount > 0 || codeResult.warnings.length > 0) {
changes.push({
filePath: sourceFile,
type: 'MODIFY',
description: `Transform ${codeResult.snapshotCount} snapshot(s) using ${transformerName}`
});
filesToModify++;
}
totalSnapshots += codeResult.snapshotCount;
}
catch (error) {
warnings.push({
message: `Failed to analyze source file ${sourceFile}: ${error instanceof Error ? error.message : 'Unknown error'}`,
details: 'The source file may be inaccessible or contain unsupported syntax.'
});
}
}
return { filesToModify, snapshotCount: totalSnapshots };
}
/**
* Analyzes execution transformation
* @param detectionResult - The detection result
* @param executionTransformer - The execution transformer instance
* @param storybookTransformer - The storybook transformer instance
* @param changes - Array to collect proposed changes
* @param warnings - Array to collect warnings
* @returns Analysis statistics
*/
async analyzeExecutionTransformation(detectionResult, executionTransformer, storybookTransformer, changes, warnings) {
let filesToModify = 0;
// Analyze package.json files
for (const packageFile of detectionResult.files.packageManager) {
try {
const packageFilePath = path_1.default.join(this.projectPath, packageFile);
const packageContent = await fs_1.promises.readFile(packageFilePath, 'utf-8');
let executionResult;
let description = 'Update test execution commands for SmartUI integration';
// Use StorybookTransformer for Storybook projects
if (detectionResult.testType === 'storybook') {
executionResult = storybookTransformer.transformPackageJsonScripts(packageContent, detectionResult.platform);
// Generate specific description for Storybook
const scriptCount = storybookTransformer.countStorybookScripts(packageContent, detectionResult.platform);
if (scriptCount > 0) {
const platformCommand = detectionResult.platform === 'Percy' ? 'percy storybook' :
detectionResult.platform === 'Applitools' ? 'eyes-storybook' : 'screener-storybook';
description = `Replace '${platformCommand}' command with 'smartui-storybook'`;
}
}
else {
executionResult = executionTransformer.transformPackageJson(packageContent, detectionResult.platform);
}
// Add warnings
warnings.push(...executionResult.warnings);
// Record file modification
if (executionResult.warnings.length === 0) { // Only if transformation was successful
changes.push({
filePath: packageFile,
type: 'MODIFY',
description: description
});
filesToModify++;
}
}
catch (error) {
warnings.push({
message: `Failed to analyze package file ${packageFile}: ${error instanceof Error ? error.message : 'Unknown error'}`,
details: 'The package file may be inaccessible or malformed.'
});
}
}
// Analyze CI/CD files
for (const ciFile of detectionResult.files.ci) {
try {
const ciFilePath = path_1.default.join(this.projectPath, ciFile);
const ciContent = await fs_1.promises.readFile(ciFilePath, 'utf-8');
const executionResult = executionTransformer.transformCiYaml(ciContent, detectionResult.platform);
// Add warnings
warnings.push(...executionResult.warnings);
// Record file modification
if (executionResult.warnings.length === 0) { // Only if transformation was successful
changes.push({
filePath: ciFile,
type: 'MODIFY',
description: 'Update CI/CD commands and environment variables for SmartUI'
});
filesToModify++;
}
}
catch (error) {
warnings.push({
message: `Failed to analyze CI file ${ciFile}: ${error instanceof Error ? error.message : 'Unknown error'}`,
details: 'The CI/CD file may be inaccessible or malformed.'
});
}
}
return { filesToModify };
}
}
exports.AnalysisReporter = AnalysisReporter;
//# sourceMappingURL=AnalysisReporter.js.map
;