| class TestcaseDashboard extends HTMLElement { |
| connectedCallback() { |
| this.attachShadow({ mode: 'open' }); |
| this.shadowRoot.innerHTML = ` |
| <style> |
| :host { |
| --jira-bg: #F4F5F7; |
| --jira-card-bg: #FFFFFF; |
| --jira-text: #172B4D; |
| --jira-text-sub: #5E6C84; |
| --jira-border: #DFE1E6; |
| --jira-blue: #0052CC; |
| --jira-purple: #6554C0; |
| --jira-green: #00875A; |
| --jira-red: #DE350B; |
| --jira-yellow: #FF991F; |
| |
| display: block; |
| font-family: 'Inter', sans-serif; |
| width: 100%; |
| min-height: 100vh; |
| background: var(--jira-bg); |
| } |
| .header { |
| background: linear-gradient(135deg, var(--jira-blue) 0%, var(--jira-purple) 100%); |
| color: white; |
| padding: 1.5rem 2rem; |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); |
| position: sticky; |
| top: 0; |
| z-index: 100; |
| } |
| .filter-bar { |
| display: flex; |
| gap: 0.75rem; |
| padding: 1rem; |
| background: var(--jira-card-bg); |
| border-radius: 4px; |
| margin: 1rem 0; |
| box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25); |
| } |
| |
| .search-input { |
| border: none; |
| border-bottom: 2px solid var(--jira-border); |
| padding: 0.5rem 0; |
| width: 200px; |
| transition: border-color 0.2s; |
| } |
| |
| .search-input:focus { |
| outline: none; |
| border-bottom-color: var(--jira-blue); |
| } |
| |
| .filter-btn { |
| background: transparent; |
| border: 1px solid transparent; |
| color: var(--jira-text-sub); |
| font-weight: 500; |
| padding: 0.5rem 1rem; |
| border-radius: 4px; |
| cursor: pointer; |
| } |
| |
| .filter-btn:hover { |
| background: rgba(9,30,66,0.08); |
| } |
| |
| .filter-btn.active { |
| background: #DEEBFF; |
| color: var(--jira-blue); |
| font-weight: 600; |
| } |
| .testcase-card { |
| background: var(--jira-card-bg); |
| border: 1px solid var(--jira-border); |
| border-radius: 4px; |
| margin-bottom: 0.75rem; |
| box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25); |
| transition: all 0.2s ease; |
| position: relative; |
| overflow: hidden; |
| } |
| |
| .testcase-card:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 4px 8px rgba(9, 30, 66, 0.15); |
| } |
| |
| .testcase-card-header { |
| display: flex; |
| align-items: center; |
| padding: 0.75rem 1rem; |
| border-bottom: 1px solid var(--jira-border); |
| background: rgba(244, 245, 247, 0.5); |
| } |
| |
| .testcase-card-body { |
| padding: 1rem; |
| } |
| |
| .testcase-card-footer { |
| display: flex; |
| justify-content: space-between; |
| padding: 0.75rem 1rem; |
| border-top: 1px solid var(--jira-border); |
| background: rgba(244, 245, 247, 0.5); |
| } |
| .project-badge { |
| background: #DEEBFF; |
| color: #0747A6; |
| padding: 0.25rem 0.5rem; |
| border-radius: 3px; |
| font-size: 0.75rem; |
| font-weight: 500; |
| margin-right: 0.5rem; |
| } |
| |
| .module-badge { |
| background: #EAE6FF; |
| color: #403294; |
| padding: 0.25rem 0.5rem; |
| border-radius: 3px; |
| font-size: 0.75rem; |
| font-weight: 500; |
| margin-right: 0.5rem; |
| } |
| |
| .fsd-badge { |
| background: #E3FCEF; |
| color: #006644; |
| padding: 0.25rem 0.5rem; |
| border-radius: 3px; |
| font-size: 0.75rem; |
| font-weight: 500; |
| margin-right: 0.5rem; |
| } |
| |
| .user-story-badge { |
| background: #E3FCEF; |
| color: #006644; |
| padding: 0.25rem 0.5rem; |
| border-radius: 3px; |
| font-size: 0.75rem; |
| font-weight: 500; |
| } |
| |
| .priority-badge { |
| display: inline-block; |
| padding: 0.25rem 0.5rem; |
| border-radius: 3px; |
| font-size: 0.75rem; |
| font-weight: 500; |
| } |
| |
| .priority-high { |
| background: #FFEBE6; |
| color: #DE350B; |
| } |
| |
| .priority-medium { |
| background: #FFF0B3; |
| color: #FF991F; |
| } |
| |
| .priority-low { |
| background: #E3FCEF; |
| color: #00875A; |
| } |
| |
| .edit-btn { |
| background: transparent; |
| border: 1px solid var(--jira-border); |
| color: var(--jira-text-sub); |
| padding: 0.25rem 0.5rem; |
| border-radius: 3px; |
| cursor: pointer; |
| font-size: 0.75rem; |
| transition: all 0.2s; |
| } |
| |
| .edit-btn:hover { |
| background: rgba(9,30,66,0.08); |
| color: var(--jira-blue); |
| } |
| .status-indicator { |
| width: 4px; |
| height: 100%; |
| position: absolute; |
| left: 0; |
| top: 0; |
| } |
| |
| .status-pass { background: var(--jira-green); } |
| .status-fail { background: var(--jira-red); } |
| .status-none { background: var(--jira-border); } |
| |
| .type-icon { |
| width: 24px; |
| height: 24px; |
| border-radius: 4px; |
| display: inline-flex; |
| align-items: center; |
| justify-content: center; |
| margin-right: 0.75rem; |
| } |
| |
| .type-manual { background: #EAE6FF; color: #403294; } |
| .type-ui { background: #E3FCEF; color: #006644; } |
| .type-api { background: #DEEBFF; color: #0747A6; } |
| |
| .container { |
| max-width: 1400px; |
| margin: 0 auto; |
| padding: 0 2rem; |
| } |
| |
| .grid { |
| display: grid; |
| grid-template-columns: 1fr 300px; |
| gap: 1.5rem; |
| } |
| .stats-card { |
| background: var(--jira-card-bg); |
| border-radius: 4px; |
| padding: 1rem; |
| box-shadow: 0 1px 1px rgba(9, 30, 66, 0.25); |
| position: sticky; |
| top: 100px; |
| } |
| |
| .stats-grid { |
| display: grid; |
| grid-template-columns: repeat(2, 1fr); |
| gap: 1rem; |
| margin-top: 1rem; |
| } |
| |
| .stat-item { |
| background: rgba(244, 245, 247, 0.5); |
| border-radius: 4px; |
| padding: 0.75rem; |
| text-align: center; |
| } |
| |
| .stat-value { |
| font-size: 1.5rem; |
| font-weight: 600; |
| } |
| |
| .stat-label { |
| font-size: 0.75rem; |
| color: var(--jira-text-sub); |
| } |
| |
| .type-filter { |
| margin-top: 1rem; |
| } |
| |
| .type-filter-item { |
| display: flex; |
| align-items: center; |
| padding: 0.5rem; |
| border-radius: 4px; |
| cursor: pointer; |
| } |
| |
| .type-filter-item:hover { |
| background: rgba(9,30,66,0.08); |
| } |
| |
| .type-filter-count { |
| margin-left: auto; |
| color: var(--jira-text-sub); |
| font-size: 0.75rem; |
| } |
| </style> |
| |
| <div class="header"> |
| <div class="container"> |
| <h1>TestCase Visualizer Pro</h1> |
| <p>Project: FSD Integration • Module: Test Management</p> |
| </div> |
| </div> |
| |
| <div class="container"> |
| <div class="grid"> |
| <main> |
| <div class="filter-bar"> |
| <input type="text" class="search-input" placeholder="Search test cases..."> |
| <select class="filter-btn" multiple> |
| <option value="SIT">SIT</option> |
| <option value="UAT">UAT</option> |
| <option value="PVT">PVT</option> |
| </select> |
| <select class="filter-btn" multiple> |
| <option value="Manual">Manual</option> |
| <option value="UI Auto">UI Auto</option> |
| <option value="API Auto">API Auto</option> |
| <option value="Performance">Performance</option> |
| <option value="Security">Security</option> |
| </select> |
| <select class="filter-btn" multiple> |
| <option value="Passed">Passed</option> |
| <option value="Failed">Failed</option> |
| <option value="Pending">Pending</option> |
| </select> |
| <button class="filter-btn active" id="clear-filters">Clear Filters</button> |
| <button class="filter-btn" id="save-filters">Save Filter Preset</button> |
| </div> |
| |
| <div class="testcase-list"> |
| ${this.generateTestCases()} |
| </div> |
| </main> |
| |
| <aside> |
| <div class="stats-card"> |
| <h3>Statistics</h3> |
| <div class="stats-grid"> |
| ${this.generateStats()} |
| </div> |
| |
| <div class="type-filter"> |
| <h4 class="mt-4 mb-2">Test Types</h4> |
| <div class="type-filter-item"> |
| <span>👨💻 Manual</span> |
| <span class="type-filter-count">12</span> |
| </div> |
| <div class="type-filter-item"> |
| <span>🖥️ UI Auto</span> |
| <span class="type-filter-count">8</span> |
| </div> |
| <div class="type-filter-item"> |
| <span>🔌 API Auto</span> |
| <span class="type-filter-count">15</span> |
| </div> |
| <div class="type-filter-item"> |
| <span>⏱️ Performance</span> |
| <span class="type-filter-count">5</span> |
| </div> |
| <div class="type-filter-item"> |
| <span>🔒 Security</span> |
| <span class="type-filter-count">3</span> |
| </div> |
| </div> |
| </div> |
| </aside> |
| </div> |
| </div> |
| `; |
| } |
| generateTestCases() { |
| const testCases = [ |
| { |
| id: 'TC-001', |
| title: 'User authentication validation', |
| type: 'Manual', |
| status: 'Passed', |
| stages: ['SIT', 'UAT'], |
| priority: 'High', |
| project: 'PROJ-1', |
| module: 'AUTH-MOD', |
| fsd: 'FSD-101', |
| userStory: 'US-42', |
| description: 'Validate user can authenticate with valid credentials', |
| steps: '1. Navigate to login page\n2. Enter valid credentials\n3. Click login button', |
| expected: 'User should be authenticated and redirected to dashboard' |
| }, |
| { |
| id: 'TC-002', |
| title: 'API endpoint response validation', |
| type: 'API Auto', |
| status: 'Failed', |
| stages: ['UAT', 'PVT'], |
| priority: 'Medium', |
| project: 'PROJ-1', |
| module: 'API-MOD', |
| fsd: 'FSD-102', |
| userStory: 'US-43', |
| description: 'Validate API returns correct response format', |
| steps: '1. Send GET request to /api/users\n2. Verify response format', |
| expected: 'Response should match OpenAPI specification' |
| }, |
| { |
| id: 'TC-003', |
| title: 'UI component rendering test', |
| type: 'UI Auto', |
| status: 'Pending', |
| stages: ['SIT', 'UAT', 'PVT'], |
| priority: 'Low', |
| project: 'PROJ-2', |
| module: 'UI-MOD', |
| fsd: 'FSD-103', |
| userStory: 'US-44', |
| description: 'Verify dashboard components render correctly', |
| steps: '1. Load dashboard page\n2. Check all components', |
| expected: 'All components should render without errors' |
| }, |
| { |
| id: 'TC-004', |
| title: 'Performance benchmark', |
| type: 'Performance', |
| status: 'Passed', |
| stages: ['SIT'], |
| priority: 'Medium', |
| project: 'PROJ-2', |
| module: 'PERF-MOD', |
| fsd: 'FSD-104', |
| userStory: 'US-45', |
| description: 'Measure API response times under load', |
| steps: '1. Run load test with 1000 concurrent users\n2. Record response times', |
| expected: '95% of requests should complete in <500ms' |
| }, |
| { |
| id: 'TC-005', |
| title: 'Security vulnerability scan', |
| type: 'Security', |
| status: 'Failed', |
| stages: ['UAT', 'PVT'], |
| priority: 'High', |
| project: 'PROJ-3', |
| module: 'SEC-MOD', |
| fsd: 'FSD-105', |
| userStory: 'US-46', |
| description: 'Check for common security vulnerabilities', |
| steps: '1. Run OWASP ZAP scan\n2. Analyze results', |
| expected: 'No critical vulnerabilities found' |
| } |
| ]; |
| return testCases.map(tc => ` |
| <div class="testcase-card" data-id="${tc.id}"> |
| <div class="status-indicator status-${tc.status.toLowerCase()}"></div> |
| <div class="testcase-card-header"> |
| <span class="project-badge">${tc.project}</span> |
| <span class="module-badge">${tc.module}</span> |
| <span class="fsd-badge">${tc.fsd}</span> |
| <span class="user-story-badge">${tc.userStory}</span> |
| <button class="edit-btn ml-auto" onclick="this.closest('.testcase-card').classList.toggle('expanded')"> |
| Edit |
| </button> |
| </div> |
| <div class="testcase-card-body"> |
| <div class="flex items-center"> |
| <div class="type-icon type-${tc.type.toLowerCase().replace(' ', '-')}"> |
| ${this.getTypeIcon(tc.type)} |
| </div> |
| <div> |
| <div class="font-medium">${tc.title}</div> |
| <div class="text-sm text-gray-600">${tc.id} • ${tc.stages.join(', ')}</div> |
| </div> |
| <div class="ml-auto"> |
| <span class="priority-badge priority-${tc.priority.toLowerCase()}">${tc.priority}</span> |
| </div> |
| </div> |
| <div class="mt-3"> |
| <div class="text-sm"><strong>Description:</strong> ${tc.description}</div> |
| <div class="text-sm mt-1"><strong>Steps:</strong><pre>${tc.steps}</pre></div> |
| <div class="text-sm mt-1"><strong>Expected:</strong> ${tc.expected}</div> |
| </div> |
| </div> |
| <div class="testcase-card-footer"> |
| <div class="text-xs text-gray-500"> |
| Last updated: ${new Date().toLocaleDateString()} • |
| Used in: ${tc.stages.map(s => `<span class="stage-tag">${s}</span>`).join(' ')} |
| </div> |
| <div class="flex gap-2"> |
| <button class="edit-btn">Comment</button> |
| <button class="edit-btn">Attach</button> |
| <button class="edit-btn">Clone</button> |
| </div> |
| </div> |
| </div> |
| `).join(''); |
| } |
|
|
| generateStats() { |
| return ` |
| <div class="stat-item"> |
| <div class="stat-value">24</div> |
| <div class="stat-label">Total</div> |
| </div> |
| <div class="stat-item"> |
| <div class="stat-value text-green-600">18</div> |
| <div class="stat-label">Passed</div> |
| </div> |
| <div class="stat-item"> |
| <div class="stat-value text-red-600">3</div> |
| <div class="stat-label">Failed</div> |
| </div> |
| <div class="stat-item"> |
| <div class="stat-value text-yellow-600">3</div> |
| <div class="stat-label">Pending</div> |
| </div> |
| `; |
| } |
| getTypeIcon(type) { |
| const icons = { |
| 'Manual': '👨💻', |
| 'UI Auto': '🖥️', |
| 'API Auto': '🔌', |
| 'Performance': '⏱️', |
| 'Security': '🔒', |
| 'Accessibility': '♿', |
| 'Compatibility': '🔄', |
| 'Regression': '🔁' |
| }; |
| return icons[type] || '📋'; |
| } |
| } |
|
|
| customElements.define('testcase-dashboard', TestcaseDashboard); |