tdpw
Version:
CLI tool for uploading Playwright test reports to TestDino platform with TestDino storage support
407 lines (381 loc) • 16.6 kB
JavaScript
"use strict";
/**
* Command registry and execution logic
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.commandManager = exports.CommandManager = void 0;
const commander_1 = require("commander");
const cache_1 = require("./commands/cache");
const last_failed_1 = require("./commands/last-failed");
const upload_1 = require("./commands/upload");
const types_1 = require("../types");
const version_1 = require("../version");
/**
* Command manager for handling subcommands and backward compatibility
*/
class CommandManager {
program;
config;
constructor() {
this.program = new commander_1.Command();
this.setupProgram();
}
/**
* Setup the main program with subcommands and backward compatibility
*/
setupProgram() {
this.program
.name('tdpw')
.description('TestDino CLI - Upload reports and cache test metadata')
.version(version_1.VERSION)
.addHelpText('after', `
Main Commands:
cache Store test execution metadata after Playwright runs
last-failed Get last failed test cases for Playwright execution
upload [report-directory] Upload test reports to TestDino
Quick Start:
$ npx tdpw cache --token="your-token" # Cache test metadata
$ npx tdpw last-failed --token="your-token" # Get failed tests
$ npx tdpw upload ./playwright-report --token="your-token" # Upload reports
$ npx tdpw upload ./playwright-report --environment="staging" --token="your-token" # Upload with environment tag
Legacy Syntax (Deprecated):
$ npx tdpw ./playwright-report --token="your-token" # Old syntax (still works)
Note: Legacy syntax without 'upload' command is deprecated and will be removed in a future version.
Environment Variables:
TESTDINO_API_URL API endpoint override
TESTDINO_TOKEN API authentication token
TESTDINO_TARGET_ENV Target environment for Testrun
For command-specific help:
$ npx tdpw cache --help
$ npx tdpw last-failed --help
$ npx tdpw upload --help
Documentation: https://docs.testdino.com/cli
`);
// Cache subcommand (store metadata)
this.program
.command('cache')
.description('Store test execution metadata after Playwright runs')
.option('--cache-id <value>', 'Custom cache ID (or TESTDINO_CACHE_ID env var)')
.option('--working-dir <path>', 'Directory to scan for test results (default: cwd)')
.option('-t, --token <value>', 'TestDino API token (or TESTDINO_TOKEN env var)')
.option('-v, --verbose', 'Verbose logging')
.action(async (options) => {
await this.executeCache(options);
});
// Last Failed subcommand (retrieve failure data)
this.program
.command('last-failed')
.description('Get last failed test cases for Playwright execution')
.option('--cache-id <value>', 'Custom cache ID (or TESTDINO_CACHE_ID env var)')
.option('--branch <name>', 'Override branch name (auto-detected from Git by default)')
.option('--commit <hash>', 'Override commit hash (auto-detected from Git by default)')
.option('-t, --token <value>', 'TestDino API token (or TESTDINO_TOKEN env var)')
.option('-v, --verbose', 'Verbose logging')
.action(async (options) => {
await this.executeLastFailed(options);
});
// Upload subcommand for backward compatibility
this.program
.command('upload')
.description('Upload test reports to TestDino')
.arguments('[report-directory]')
.option('-t, --token <value>', 'TestDino API token')
.option('--environment <value>', 'Target environment tag (e.g., staging, production, qa)')
.option('--upload-images', 'Upload image attachments', false)
.option('--upload-videos', 'Upload video attachments', false)
.option('--upload-html', 'Upload HTML reports', false)
.option('--upload-traces', 'Upload trace files', false)
.option('--upload-files', 'Upload file attachments', false)
.option('--upload-full-json', 'Upload all attachments', false)
.option('--json-report <path>', 'Specific JSON report path')
.option('--html-report <path>', 'Specific HTML report path')
.option('--trace-dir <path>', 'Specific trace directory path')
.option('-v, --verbose', 'Verbose logging', false)
.action(async (reportDirectory, options) => {
await this.executeUpload(reportDirectory, options);
});
}
/**
* Execute cache command
*/
async executeCache(options) {
try {
// Validate cache options
const validatedOptions = cache_1.CacheOptionsSchema.parse(options);
// Create configuration for cache command
const config = this.getOrCreateConfig(validatedOptions.token);
// Execute cache command
const cacheCommand = new cache_1.CacheCommand(config);
await cacheCommand.execute(validatedOptions);
}
catch (error) {
throw new types_1.ValidationError(error instanceof Error ? error.message : 'Cache command failed');
}
}
/**
* Execute last failed command
*/
async executeLastFailed(options) {
try {
// Validate last-failed options
const validatedOptions = last_failed_1.LastFailedOptionsSchema.parse(options);
// Create configuration for last failed command
const config = this.getOrCreateConfig(validatedOptions.token);
// Execute last failed command
const lastFailedCommand = new last_failed_1.LastFailedCommand(config);
await lastFailedCommand.execute(validatedOptions);
}
catch (error) {
throw new types_1.ValidationError(error instanceof Error ? error.message : 'Last failed command failed');
}
}
/**
* Execute upload command (backward compatibility)
*/
async executeUpload(reportDirectory, options) {
if (!reportDirectory) {
throw new types_1.ValidationError('Report directory is required for upload command. Use "npx tdpw cache" for caching metadata.');
}
// Resolve environment value: CLI option > env var > default
const resolvedEnvironment = this.resolveEnvironmentValue(options.environment);
// Build CLIOptions for upload command
const cliOptions = {
reportDirectory,
token: options.token || '',
uploadImages: Boolean(options.uploadImages),
uploadVideos: Boolean(options.uploadVideos),
uploadHtml: Boolean(options.uploadHtml),
uploadTraces: Boolean(options.uploadTraces),
uploadFiles: Boolean(options.uploadFiles),
uploadFullJson: Boolean(options.uploadFullJson),
jsonReport: options.jsonReport,
htmlReport: options.htmlReport,
traceDir: options.traceDir,
verbose: Boolean(options.verbose),
environment: resolvedEnvironment,
};
// Create configuration and execute
this.getOrCreateConfig(cliOptions.token); // Ensures config is created with token
const uploadCommand = new upload_1.UploadCommand();
await uploadCommand.execute(cliOptions);
}
/**
* Resolve environment value with precedence: CLI option > env var > default
* Validates format using regex: /^[a-z0-9]+([_-][a-z0-9]+)*$/
*/
resolveEnvironmentValue(cliValue) {
const defaultValue = 'unknown';
const envVarValue = process.env.TESTDINO_TARGET_ENV;
// Determine the resolved value based on precedence
let resolvedValue;
if (cliValue !== undefined && cliValue !== '') {
resolvedValue = cliValue;
}
else if (envVarValue !== undefined && envVarValue !== '') {
resolvedValue = envVarValue;
}
else {
resolvedValue = defaultValue;
}
// Skip validation for default value
if (resolvedValue === defaultValue) {
return resolvedValue;
}
// Validate format using regex
const environmentPattern = /^[a-z0-9]+([_-][a-z0-9]+)*$/;
if (!environmentPattern.test(resolvedValue)) {
throw new types_1.ValidationError(`Invalid environment value "${resolvedValue}". ` +
'Must contain only lowercase letters, numbers, hyphens, and underscores. ' +
'Examples: staging, production, qa, dev-1, test_env');
}
return resolvedValue;
}
/**
* Get or create configuration for cache command
*/
getOrCreateConfig(token) {
if (!this.config) {
this.config = this.createConfigForCache(token);
}
return this.config;
}
/**
* Create configuration specifically for cache command
*/
createConfigForCache(token) {
// Resolve token from CLI option or environment variable
const resolvedToken = token || process.env.TESTDINO_TOKEN || '';
if (!resolvedToken) {
throw new types_1.ValidationError('API token is required. Provide via --token flag or TESTDINO_TOKEN environment variable.');
}
// Create minimal config for cache command
const config = {
apiUrl: process.env.TESTDINO_API_URL || 'https://api.testdino.com',
token: resolvedToken,
uploadImages: false,
uploadVideos: false,
uploadHtml: false,
uploadTraces: false,
uploadFiles: false,
uploadFullJson: false,
verbose: false,
environment: 'unknown', // Not used by cache command
batchSize: 5,
maxConcurrentUploads: 10,
uploadTimeout: 60000,
retryAttempts: 3,
};
return config;
}
/**
* Parse and execute commands
*/
async parseAndExecute(args = process.argv) {
try {
// Note: Help handling is now done in CLI index.ts before reaching here
await this.program.parseAsync(args);
}
catch (error) {
// Re-throw with better context
throw new types_1.ValidationError(error instanceof Error ? error.message : 'Command execution failed');
}
}
/**
* Show help
*/
showHelp() {
this.program.help();
}
/**
* Show cache command help
*/
showCacheHelp() {
console.log(`
Usage: tdpw cache [options]
Store test execution metadata after Playwright runs
Options:
--cache-id <value> Custom cache ID (or TESTDINO_CACHE_ID env var)
--working-dir <path> Directory to scan for test results (default: cwd)
-t, --token <value> TestDino API token (or TESTDINO_TOKEN env var)
-v, --verbose Verbose logging
-h, --help Display help for cache command
Examples:
$ npx tdpw cache # Use TESTDINO_TOKEN env var
$ npx tdpw cache -t "trx_dev_abc123..." # Provide token directly
$ npx tdpw cache --verbose # With detailed logging
$ npx tdpw cache --working-dir ./test-results # Custom directory
$ npx tdpw cache --cache-id "custom_project_main" # Custom cache ID
Cache ID Format:
Auto-detected: ciProvider_repoName_branchName (e.g., gh_playwright-tests_main)
Custom: Any alphanumeric string with dashes/underscores (5-150 chars)
The cache ID uniquely identifies your test runs and enables the "last-failed" feature.
Use the same cache ID across workflow runs to share cache data between them.
Auto-detection:
- Cache ID: Auto-generated from CI provider, repo name, and branch
- Branch: Auto-detected from Git metadata
- Commit: Auto-detected from Git metadata
- Shard info: Automatically detected from Playwright config and JSON reports
- JSON Reports: Uses existing TestDino discovery system
- Metadata: Reuses existing Git, CI, and system collectors
Environment Variables:
TESTDINO_API_URL API endpoint override
TESTDINO_TOKEN API authentication token
TESTDINO_CACHE_ID Custom cache ID override
`);
}
/**
* Show last-failed command help
*/
showLastFailedHelp() {
console.log(`
Usage: tdpw last-failed [options]
Get last failed test cases for Playwright execution
Options:
--cache-id <value> Custom cache ID (or TESTDINO_CACHE_ID env var)
--branch <name> Override branch name (auto-detected from Git by default)
--commit <hash> Override commit hash (auto-detected from Git by default)
-t, --token <value> TestDino API token (or TESTDINO_TOKEN env var)
-v, --verbose Verbose logging
-h, --help Display help for last-failed command
Examples:
$ npx tdpw last-failed # Use TESTDINO_TOKEN env var
$ npx tdpw last-failed -t "trx_dev_abc123..." # Provide token directly
$ npx tdpw last-failed --verbose # With detailed logging
$ npx tdpw last-failed --cache-id "gh_myrepo_main" # Custom cache ID
$ npx tdpw last-failed --branch "main" # Override branch
Usage with Playwright:
# Get failed tests and run them
$ npx playwright test $(npx tdpw last-failed)
# Or store in a variable
$ FAILED_TESTS=$(npx tdpw last-failed)
$ npx playwright test $FAILED_TESTS
Output Format:
The command outputs Playwright CLI arguments for running only the failed tests:
- Single file: "tests/example.spec.ts -g \\"test1|test2\\""
- Multiple files: "-g \\"test1|test2|test3\\""
Auto-detection:
- Cache ID: Auto-generated from CI provider, repo name, and branch
- Branch: Auto-detected from Git (override with --branch)
- Commit: Auto-detected from Git (override with --commit)
Environment Variables:
TESTDINO_API_URL API endpoint override
TESTDINO_TOKEN API authentication token
TESTDINO_CACHE_ID Custom cache ID override
`);
}
/**
* Show upload command help
*/
showUploadHelp() {
console.log(`
Usage: tdpw upload [report-directory] [options]
Upload test reports to TestDino
Arguments:
report-directory Directory containing Playwright test reports
Options:
-t, --token <value> TestDino API token
--environment <value> Target environment tag (e.g., staging, production, qa)
--upload-images Upload image attachments
--upload-videos Upload video attachments
--upload-html Upload HTML reports
--upload-traces Upload trace files
--upload-files Upload file attachments
--upload-full-json Upload all attachments
--json-report <path> Specific JSON report path
--html-report <path> Specific HTML report path
--trace-dir <path> Specific trace directory path
-v, --verbose Verbose logging
-h, --help Display help for upload command
Examples:
$ npx tdpw upload ./playwright-report --token="trx_dev_abc123..."
$ npx tdpw upload ./test-results --upload-images
$ npx tdpw upload ./reports --upload-html --verbose
$ npx tdpw upload ./test-results --upload-full-json
$ npx tdpw upload ./playwright-report --environment="staging" --token="trx_dev_abc123..."
Flag Combinations:
No flags: Only JSON report uploaded
--upload-images: JSON + image attachments
--upload-videos: JSON + video attachments
--upload-files: JSON + file attachments (.md, .pdf, .txt, .log)
--upload-traces: JSON + trace files
--upload-html: JSON + HTML + images + videos (complete bundle)
--upload-full-json: JSON + images + videos + files (complete bundle)
Environment Variables:
TESTDINO_API_URL API endpoint override
TESTDINO_TOKEN API authentication token
TESTDINO_TARGET_ENV Target environment for Testrun
`);
}
/**
* Get version
*/
getVersion() {
return version_1.VERSION;
}
}
exports.CommandManager = CommandManager;
/**
* Export command manager instance
*/
exports.commandManager = new CommandManager();
//# sourceMappingURL=commands.js.map