Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 42s
CI / test-go-edu-search (push) Successful in 34s
CI / test-python-klausur (push) Failing after 2m51s
CI / test-python-agent-core (push) Successful in 21s
CI / test-nodejs-website (push) Successful in 29s
sed replacement left orphaned hostname references in story page and empty lines in getApiBase functions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
321 lines
12 KiB
TypeScript
321 lines
12 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* Test Dashboard - Zentrales Test-Registry
|
|
*
|
|
* Aggregiert alle 280+ Tests aus allen Services:
|
|
* - Go Unit Tests (~57)
|
|
* - Python Tests (~50)
|
|
* - BQAS Golden (97)
|
|
* - BQAS RAG (~20)
|
|
* - TypeScript Jest (~8)
|
|
* - SDK Vitest Unit Tests (~43)
|
|
* - SDK Playwright E2E (~25)
|
|
* - E2E Playwright (~5)
|
|
*/
|
|
|
|
import React from 'react'
|
|
import Link from 'next/link'
|
|
import { PagePurpose } from '@/components/common/PagePurpose'
|
|
import { DevOpsPipelineSidebarResponsive } from '@/components/infrastructure/DevOpsPipelineSidebar'
|
|
import type { TabType } from './types'
|
|
|
|
import { useTestDashboard } from './_hooks/useTestDashboard'
|
|
import { ToastContainer } from './_components/ToastContainer'
|
|
import { MetricCard } from './_components/MetricCard'
|
|
import { ServiceTestCard } from './_components/ServiceTestCard'
|
|
import { CoverageChart, FrameworkDistribution } from './_components/CoverageChart'
|
|
import { TestRunsTable } from './_components/TestRunsTable'
|
|
import { GuideTab } from './_components/GuideTab'
|
|
import { BacklogTab } from './_components/BacklogTab'
|
|
|
|
export default function TestDashboardPage() {
|
|
const {
|
|
activeTab,
|
|
setActiveTab,
|
|
isLoading,
|
|
error,
|
|
fetchData,
|
|
toasts,
|
|
removeToast,
|
|
services,
|
|
stats,
|
|
coverage,
|
|
testRuns,
|
|
failedTests,
|
|
backlogItems,
|
|
usePostgres,
|
|
runningServices,
|
|
serviceProgress,
|
|
updateTestStatus,
|
|
updateTestPriority,
|
|
runTests,
|
|
unitServices,
|
|
bqasServices,
|
|
} = useTestDashboard()
|
|
|
|
const renderTabContent = () => {
|
|
switch (activeTab) {
|
|
case 'overview':
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<MetricCard
|
|
title="Gesamt Tests"
|
|
value={stats?.total_tests || 195}
|
|
subtitle={`${stats?.services_count || 8} Services`}
|
|
color="orange"
|
|
/>
|
|
<MetricCard
|
|
title="Pass Rate"
|
|
value={`${stats?.overall_pass_rate?.toFixed(1) || 92.3}%`}
|
|
subtitle={`${stats?.total_passed || 180} bestanden`}
|
|
trend="up"
|
|
color="green"
|
|
/>
|
|
<MetricCard
|
|
title="Fehlgeschlagen"
|
|
value={stats?.total_failed || 15}
|
|
subtitle="Tests mit Fehlern"
|
|
color="red"
|
|
/>
|
|
<MetricCard
|
|
title="Coverage"
|
|
value={`${stats?.average_coverage?.toFixed(1) || 76.8}%`}
|
|
subtitle="Durchschnitt"
|
|
color="purple"
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
<h3 className="text-lg font-semibold text-slate-900 mb-4">Framework-Verteilung</h3>
|
|
<FrameworkDistribution data={stats?.by_framework || {}} />
|
|
</div>
|
|
|
|
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
<h3 className="text-lg font-semibold text-slate-900 mb-4">Coverage nach Service</h3>
|
|
<CoverageChart data={coverage} />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
<h3 className="text-lg font-semibold text-slate-900 mb-4">Service-Uebersicht</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
|
{services.slice(0, 8).map((service) => (
|
|
<ServiceTestCard
|
|
key={service.service}
|
|
service={service}
|
|
onRun={runTests}
|
|
isRunning={runningServices.has(service.service)}
|
|
progress={serviceProgress[service.service]}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
|
|
case 'unit':
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
<h3 className="text-lg font-semibold text-slate-900 mb-4">Unit Tests (Go & Python)</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{unitServices.map((service) => (
|
|
<ServiceTestCard
|
|
key={service.service}
|
|
service={service}
|
|
onRun={runTests}
|
|
isRunning={runningServices.has(service.service)}
|
|
progress={serviceProgress[service.service]}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
|
|
case 'bqas':
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-slate-900">BQAS (LLM Quality Assurance)</h3>
|
|
<p className="text-sm text-slate-500">Golden Suite, RAG Tests und Synthetic Tests</p>
|
|
</div>
|
|
<Link
|
|
href="/ai/test-quality"
|
|
className="px-4 py-2 bg-orange-100 text-orange-700 rounded-lg text-sm font-medium hover:bg-orange-200 transition-colors"
|
|
>
|
|
Vollstaendiges BQAS Dashboard →
|
|
</Link>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{bqasServices.map((service) => (
|
|
<ServiceTestCard
|
|
key={service.service}
|
|
service={service}
|
|
onRun={runTests}
|
|
isRunning={runningServices.has(service.service)}
|
|
progress={serviceProgress[service.service]}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-blue-50 border border-blue-200 rounded-xl p-4">
|
|
<div className="flex items-start gap-3">
|
|
<svg className="w-5 h-5 text-blue-600 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<div>
|
|
<p className="text-sm text-blue-800">
|
|
<strong>Tipp:</strong> Das vollstaendige BQAS Dashboard unter <Link href="/ai/test-quality" className="underline">/ai/test-quality</Link> bietet
|
|
detaillierte Metriken, Trend-Analyse und Intent-spezifische Scores.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
|
|
case 'history':
|
|
return (
|
|
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
|
<h3 className="text-lg font-semibold text-slate-900 mb-6">Test Run Historie</h3>
|
|
<TestRunsTable runs={testRuns} />
|
|
</div>
|
|
)
|
|
|
|
case 'backlog':
|
|
return (
|
|
<BacklogTab
|
|
failedTests={failedTests}
|
|
onStatusChange={updateTestStatus}
|
|
onPriorityChange={usePostgres ? updateTestPriority : undefined}
|
|
isLoading={isLoading}
|
|
backlogItems={backlogItems}
|
|
usePostgres={usePostgres}
|
|
/>
|
|
)
|
|
|
|
case 'guide':
|
|
return <GuideTab />
|
|
|
|
default:
|
|
return null
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<ToastContainer toasts={toasts} onDismiss={removeToast} />
|
|
|
|
<PagePurpose
|
|
title="Test Dashboard"
|
|
purpose="Zentrales Dashboard fuer alle 260+ Tests. Aggregiert Unit Tests (Go, Python), SDK Tests (Vitest), E2E Tests (Playwright) und BQAS Quality Tests aus allen Services ohne physische Migration."
|
|
audience={['Entwickler', 'QA', 'DevOps']}
|
|
architecture={{
|
|
services: ['Python Backend (Port 8000)', 'Voice Service (Port 8091)', 'SDK Backend (Port 8085)'],
|
|
databases: ['PostgreSQL', 'Qdrant'],
|
|
}}
|
|
relatedPages={[
|
|
{ name: 'BQAS Dashboard', href: '/ai/test-quality', description: 'Detaillierte LLM-Qualitaetsmetriken' },
|
|
{ name: 'CI/CD', href: '/infrastructure/ci-cd', description: 'Pipelines und Deployments' },
|
|
{ name: 'Security', href: '/infrastructure/security', description: 'DevSecOps Dashboard' },
|
|
{ name: 'Developer Portal', href: '/developers', description: 'SDK & API Dokumentation' },
|
|
]}
|
|
collapsible={true}
|
|
defaultCollapsed={true}
|
|
/>
|
|
|
|
{/* DevOps Pipeline Sidebar */}
|
|
<DevOpsPipelineSidebarResponsive currentTool="tests" />
|
|
|
|
{error && (
|
|
<div className="p-4 bg-red-50 border border-red-200 rounded-lg text-red-700 flex items-center gap-3">
|
|
<svg className="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<span>{error}</span>
|
|
<button onClick={fetchData} className="ml-auto text-red-600 hover:text-red-800 text-sm font-medium">
|
|
Erneut versuchen
|
|
</button>
|
|
</div>
|
|
)}
|
|
|
|
<div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
|
<div className="border-b border-slate-200">
|
|
<nav className="flex gap-6 px-6">
|
|
{[
|
|
{ id: 'overview', label: 'Uebersicht' },
|
|
{ id: 'unit', label: 'Unit Tests' },
|
|
{ id: 'bqas', label: 'BQAS' },
|
|
{ id: 'backlog', label: `Backlog (${failedTests.filter(t => t.status === 'open').length})`, highlight: failedTests.filter(t => t.status === 'open').length > 0 },
|
|
{ id: 'history', label: 'Historie' },
|
|
{ id: 'guide', label: 'Anleitung' },
|
|
].map((tab) => (
|
|
<button
|
|
key={tab.id}
|
|
onClick={() => setActiveTab(tab.id as TabType)}
|
|
className={`py-4 text-sm font-medium border-b-2 transition-colors ${
|
|
activeTab === tab.id
|
|
? 'border-orange-600 text-orange-600'
|
|
: 'highlight' in tab && tab.highlight
|
|
? 'border-transparent text-blue-500 hover:text-blue-600'
|
|
: 'border-transparent text-slate-500 hover:text-slate-700'
|
|
}`}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</nav>
|
|
</div>
|
|
|
|
<div className="p-6">
|
|
{isLoading ? (
|
|
<div className="flex items-center justify-center py-12">
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-orange-600"></div>
|
|
</div>
|
|
) : (
|
|
renderTabContent()
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between text-sm text-slate-500 px-2">
|
|
<div>
|
|
<span className="font-medium">Test Registry:</span> /api/tests
|
|
</div>
|
|
<div className="flex items-center gap-4">
|
|
<Link href="/ai/test-quality" className="text-orange-600 hover:text-orange-700">
|
|
BQAS Details
|
|
</Link>
|
|
<Link href="/infrastructure/ci-cd" className="text-orange-600 hover:text-orange-700">
|
|
CI/CD Pipelines
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
<style jsx>{`
|
|
@keyframes slide-in {
|
|
from {
|
|
transform: translateX(100%);
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
.animate-slide-in {
|
|
animation: slide-in 0.3s ease-out;
|
|
}
|
|
`}</style>
|
|
</div>
|
|
)
|
|
}
|