feat: test case detail dialog
This commit is contained in:
@@ -201,12 +201,12 @@
|
|||||||
"template": "Template",
|
"template": "Template",
|
||||||
"test_detail": "Test detail",
|
"test_detail": "Test detail",
|
||||||
"preconditions": "Preconditions",
|
"preconditions": "Preconditions",
|
||||||
|
"expected_result": "Expected result",
|
||||||
"step": "Step",
|
"step": "Step",
|
||||||
"text": "Text",
|
"text": "Text",
|
||||||
"steps": "Steps",
|
"steps": "Steps",
|
||||||
"new_step": "New Step",
|
"new_step": "New Step",
|
||||||
"details_of_the_step": "Details of the step",
|
"details_of_the_step": "Details of the step",
|
||||||
"expected_result": "Expected result",
|
|
||||||
"delete_this_step": "Delete this step",
|
"delete_this_step": "Delete this step",
|
||||||
"insert_step": "Insert step",
|
"insert_step": "Insert step",
|
||||||
"attachments": "Attachments",
|
"attachments": "Attachments",
|
||||||
@@ -272,7 +272,25 @@
|
|||||||
"include_in_run": "Include in run",
|
"include_in_run": "Include in run",
|
||||||
"exclude_from_run": "Exclude from run",
|
"exclude_from_run": "Exclude from run",
|
||||||
"no_cases_found": "No cases found",
|
"no_cases_found": "No cases found",
|
||||||
"are_you_sure_leave": "Are you sure you want to leave the page?"
|
"are_you_sure_leave": "Are you sure you want to leave the page?",
|
||||||
|
"type": "Type",
|
||||||
|
"other": "Other",
|
||||||
|
"security": "Security",
|
||||||
|
"performance": "Performance",
|
||||||
|
"accessibility": "Accessibility",
|
||||||
|
"functional": "Functional",
|
||||||
|
"acceptance": "Acceptance",
|
||||||
|
"usability": "Usability",
|
||||||
|
"smoke_sanity": "Smoke&Sanity",
|
||||||
|
"compatibility": "Compatibility",
|
||||||
|
"destructive": "Destructive",
|
||||||
|
"regression": "Regression",
|
||||||
|
"automated": "Automated",
|
||||||
|
"manual": "Manual",
|
||||||
|
"preconditions": "Preconditions",
|
||||||
|
"expected_result": "Expected result",
|
||||||
|
"details_of_the_step": "Details of the step",
|
||||||
|
"close": "Close"
|
||||||
},
|
},
|
||||||
"Members": {
|
"Members": {
|
||||||
"member_management": "Member Management",
|
"member_management": "Member Management",
|
||||||
|
|||||||
@@ -201,12 +201,12 @@
|
|||||||
"template": "テンプレート",
|
"template": "テンプレート",
|
||||||
"test_detail": "テスト詳細",
|
"test_detail": "テスト詳細",
|
||||||
"preconditions": "前提条件",
|
"preconditions": "前提条件",
|
||||||
|
"expected_result": "期待結果",
|
||||||
"step": "ステップ",
|
"step": "ステップ",
|
||||||
"text": "テキスト",
|
"text": "テキスト",
|
||||||
"steps": "ステップ",
|
"steps": "ステップ",
|
||||||
"new_step": "新規ステップ",
|
"new_step": "新規ステップ",
|
||||||
"details_of_the_step": "ステップ詳細",
|
"details_of_the_step": "ステップ詳細",
|
||||||
"expected_result": "期待結果",
|
|
||||||
"delete_this_step": "このステップを削除",
|
"delete_this_step": "このステップを削除",
|
||||||
"insert_step": "ステップを挿入",
|
"insert_step": "ステップを挿入",
|
||||||
"attachments": "添付ファイル",
|
"attachments": "添付ファイル",
|
||||||
@@ -272,7 +272,26 @@
|
|||||||
"include_in_run": "テストランに含める",
|
"include_in_run": "テストランに含める",
|
||||||
"exclude_from_run": "テストランから除外する",
|
"exclude_from_run": "テストランから除外する",
|
||||||
"no_cases_found": "テストケースが見つかりません",
|
"no_cases_found": "テストケースが見つかりません",
|
||||||
"are_you_sure_leave": "ページを離れてもよろしいですか"
|
"are_you_sure_leave": "ページを離れてもよろしいですか",
|
||||||
|
"type": "タイプ",
|
||||||
|
"other": "その他",
|
||||||
|
"security": "セキュリティ",
|
||||||
|
"performance": "パフォーマンス",
|
||||||
|
"accessibility": "アクセシビリティ",
|
||||||
|
"functional": "機能",
|
||||||
|
"acceptance": "受け入れ",
|
||||||
|
"usability": "ユーザビリティ",
|
||||||
|
"smoke_sanity": "スモーク/サニティ",
|
||||||
|
"compatibility": "互換性",
|
||||||
|
"destructive": "破壊",
|
||||||
|
"regression": "回帰",
|
||||||
|
"automated": "自動",
|
||||||
|
"manual": "手動",
|
||||||
|
"test_detail": "テスト詳細",
|
||||||
|
"preconditions": "前提条件",
|
||||||
|
"expected_result": "期待結果",
|
||||||
|
"details_of_the_step": "ステップ詳細",
|
||||||
|
"close": "閉じる"
|
||||||
},
|
},
|
||||||
"Members": {
|
"Members": {
|
||||||
"member_management": "メンバー管理",
|
"member_management": "メンバー管理",
|
||||||
|
|||||||
@@ -43,12 +43,12 @@ export default function Page({
|
|||||||
template: t('template'),
|
template: t('template'),
|
||||||
testDetail: t('test_detail'),
|
testDetail: t('test_detail'),
|
||||||
preconditions: t('preconditions'),
|
preconditions: t('preconditions'),
|
||||||
|
expectedResult: t('expected_result'),
|
||||||
step: t('step'),
|
step: t('step'),
|
||||||
text: t('text'),
|
text: t('text'),
|
||||||
steps: t('steps'),
|
steps: t('steps'),
|
||||||
newStep: t('new_step'),
|
newStep: t('new_step'),
|
||||||
detailsOfTheStep: t('details_of_the_step'),
|
detailsOfTheStep: t('details_of_the_step'),
|
||||||
expectedResult: t('expected_result'),
|
|
||||||
deleteThisStep: t('delete_this_step'),
|
deleteThisStep: t('delete_this_step'),
|
||||||
insertStep: t('insert_step'),
|
insertStep: t('insert_step'),
|
||||||
attachments: t('attachments'),
|
attachments: t('attachments'),
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props)
|
|||||||
isDisabled={!context.isProjectReporter(Number(projectId))}
|
isDisabled={!context.isProjectReporter(Number(projectId))}
|
||||||
selectedKeys={selectedKeys}
|
selectedKeys={selectedKeys}
|
||||||
onSelectionChange={setSelectedKeys}
|
onSelectionChange={setSelectedKeys}
|
||||||
onStatusChange={handleChangeStatus}
|
onChangeStatus={handleChangeStatus}
|
||||||
onIncludeCase={(includeTestId) => handleIncludeExcludeCase(true, includeTestId)}
|
onIncludeCase={(includeTestId) => handleIncludeExcludeCase(true, includeTestId)}
|
||||||
onExcludeCase={(excludeCaseId) => handleIncludeExcludeCase(false, excludeCaseId)}
|
onExcludeCase={(excludeCaseId) => handleIncludeExcludeCase(false, excludeCaseId)}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Chip, Divider } from '@nextui-org/react';
|
||||||
|
import { RunMessages } from '@/types/run';
|
||||||
|
import { CaseType } from '@/types/case';
|
||||||
|
import { Circle } from 'lucide-react';
|
||||||
|
import { priorities, testTypes, templates } from '@/config/selection';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isOpen: boolean;
|
||||||
|
testCase: CaseType;
|
||||||
|
onCancel: () => void;
|
||||||
|
onChangeStatus: (changeCaseId: number, status: number) => {};
|
||||||
|
messages: RunMessages;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function showTestCaseDetailDialog({ isOpen, testCase, onCancel, onChangeStatus, messages }: Props) {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
size="3xl"
|
||||||
|
onOpenChange={() => {
|
||||||
|
onCancel();
|
||||||
|
}}
|
||||||
|
classNames={{
|
||||||
|
header: 'border-b-[1px] border-[#e5e5e5]',
|
||||||
|
body: 'border-b-[1px] border-[#e5e5e5]',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader className="flex flex-col gap-1">{testCase.title}</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<p className={'font-bold mt-2'}>{messages.description}</p>
|
||||||
|
<div>{testCase.description}</div>
|
||||||
|
|
||||||
|
<div className="flex my-2">
|
||||||
|
<div className="w-1/2">
|
||||||
|
<p className={'font-bold'}>{messages.priority}</p>
|
||||||
|
<Chip
|
||||||
|
startContent={
|
||||||
|
<Circle
|
||||||
|
size={8}
|
||||||
|
className="me-2"
|
||||||
|
color={priorities[testCase.priority].color}
|
||||||
|
fill={priorities[testCase.priority].color}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
variant="light"
|
||||||
|
>
|
||||||
|
{messages[priorities[testCase.priority].uid]}
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/2">
|
||||||
|
<p className={'font-bold'}>{messages.type}</p>
|
||||||
|
<div>{messages[testTypes[testCase.type].uid]}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalBody>
|
||||||
|
{templates[testCase.template].uid === 'text' ? (
|
||||||
|
<div className="flex my-2">
|
||||||
|
<div className="w-1/2">
|
||||||
|
<p className={'font-bold'}>{messages.preconditions}</p>
|
||||||
|
<div>{testCase.preConditions}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/2">
|
||||||
|
<p className={'font-bold'}>{messages.expectedResult}</p>
|
||||||
|
<div>{testCase.expectedResults}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex my-2">
|
||||||
|
{testCase.Steps &&
|
||||||
|
testCase.Steps.map((step, index) => (
|
||||||
|
<>
|
||||||
|
<div className="w-1/2">
|
||||||
|
<p className={'font-bold'}>{messages.preconditions}</p>
|
||||||
|
<div>{step.step}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/2">
|
||||||
|
<p className={'font-bold'}>{messages.expectedResult}</p>
|
||||||
|
<div>{step.result}</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button variant="light" onPress={onCancel}>
|
||||||
|
{messages.close}
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -25,16 +25,18 @@ import {
|
|||||||
CircleX,
|
CircleX,
|
||||||
CircleSlash2,
|
CircleSlash2,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
import { NextUiLinkClasses } from '@/src/navigation';
|
||||||
import { priorities, testRunCaseStatus } from '@/config/selection';
|
import { priorities, testRunCaseStatus } from '@/config/selection';
|
||||||
import { CaseType } from '@/types/case';
|
import { CaseType } from '@/types/case';
|
||||||
import { RunMessages } from '@/types/run';
|
import { RunMessages } from '@/types/run';
|
||||||
|
import TestCaseDetailDialog from './TestCaseDetailDialog';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
cases: CaseType[];
|
cases: CaseType[];
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
selectedKeys: Selection;
|
selectedKeys: Selection;
|
||||||
onSelectionChange: React.Dispatch<React.SetStateAction<Selection>>;
|
onSelectionChange: React.Dispatch<React.SetStateAction<Selection>>;
|
||||||
onStatusChange: (changeCaseId: number, status: number) => {};
|
onChangeStatus: (changeCaseId: number, status: number) => {};
|
||||||
onIncludeCase: (includeCaseId: number) => {};
|
onIncludeCase: (includeCaseId: number) => {};
|
||||||
onExcludeCase: (excludeCaseId: number) => {};
|
onExcludeCase: (excludeCaseId: number) => {};
|
||||||
messages: RunMessages;
|
messages: RunMessages;
|
||||||
@@ -45,7 +47,7 @@ export default function TestCaseSelector({
|
|||||||
isDisabled,
|
isDisabled,
|
||||||
selectedKeys,
|
selectedKeys,
|
||||||
onSelectionChange,
|
onSelectionChange,
|
||||||
onStatusChange,
|
onChangeStatus,
|
||||||
onIncludeCase,
|
onIncludeCase,
|
||||||
onExcludeCase,
|
onExcludeCase,
|
||||||
messages,
|
messages,
|
||||||
@@ -124,6 +126,17 @@ export default function TestCaseSelector({
|
|||||||
const runStatus = testCase.RunCases && testCase.RunCases.length > 0 ? testCase.RunCases[0].status : 0;
|
const runStatus = testCase.RunCases && testCase.RunCases.length > 0 ? testCase.RunCases[0].status : 0;
|
||||||
|
|
||||||
switch (columnKey) {
|
switch (columnKey) {
|
||||||
|
case 'title':
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="light"
|
||||||
|
className="data-[hover=true]:bg-transparent"
|
||||||
|
onPress={() => showTestCaseDetailDialog(testCase)}
|
||||||
|
>
|
||||||
|
<span className={NextUiLinkClasses}>{cellValue}</span>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
case 'priority':
|
case 'priority':
|
||||||
return (
|
return (
|
||||||
<div className={isIncluded ? chipBaseClass : chipBaseClass + notIncludedCaseClass}>
|
<div className={isIncluded ? chipBaseClass : chipBaseClass + notIncludedCaseClass}>
|
||||||
@@ -154,7 +167,7 @@ export default function TestCaseSelector({
|
|||||||
<DropdownItem
|
<DropdownItem
|
||||||
key={runCaseStatus.uid}
|
key={runCaseStatus.uid}
|
||||||
startContent={renderStatusIcon(runCaseStatus.uid)}
|
startContent={renderStatusIcon(runCaseStatus.uid)}
|
||||||
onPress={() => onStatusChange(testCase.id, index)}
|
onPress={() => onChangeStatus(testCase.id, index)}
|
||||||
>
|
>
|
||||||
{messages[runCaseStatus.uid]}
|
{messages[runCaseStatus.uid]}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
@@ -226,6 +239,29 @@ export default function TestCaseSelector({
|
|||||||
onSelectionChange(keys);
|
onSelectionChange(keys);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Test Case Detail
|
||||||
|
const [isTestCaseDetailDialogOpen, setIsTestCaseDetailDialogOpen] = useState(false);
|
||||||
|
const [showingTestCase, setShowingTestCase] = useState<CaseType>({
|
||||||
|
id: 0,
|
||||||
|
title: '',
|
||||||
|
state: 0,
|
||||||
|
priority: 0,
|
||||||
|
type: 0,
|
||||||
|
automationStatus: 0,
|
||||||
|
description: '',
|
||||||
|
template: 0,
|
||||||
|
preConditions: '',
|
||||||
|
expectedResults: '',
|
||||||
|
folderId: 0,
|
||||||
|
});
|
||||||
|
const showTestCaseDetailDialog = (showTestCase: CaseType) => {
|
||||||
|
setIsTestCaseDetailDialogOpen(true);
|
||||||
|
setShowingTestCase(showTestCase);
|
||||||
|
};
|
||||||
|
const hideTestCaseDetailDialog = () => {
|
||||||
|
setIsTestCaseDetailDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Table
|
<Table
|
||||||
@@ -260,6 +296,14 @@ export default function TestCaseSelector({
|
|||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
|
<TestCaseDetailDialog
|
||||||
|
isOpen={isTestCaseDetailDialogOpen}
|
||||||
|
testCase={showingTestCase}
|
||||||
|
onCancel={hideTestCaseDetailDialog}
|
||||||
|
onChangeStatus={(showingCaseId, newStatus) => onChangeStatus(showingCaseId, newStatus)}
|
||||||
|
messages={messages}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,24 @@ export default function Page({ params }: { params: { projectId: string; runId: s
|
|||||||
excludeFromRun: t('exclude_from_run'),
|
excludeFromRun: t('exclude_from_run'),
|
||||||
noCasesFound: t('no_cases_found'),
|
noCasesFound: t('no_cases_found'),
|
||||||
areYouSureLeave: t('are_you_sure_leave'),
|
areYouSureLeave: t('are_you_sure_leave'),
|
||||||
|
type: t('type'),
|
||||||
|
other: t('other'),
|
||||||
|
security: t('security'),
|
||||||
|
performance: t('performance'),
|
||||||
|
accessibility: t('accessibility'),
|
||||||
|
functional: t('functional'),
|
||||||
|
acceptance: t('acceptance'),
|
||||||
|
usability: t('usability'),
|
||||||
|
smokeSanity: t('smoke_sanity'),
|
||||||
|
compatibility: t('compatibility'),
|
||||||
|
destructive: t('destructive'),
|
||||||
|
regression: t('regression'),
|
||||||
|
automated: t('automated'),
|
||||||
|
manual: t('manual'),
|
||||||
|
preconditions: t('preconditions'),
|
||||||
|
expectedResult: t('expected_result'),
|
||||||
|
detailsOfTheStep: t('details_of_the_step'),
|
||||||
|
close: t('close'),
|
||||||
};
|
};
|
||||||
|
|
||||||
return <RunEditor projectId={params.projectId} runId={params.runId} messages={messages} locale={params.locale} />;
|
return <RunEditor projectId={params.projectId} runId={params.runId} messages={messages} locale={params.locale} />;
|
||||||
|
|||||||
@@ -123,12 +123,12 @@ type CaseMessages = {
|
|||||||
template: string;
|
template: string;
|
||||||
testDetail: string;
|
testDetail: string;
|
||||||
preconditions: string;
|
preconditions: string;
|
||||||
|
expectedResult: string;
|
||||||
step: string;
|
step: string;
|
||||||
text: string;
|
text: string;
|
||||||
steps: string;
|
steps: string;
|
||||||
newStep: string;
|
newStep: string;
|
||||||
detailsOfTheStep: string;
|
detailsOfTheStep: string;
|
||||||
expectedResult: string;
|
|
||||||
deleteThisStep: string;
|
deleteThisStep: string;
|
||||||
insertStep: string;
|
insertStep: string;
|
||||||
attachments: string;
|
attachments: string;
|
||||||
|
|||||||
@@ -83,6 +83,24 @@ type RunMessages = {
|
|||||||
excludeFromRun: string;
|
excludeFromRun: string;
|
||||||
noCasesFound: string;
|
noCasesFound: string;
|
||||||
areYouSureLeave: string;
|
areYouSureLeave: string;
|
||||||
|
type: string;
|
||||||
|
other: string;
|
||||||
|
security: string;
|
||||||
|
performance: string;
|
||||||
|
accessibility: string;
|
||||||
|
functional: string;
|
||||||
|
acceptance: string;
|
||||||
|
usability: string;
|
||||||
|
smokeSanity: string;
|
||||||
|
compatibility: string;
|
||||||
|
destructive: string;
|
||||||
|
regression: string;
|
||||||
|
automated: string;
|
||||||
|
manual: string;
|
||||||
|
preconditions: string;
|
||||||
|
expectedResult: string;
|
||||||
|
detailsOfTheStep: string;
|
||||||
|
close: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type { RunType, RunCaseType, RunStatusCountType, ProgressSeriesType, RunsMessages, RunMessages };
|
export type { RunType, RunCaseType, RunStatusCountType, ProgressSeriesType, RunsMessages, RunMessages };
|
||||||
|
|||||||
Reference in New Issue
Block a user