tdpw
Version:
CLI tool for uploading Playwright test reports to TestDino platform with Azure storage support
171 lines (167 loc) • 6.76 kB
JavaScript
;
/**
* CLI argument parser using Commander.js
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.cliParser = exports.CliParser = void 0;
const commander_1 = require("commander");
const zod_1 = require("zod");
const types_1 = require("../types");
/**
* CLI argument parser and validator
*/
class CliParser {
program;
constructor() {
this.program = new commander_1.Command();
this.setupProgram();
}
/**
* Configure the CLI program with all options and metadata
*/
setupProgram() {
this.program
.name('tdpw')
.description('Upload Playwright test reports to TestDino platform')
.version('1.0.0')
.usage('<report-directory> [options]')
.argument('<report-directory>', 'Directory containing Playwright test reports (e.g., ./playwright-report)')
.option('-t, --token <value>', 'TestDino API token (required, can be set via TESTDINO_TOKEN env var)')
.option('--upload-images', 'Upload image attachments (screenshots) to TestDino server', false)
.option('--upload-videos', 'Upload video attachments to TestDino server', false)
.option('--upload-html', 'Upload HTML reports with images and videos to TestDino server', false)
.option('--upload-traces', 'Upload trace files to TestDino server (not implemented yet)', false)
.option('--json-report <path>', 'Specific path to JSON report file (auto-detected if not provided)')
.option('--html-report <path>', 'Specific path to HTML report directory (auto-detected if not provided)')
.option('--trace-dir <path>', 'Specific path to trace files directory (auto-detected if not provided)')
.option('-v, --verbose', 'Enable verbose logging for debugging', false)
.option('--dry-run', 'Validate configuration and discover reports without uploading', false)
.addHelpText('after', `
Examples:
$ npx tdpw ./playwright-report --token="trx_dev_abc123..."
$ npx tdpw ./test-results --upload-images
$ npx tdpw ./test-results --upload-html
$ npx tdpw ./reports --upload-images --upload-videos --verbose
$ npx tdpw ./custom --json-report ./custom/results.json --dry-run
Flag Combinations:
No flags: Only JSON report uploaded
--upload-images: JSON + image attachments
--upload-videos: JSON + video attachments
--upload-images --upload-videos: JSON + images + videos
--upload-html: JSON + HTML + images + videos (complete bundle)
Environment Variables:
TESTDINO_API_URL API endpoint (development only)
TESTDINO_TOKEN API authentication token
TESTDINO_UPLOAD_IMAGES Upload image attachments (true/false)
TESTDINO_UPLOAD_VIDEOS Upload video attachments (true/false)
TESTDINO_UPLOAD_HTML Upload HTML reports (true/false)
TESTDINO_UPLOAD_TRACES Upload trace files (true/false)
TESTDINO_VERBOSE Enable verbose logging (true/false)
Token Format:
API tokens must follow the format: trx_{environment}_{64-char-hex}
Example: trx_development_a1b2c3d4e5f6...
For more information, visit: https://docs.testdino.com/cli
`);
// Add error handling for unknown options
this.program.on('option:unknown', (option) => {
throw new types_1.ValidationError(`Unknown option: ${option}. Use --help to see available options.`);
});
}
/**
* Parse and validate CLI arguments
*/
parseArguments(args = process.argv) {
try {
// Parse arguments using Commander
this.program.parse(args);
const options = this.program.opts();
const reportDirectory = this.program.args[0];
// Build CLI options object
const cliOptions = {
reportDirectory,
token: options.token,
uploadImages: options.uploadImages,
uploadVideos: options.uploadVideos,
uploadHtml: options.uploadHtml,
uploadTraces: options.uploadTraces,
jsonReport: options.jsonReport,
htmlReport: options.htmlReport,
traceDir: options.traceDir,
verbose: options.verbose,
dryRun: options.dryRun,
};
// Validate using Zod schema
const validatedOptions = types_1.CLIOptionsSchema.parse(cliOptions);
// Log parsed options (with token masked) if verbose
if (validatedOptions.verbose) {
console.log('✅ Parsed CLI options:', {
...validatedOptions,
token: (0, types_1.maskToken)(validatedOptions.token),
});
}
return validatedOptions;
}
catch (error) {
if (error instanceof zod_1.z.ZodError) {
const issues = error.issues.map(issue => {
const field = issue.path.join('.');
return `${field}: ${issue.message}`;
});
throw new types_1.ValidationError(`Invalid arguments: ${issues.join(', ')}`);
}
// Re-throw other errors as-is
throw error;
}
}
/**
* Display help information
*/
showHelp() {
this.program.help();
}
/**
* Get the version string
*/
getVersion() {
return this.program.version() || '1.0.0';
}
/**
* Validate that required arguments are present
*/
validateRequiredArgs(options) {
const errors = [];
if (!options.reportDirectory) {
errors.push('Report directory is required');
}
if (!options.token) {
errors.push('API token is required (use --token or TESTDINO_TOKEN env var)');
}
if (errors.length > 0) {
throw new types_1.ValidationError(`Missing required arguments: ${errors.join(', ')}`);
}
}
/**
* Enhanced parse with better error handling
*/
parseWithErrorHandling(args = process.argv) {
try {
const options = this.parseArguments(args);
this.validateRequiredArgs(options);
return options;
}
catch (error) {
if (error instanceof types_1.ValidationError) {
console.error(`❌ ${error.message}`);
console.error('\nUse --help for usage information.');
process.exit(1);
}
throw error;
}
}
}
exports.CliParser = CliParser;
/**
* Create and export parser instance
*/
exports.cliParser = new CliParser();
//# sourceMappingURL=parser.js.map