Files
blackcanyontickets/reactrebuild0825/tests/test-runner.ts
dzinesco aa81eb5adb feat: add advanced analytics and territory management system
- Add comprehensive analytics components with export functionality
- Implement territory management with manager performance tracking
- Add seatmap components for venue layout management
- Create customer management features with modal interface
- Add advanced hooks for dashboard flags and territory data
- Implement seat selection and venue management utilities
- Add type definitions for ticketing and seatmap systems

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-26 09:25:10 -06:00

312 lines
9.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Comprehensive test runner for Black Canyon Tickets React Rebuild
*
* This script orchestrates the execution of all test suites and generates
* comprehensive reports with screenshots for QA validation.
*/
import { exec } from 'child_process';
import fs from 'fs';
import path from 'path';
import { promisify } from 'util';
const execAsync = promisify(exec);
interface TestSuite {
name: string;
file: string;
description: string;
critical: boolean;
}
const TEST_SUITES: TestSuite[] = [
{
name: 'Smoke Tests',
file: 'smoke.spec.ts',
description: 'Basic functionality and application health checks',
critical: true
},
{
name: 'Authentication (Realistic)',
file: 'auth-realistic.spec.ts',
description: 'Login flows using current component selectors',
critical: true
},
{
name: 'Authentication (Enhanced)',
file: 'auth.spec.ts',
description: 'Full auth suite requiring data-testid attributes',
critical: false
},
{
name: 'Navigation',
file: 'navigation.spec.ts',
description: 'Sidebar navigation, mobile menu, breadcrumbs, and routing',
critical: false
},
{
name: 'Theme Switching',
file: 'theme.spec.ts',
description: 'Light/dark theme transitions and persistence',
critical: false
},
{
name: 'Responsive Design',
file: 'responsive.spec.ts',
description: 'Mobile, tablet, desktop layouts and touch interactions',
critical: false
},
{
name: 'UI Components',
file: 'components.spec.ts',
description: 'Buttons, forms, cards, modals, and interactive elements',
critical: false
}
];
class TestRunner {
private results: { [key: string]: any } = {};
private readonly startTime: Date = new Date();
async run(options: { critical?: boolean; suite?: string; headed?: boolean } = {}) {
console.log('🚀 Starting Black Canyon Tickets QA Test Suite');
console.log('=' .repeat(60));
await this.ensureDirectories();
await this.clearPreviousResults();
const suitesToRun = this.filterSuites(options);
const playwrightOptions = this.buildPlaywrightOptions(options);
console.log(`📋 Running ${suitesToRun.length} test suite(s):`);
suitesToRun.forEach(suite => {
console.log(` ${suite.critical ? '🔴' : '🟡'} ${suite.name}: ${suite.description}`);
});
console.log('');
for (const suite of suitesToRun) {
await this.runTestSuite(suite, playwrightOptions);
}
await this.generateReport();
const duration = new Date().getTime() - this.startTime.getTime();
console.log(`\n✅ Test suite completed in ${Math.round(duration / 1000)}s`);
console.log(`📊 View detailed report: ./playwright-report/index.html`);
console.log(`📸 Screenshots saved to: ./screenshots/`);
}
private filterSuites(options: { critical?: boolean; suite?: string }): TestSuite[] {
if (options.suite) {
const suite = TEST_SUITES.find(s => s.name.toLowerCase().includes(options.suite!.toLowerCase()));
return suite ? [suite] : [];
}
if (options.critical) {
return TEST_SUITES.filter(s => s.critical);
}
return TEST_SUITES;
}
private buildPlaywrightOptions(options: { headed?: boolean }): string {
const opts = [];
if (options.headed) {
opts.push('--headed');
}
opts.push('--reporter=html,line');
return opts.join(' ');
}
private async ensureDirectories() {
const dirs = ['screenshots', 'test-results', 'playwright-report'];
for (const dir of dirs) {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
}
private async clearPreviousResults() {
// Clear previous screenshots
const screenshotsDir = './screenshots';
if (fs.existsSync(screenshotsDir)) {
const files = fs.readdirSync(screenshotsDir);
for (const file of files) {
if (file.endsWith('.png')) {
fs.unlinkSync(path.join(screenshotsDir, file));
}
}
}
}
private async runTestSuite(suite: TestSuite, playwrightOptions: string) {
console.log(`🧪 Running ${suite.name} tests...`);
try {
const command = `./node_modules/.bin/playwright test tests/${suite.file} ${playwrightOptions}`;
const { stdout } = await execAsync(command);
this.results[suite.name] = {
success: true,
output: stdout,
error: null,
suite
};
console.log(`${suite.name} - PASSED`);
} catch (error: any) {
this.results[suite.name] = {
success: false,
output: error.stdout || '',
error: error.stderr || error.message,
suite
};
console.log(`${suite.name} - FAILED`);
if (suite.critical) {
console.log(` 🚨 CRITICAL TEST FAILED - Consider stopping deployment`);
}
}
}
private async generateReport() {
const report = {
timestamp: new Date().toISOString(),
duration: new Date().getTime() - this.startTime.getTime(),
results: this.results,
summary: this.generateSummary()
};
// Save JSON report
fs.writeFileSync('./test-results/qa-report.json', JSON.stringify(report, null, 2));
// Generate markdown report
const markdown = this.generateMarkdownReport(report);
fs.writeFileSync('./test-results/qa-report.md', markdown);
console.log('\n📊 Test Summary:');
console.log(` Total Suites: ${Object.keys(this.results).length}`);
console.log(` Passed: ${report.summary.passed}`);
console.log(` Failed: ${report.summary.failed}`);
console.log(` Critical Failed: ${report.summary.criticalFailed}`);
}
private generateSummary() {
const total = Object.keys(this.results).length;
const passed = Object.values(this.results).filter(r => r.success).length;
const failed = total - passed;
const criticalFailed = Object.values(this.results).filter(r => !r.success && r.suite.critical).length;
return { total, passed, failed, criticalFailed };
}
private generateMarkdownReport(report: any): string {
const { summary } = report;
let markdown = `# Black Canyon Tickets QA Report\n\n`;
markdown += `**Generated:** ${new Date(report.timestamp).toLocaleString()}\n`;
markdown += `**Duration:** ${Math.round(report.duration / 1000)}s\n\n`;
markdown += `## Summary\n\n`;
markdown += `- Total Test Suites: ${summary.total}\n`;
markdown += `- ✅ Passed: ${summary.passed}\n`;
markdown += `- ❌ Failed: ${summary.failed}\n`;
markdown += `- 🚨 Critical Failed: ${summary.criticalFailed}\n\n`;
if (summary.criticalFailed > 0) {
markdown += `> ⚠️ **WARNING:** Critical tests have failed. Consider reviewing before deployment.\n\n`;
}
markdown += `## Test Results\n\n`;
for (const [name, result] of Object.entries(report.results)) {
const r = result as any;
const status = r.success ? '✅ PASSED' : '❌ FAILED';
const critical = r.suite.critical ? ' (CRITICAL)' : '';
markdown += `### ${name}${critical}\n\n`;
markdown += `**Status:** ${status}\n`;
markdown += `**Description:** ${r.suite.description}\n\n`;
if (!r.success && r.error) {
markdown += `**Error:**\n\`\`\`\n${r.error}\n\`\`\`\n\n`;
}
}
markdown += `## Screenshots\n\n`;
markdown += `All test screenshots are saved in the \`./screenshots/\` directory.\n`;
markdown += `Screenshots are organized by test suite and include timestamps.\n\n`;
markdown += `## Next Steps\n\n`;
if (summary.criticalFailed > 0) {
markdown += `1. Review failed critical tests immediately\n`;
markdown += `2. Fix critical issues before deployment\n`;
markdown += `3. Re-run critical tests to verify fixes\n`;
} else if (summary.failed > 0) {
markdown += `1. Review failed non-critical tests\n`;
markdown += `2. Consider fixing for next iteration\n`;
markdown += `3. Document known issues if acceptable\n`;
} else {
markdown += `1. All tests passed! 🎉\n`;
markdown += `2. Review screenshots for visual validation\n`;
markdown += `3. Application is ready for deployment\n`;
}
return markdown;
}
}
// CLI interface
if (require.main === module) {
const args = process.argv.slice(2);
const options: any = {};
for (let i = 0; i < args.length; i++) {
switch (args[i]) {
case '--critical':
options.critical = true;
break;
case '--suite':
options.suite = args[++i];
break;
case '--headed':
options.headed = true;
break;
case '--help':
console.log(`
Black Canyon Tickets QA Test Runner
Usage: npm run test:qa [options]
Options:
--critical Run only critical test suites
--suite NAME Run specific test suite (auth, navigation, theme, responsive, components)
--headed Run tests with visible browser windows
--help Show this help message
Examples:
npm run test:qa # Run all tests
npm run test:qa -- --critical # Run only critical tests
npm run test:qa -- --suite auth # Run only authentication tests
npm run test:qa -- --headed # Run with visible browser
`);
process.exit(0);
}
}
const runner = new TestRunner();
runner.run(options).catch(error => {
console.error('❌ Test runner failed:', error);
process.exit(1);
});
}
export default TestRunner;