Spaces:
Paused
Paused
| import { Component, inject } from '@angular/core'; | |
| import { CommonModule } from '@angular/common'; | |
| import { FormsModule } from '@angular/forms'; | |
| import { ApiService } from '../../services/api.service'; | |
| interface TestResult { | |
| name: string; | |
| status: 'PASS' | 'FAIL' | 'RUNNING'; | |
| duration_ms?: number; | |
| error?: string; | |
| } | |
| interface TestRun { | |
| test_type: string; | |
| start_time: string; | |
| tests: TestResult[]; | |
| summary: { | |
| total: number; | |
| passed: number; | |
| failed: number; | |
| duration_ms: number; | |
| }; | |
| } | |
| ({ | |
| selector: 'app-test', | |
| standalone: true, | |
| imports: [CommonModule, FormsModule], | |
| template: ` | |
| <div class="test-container"> | |
| <h2>System Tests</h2> | |
| <div class="test-controls"> | |
| <button class="btn btn-primary" (click)="runAllTests()" [disabled]="running"> | |
| Run All Tests | |
| </button> | |
| <button class="btn btn-secondary" (click)="runSelectedTests()" [disabled]="running || selectedTests.length === 0"> | |
| Run Selected | |
| </button> | |
| <button class="btn btn-danger" (click)="stopTests()" [disabled]="!running"> | |
| Stop | |
| </button> | |
| </div> | |
| <div class="test-categories"> | |
| <div class="category"> | |
| <label> | |
| <input type="checkbox" [(ngModel)]="allSelected" (change)="toggleAll()"> | |
| <strong>All Tests</strong> | |
| </label> | |
| </div> | |
| <div class="category"> | |
| <label> | |
| <input type="checkbox" [(ngModel)]="categories.ui" (change)="updateSelection()"> | |
| UI Tests (15 tests) | |
| </label> | |
| <div class="sub-tests" *ngIf="categories.ui"> | |
| <label><input type="checkbox"> Login Flow</label> | |
| <label><input type="checkbox"> Project CRUD</label> | |
| <label><input type="checkbox"> Version Management</label> | |
| </div> | |
| </div> | |
| <div class="category"> | |
| <label> | |
| <input type="checkbox" [(ngModel)]="categories.backend" (change)="updateSelection()"> | |
| Backend Tests (22 tests) | |
| </label> | |
| <div class="sub-tests" *ngIf="categories.backend"> | |
| <label><input type="checkbox"> Authentication</label> | |
| <label><input type="checkbox"> API Endpoints</label> | |
| <label><input type="checkbox"> Race Conditions</label> | |
| </div> | |
| </div> | |
| <div class="category"> | |
| <label> | |
| <input type="checkbox" [(ngModel)]="categories.integration" (change)="updateSelection()"> | |
| Integration Tests (18 tests) | |
| </label> | |
| </div> | |
| <div class="category"> | |
| <label> | |
| <input type="checkbox" [(ngModel)]="categories.spark" (change)="updateSelection()"> | |
| Spark Tests (8 tests) | |
| </label> | |
| </div> | |
| </div> | |
| @if (currentRun) { | |
| <div class="test-results"> | |
| <h3>Test Results:</h3> | |
| <div class="results-list"> | |
| @for (test of currentRun.tests; track test.name) { | |
| <div class="test-result" [class.pass]="test.status === 'PASS'" [class.fail]="test.status === 'FAIL'"> | |
| @if (test.status === 'PASS') { | |
| <span class="status">β</span> | |
| } @else if (test.status === 'FAIL') { | |
| <span class="status">β</span> | |
| } @else { | |
| <span class="status spinner"></span> | |
| } | |
| <span class="name">{{ test.name }}</span> | |
| @if (test.duration_ms) { | |
| <span class="duration">{{ test.duration_ms }}ms</span> | |
| } | |
| @if (test.error) { | |
| <div class="error">{{ test.error }}</div> | |
| } | |
| </div> | |
| } | |
| </div> | |
| @if (!running && currentRun.summary) { | |
| <div class="test-summary"> | |
| <div class="progress-bar"> | |
| <div | |
| class="progress-fill" | |
| [style.width.%]="(currentRun.summary.passed / currentRun.summary.total) * 100" | |
| [class.success]="currentRun.summary.failed === 0" | |
| [class.warning]="currentRun.summary.failed > 0" | |
| ></div> | |
| </div> | |
| <div class="summary-text"> | |
| Progress: {{ currentRun.summary.passed + currentRun.summary.failed }}/{{ currentRun.summary.total }} | |
| ({{ ((currentRun.summary.passed / currentRun.summary.total) * 100).toFixed(0) }}%) | |
| </div> | |
| <div class="summary-stats"> | |
| Passed: {{ currentRun.summary.passed }} | | |
| Failed: {{ currentRun.summary.failed }} | | |
| Total time: {{ (currentRun.summary.duration_ms / 1000).toFixed(1) }}s | |
| </div> | |
| </div> | |
| } | |
| </div> | |
| } | |
| @if (!currentRun && !running) { | |
| <div class="empty-state"> | |
| <p>No test results yet. Click "Run All Tests" to start.</p> | |
| </div> | |
| } | |
| </div> | |
| `, | |
| styles: [` | |
| .test-container { | |
| h2 { | |
| margin-bottom: 1.5rem; | |
| } | |
| } | |
| .test-controls { | |
| display: flex; | |
| gap: 0.5rem; | |
| margin-bottom: 1.5rem; | |
| } | |
| .test-categories { | |
| background: white; | |
| border: 1px solid #dee2e6; | |
| border-radius: 0.25rem; | |
| padding: 1rem; | |
| margin-bottom: 1.5rem; | |
| .category { | |
| margin-bottom: 0.5rem; | |
| label { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| cursor: pointer; | |
| input[type="checkbox"] { | |
| cursor: pointer; | |
| } | |
| } | |
| } | |
| .sub-tests { | |
| margin-left: 1.5rem; | |
| margin-top: 0.5rem; | |
| label { | |
| display: block; | |
| margin-bottom: 0.25rem; | |
| font-weight: normal; | |
| color: #6c757d; | |
| } | |
| } | |
| } | |
| .test-results { | |
| background: white; | |
| border: 1px solid #dee2e6; | |
| border-radius: 0.25rem; | |
| padding: 1rem; | |
| h3 { | |
| margin-top: 0; | |
| margin-bottom: 1rem; | |
| } | |
| .results-list { | |
| max-height: 400px; | |
| overflow-y: auto; | |
| margin-bottom: 1rem; | |
| } | |
| .test-result { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| padding: 0.5rem; | |
| border-bottom: 1px solid #f0f0f0; | |
| &.pass .status { color: #28a745; } | |
| &.fail .status { color: #dc3545; } | |
| .status { | |
| width: 20px; | |
| text-align: center; | |
| } | |
| .name { | |
| flex: 1; | |
| } | |
| .duration { | |
| color: #6c757d; | |
| font-size: 0.875rem; | |
| } | |
| .error { | |
| width: 100%; | |
| margin-top: 0.5rem; | |
| padding: 0.5rem; | |
| background-color: #f8d7da; | |
| color: #721c24; | |
| border-radius: 0.25rem; | |
| font-size: 0.875rem; | |
| } | |
| } | |
| } | |
| .test-summary { | |
| border-top: 1px solid #dee2e6; | |
| padding-top: 1rem; | |
| .progress-bar { | |
| height: 20px; | |
| background-color: #e9ecef; | |
| border-radius: 0.25rem; | |
| overflow: hidden; | |
| margin-bottom: 0.5rem; | |
| .progress-fill { | |
| height: 100%; | |
| transition: width 0.3s ease; | |
| &.success { background-color: #28a745; } | |
| &.warning { background-color: #ffc107; } | |
| } | |
| } | |
| .summary-text, .summary-stats { | |
| text-align: center; | |
| color: #6c757d; | |
| margin-bottom: 0.5rem; | |
| } | |
| } | |
| .empty-state { | |
| text-align: center; | |
| padding: 3rem; | |
| background-color: white; | |
| border-radius: 0.25rem; | |
| p { | |
| color: #6c757d; | |
| } | |
| } | |
| `] | |
| }) | |
| export class TestComponent { | |
| private apiService = inject(ApiService); | |
| running = false; | |
| allSelected = false; | |
| categories = { | |
| ui: false, | |
| backend: false, | |
| integration: false, | |
| spark: false | |
| }; | |
| selectedTests: string[] = []; | |
| currentRun: TestRun | null = null; | |
| toggleAll() { | |
| this.categories.ui = this.allSelected; | |
| this.categories.backend = this.allSelected; | |
| this.categories.integration = this.allSelected; | |
| this.categories.spark = this.allSelected; | |
| this.updateSelection(); | |
| } | |
| updateSelection() { | |
| this.selectedTests = []; | |
| if (this.categories.ui) this.selectedTests.push('ui'); | |
| if (this.categories.backend) this.selectedTests.push('backend'); | |
| if (this.categories.integration) this.selectedTests.push('integration'); | |
| if (this.categories.spark) this.selectedTests.push('spark'); | |
| this.allSelected = this.selectedTests.length === 4; | |
| } | |
| runAllTests() { | |
| this.running = true; | |
| this.apiService.runTests('all').subscribe({ | |
| next: (result) => { | |
| this.currentRun = result; | |
| this.running = false; | |
| }, | |
| error: (err) => { | |
| console.error('Test run failed:', err); | |
| this.running = false; | |
| } | |
| }); | |
| } | |
| runSelectedTests() { | |
| // TODO: Implement selected tests | |
| console.log('Running selected tests:', this.selectedTests); | |
| this.runAllTests(); // For now, just run all | |
| } | |
| stopTests() { | |
| this.running = false; | |
| // TODO: Implement stop functionality | |
| } | |
| } |