142 lines
2.9 KiB
TypeScript
142 lines
2.9 KiB
TypeScript
|
|
/** Test results card sub-components for WorkItemDetailPanel. */
|
||
|
|
|
||
|
|
import type { TestCaseResult, TestResultsResponse } from "../api/client";
|
||
|
|
|
||
|
|
function TestCaseRow({ tc }: { tc: TestCaseResult }) {
|
||
|
|
const isPassing = tc.status === "pass";
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
data-testid={`test-case-${tc.name}`}
|
||
|
|
style={{
|
||
|
|
display: "flex",
|
||
|
|
flexDirection: "column",
|
||
|
|
gap: "2px",
|
||
|
|
padding: "4px 0",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<div style={{ display: "flex", alignItems: "center", gap: "6px" }}>
|
||
|
|
<span
|
||
|
|
data-testid={`test-status-${tc.name}`}
|
||
|
|
style={{
|
||
|
|
fontSize: "0.85em",
|
||
|
|
color: isPassing ? "#3fb950" : "#f85149",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{isPassing ? "PASS" : "FAIL"}
|
||
|
|
</span>
|
||
|
|
<span style={{ fontSize: "0.82em", color: "#ccc" }}>{tc.name}</span>
|
||
|
|
</div>
|
||
|
|
{tc.details && (
|
||
|
|
<div
|
||
|
|
data-testid={`test-details-${tc.name}`}
|
||
|
|
style={{
|
||
|
|
fontSize: "0.75em",
|
||
|
|
color: "#888",
|
||
|
|
paddingLeft: "22px",
|
||
|
|
whiteSpace: "pre-wrap",
|
||
|
|
wordBreak: "break-word",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{tc.details}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
function TestSection({
|
||
|
|
title,
|
||
|
|
tests,
|
||
|
|
testId,
|
||
|
|
}: {
|
||
|
|
title: string;
|
||
|
|
tests: TestCaseResult[];
|
||
|
|
testId: string;
|
||
|
|
}) {
|
||
|
|
const passCount = tests.filter((t) => t.status === "pass").length;
|
||
|
|
const failCount = tests.length - passCount;
|
||
|
|
return (
|
||
|
|
<div data-testid={testId}>
|
||
|
|
<div
|
||
|
|
style={{
|
||
|
|
fontSize: "0.78em",
|
||
|
|
fontWeight: 600,
|
||
|
|
color: "#aaa",
|
||
|
|
marginBottom: "6px",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
{title} ({passCount} passed, {failCount} failed)
|
||
|
|
</div>
|
||
|
|
{tests.length === 0 ? (
|
||
|
|
<div style={{ fontSize: "0.75em", color: "#555", fontStyle: "italic" }}>
|
||
|
|
No tests recorded
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
tests.map((tc) => <TestCaseRow key={tc.name} tc={tc} />)
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Renders the "Test Results" card in the detail panel. */
|
||
|
|
export function TestResultsSection({
|
||
|
|
testResults,
|
||
|
|
}: {
|
||
|
|
testResults: TestResultsResponse | null;
|
||
|
|
}) {
|
||
|
|
const hasTestResults =
|
||
|
|
testResults &&
|
||
|
|
(testResults.unit.length > 0 || testResults.integration.length > 0);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
data-testid="test-results-section"
|
||
|
|
style={{
|
||
|
|
border: "1px solid #2a2a2a",
|
||
|
|
borderRadius: "8px",
|
||
|
|
padding: "10px 12px",
|
||
|
|
background: "#161616",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<div
|
||
|
|
style={{
|
||
|
|
fontWeight: 600,
|
||
|
|
fontSize: "0.8em",
|
||
|
|
color: "#555",
|
||
|
|
marginBottom: "8px",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
Test Results
|
||
|
|
</div>
|
||
|
|
{hasTestResults ? (
|
||
|
|
<div
|
||
|
|
data-testid="test-results-content"
|
||
|
|
style={{
|
||
|
|
display: "flex",
|
||
|
|
flexDirection: "column",
|
||
|
|
gap: "12px",
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<TestSection
|
||
|
|
title="Unit Tests"
|
||
|
|
tests={testResults.unit}
|
||
|
|
testId="test-section-unit"
|
||
|
|
/>
|
||
|
|
<TestSection
|
||
|
|
title="Integration Tests"
|
||
|
|
tests={testResults.integration}
|
||
|
|
testId="test-section-integration"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<div
|
||
|
|
data-testid="test-results-empty"
|
||
|
|
style={{ fontSize: "0.75em", color: "#444" }}
|
||
|
|
>
|
||
|
|
No test results recorded
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|