| 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); |