feat(frontend): implement batch testing views and status components

Add components for batch testing, including BatchRunCompletedView and BatchRunRunningView, to display test results and progress. Introduce BatchCaseStatusBadge and BatchPhasePill for visual status representation. Implement mock data handling for batch run snapshots and case statuses, enhancing the user experience for managing batch tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xin Wang
2026-08-08 17:37:48 +08:00
parent 398b20778d
commit 21a25874a9
10 changed files with 1679 additions and 94 deletions

View File

@@ -8,6 +8,7 @@
import {
ChevronLeft,
Copy,
Loader2,
MoreHorizontal,
Pencil,
@@ -56,6 +57,8 @@ import { Textarea } from "@/components/ui/textarea";
import {
createTestCase,
createTestSuite,
duplicateTestCase,
duplicateTestSuite,
formatSuiteResult,
getTestSuite,
listTestCases,
@@ -126,6 +129,12 @@ function SuiteListView() {
router.push(`/test/cases/${suite.id}`);
}
function duplicateSuite(suite: TestSuite) {
const copied = duplicateTestSuite(suite.id);
if (!copied) return;
setSuites(listTestSuites());
}
function removeSuite(suite: TestSuite) {
if (
!window.confirm(
@@ -265,6 +274,13 @@ function SuiteListView() {
align="end"
className="w-32 min-w-32 rounded-xl border border-hairline bg-popover p-1"
>
<DropdownMenuItem
className="rounded-lg"
onSelect={() => duplicateSuite(suite)}
>
<Copy size={14} />
</DropdownMenuItem>
<DropdownMenuItem
variant="destructive"
className="rounded-lg"
@@ -565,6 +581,16 @@ function SuiteDetailView({ suiteId }: { suiteId: string }) {
window.setTimeout(() => setStatusMessage(""), 2000);
}
function handleDuplicateCase(item: TestCase) {
if (dirty && !window.confirm("当前用例有未保存修改,复制将丢弃。继续?")) {
return;
}
const copied = duplicateTestCase(item.id);
if (!copied) return;
reload(copied.id);
setStatusMessage("");
}
function handleDeleteCase(item: TestCase) {
if (!window.confirm(`确定删除测试用例“${item.name}”吗?`)) return;
removeTestCase(item.id);
@@ -696,6 +722,7 @@ function SuiteDetailView({ suiteId }: { suiteId: string }) {
onSearchChange={setSearch}
onSelectCase={selectCase}
onCreateCase={handleCreateCase}
onDuplicateCase={handleDuplicateCase}
onDeleteCase={handleDeleteCase}
onEnterSelectionMode={handleEnterSelectionMode}
onExitSelectionMode={handleExitSelectionMode}