feat: test case detail dialog
This commit is contained in:
@@ -252,6 +252,8 @@
|
|||||||
"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",
|
"type": "Type",
|
||||||
|
"test_detail": "Test detail",
|
||||||
|
"steps": "Steps",
|
||||||
"preconditions": "Preconditions",
|
"preconditions": "Preconditions",
|
||||||
"expected_result": "Expected result",
|
"expected_result": "Expected result",
|
||||||
"details_of_the_step": "Details of the step",
|
"details_of_the_step": "Details of the step",
|
||||||
|
|||||||
@@ -254,6 +254,7 @@
|
|||||||
"are_you_sure_leave": "ページを離れてもよろしいですか",
|
"are_you_sure_leave": "ページを離れてもよろしいですか",
|
||||||
"type": "タイプ",
|
"type": "タイプ",
|
||||||
"test_detail": "テスト詳細",
|
"test_detail": "テスト詳細",
|
||||||
|
"steps": "ステップ",
|
||||||
"preconditions": "前提条件",
|
"preconditions": "前提条件",
|
||||||
"expected_result": "期待結果",
|
"expected_result": "期待結果",
|
||||||
"details_of_the_step": "ステップ詳細",
|
"details_of_the_step": "ステップ詳細",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import { useTheme } from 'next-themes';
|
|||||||
import { useFormGuard } from '@/utils/formGuard';
|
import { useFormGuard } from '@/utils/formGuard';
|
||||||
import { PriorityMessages } from '@/types/priority';
|
import { PriorityMessages } from '@/types/priority';
|
||||||
import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status';
|
import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status';
|
||||||
|
import { TestTypeMessages } from '@/types/testType';
|
||||||
|
|
||||||
const defaultTestRun = {
|
const defaultTestRun = {
|
||||||
id: 0,
|
id: 0,
|
||||||
@@ -58,6 +59,7 @@ type Props = {
|
|||||||
runStatusMessages: RunStatusMessages;
|
runStatusMessages: RunStatusMessages;
|
||||||
testRunCaseStatusMessages: TestRunCaseStatusMessages;
|
testRunCaseStatusMessages: TestRunCaseStatusMessages;
|
||||||
priorityMessages: PriorityMessages;
|
priorityMessages: PriorityMessages;
|
||||||
|
testTypeMessages: TestTypeMessages;
|
||||||
locale: string;
|
locale: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,6 +70,7 @@ export default function RunEditor({
|
|||||||
runStatusMessages,
|
runStatusMessages,
|
||||||
testRunCaseStatusMessages,
|
testRunCaseStatusMessages,
|
||||||
priorityMessages,
|
priorityMessages,
|
||||||
|
testTypeMessages,
|
||||||
locale,
|
locale,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const context = useContext(TokenContext);
|
const context = useContext(TokenContext);
|
||||||
@@ -333,6 +336,7 @@ export default function RunEditor({
|
|||||||
messages={messages}
|
messages={messages}
|
||||||
testRunCaseStatusMessages={testRunCaseStatusMessages}
|
testRunCaseStatusMessages={testRunCaseStatusMessages}
|
||||||
priorityMessages={priorityMessages}
|
priorityMessages={priorityMessages}
|
||||||
|
testTypeMessages={testTypeMessages}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,31 +1,84 @@
|
|||||||
import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react';
|
import { useState, useEffect, useContext } from 'react';
|
||||||
|
import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Avatar, Textarea } from '@nextui-org/react';
|
||||||
import { testTypes, templates } from '@/config/selection';
|
import { testTypes, templates } from '@/config/selection';
|
||||||
import { RunMessages } from '@/types/run';
|
import { RunMessages } from '@/types/run';
|
||||||
import { CaseType } from '@/types/case';
|
import { CaseType, StepType } from '@/types/case';
|
||||||
import { PriorityMessages } from '@/types/priority';
|
import { PriorityMessages } from '@/types/priority';
|
||||||
import TestCasePriority from '@/components/TestCasePriority';
|
import TestCasePriority from '@/components/TestCasePriority';
|
||||||
|
import { TokenContext } from '@/utils/TokenProvider';
|
||||||
|
import { fetchCase } from '@/utils/caseControl';
|
||||||
|
import { TestTypeMessages } from '@/types/testType';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
testCase: CaseType;
|
caseId: number;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onChangeStatus: (changeCaseId: number, status: number) => {};
|
onChangeStatus: (changeCaseId: number, status: number) => {};
|
||||||
messages: RunMessages;
|
messages: RunMessages;
|
||||||
|
testTypeMessages: TestTypeMessages;
|
||||||
priorityMessages: PriorityMessages;
|
priorityMessages: PriorityMessages;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function showTestCaseDetailDialog({
|
const defaultTestCase = {
|
||||||
|
id: 0,
|
||||||
|
title: '',
|
||||||
|
state: 0,
|
||||||
|
priority: 0,
|
||||||
|
type: 0,
|
||||||
|
automationStatus: 0,
|
||||||
|
description: '',
|
||||||
|
template: 0,
|
||||||
|
preConditions: '',
|
||||||
|
expectedResults: '',
|
||||||
|
folderId: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function TestCaseDetailDialog({
|
||||||
isOpen,
|
isOpen,
|
||||||
testCase,
|
caseId,
|
||||||
onCancel,
|
onCancel,
|
||||||
onChangeStatus,
|
onChangeStatus,
|
||||||
messages,
|
messages,
|
||||||
|
testTypeMessages,
|
||||||
priorityMessages,
|
priorityMessages,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const context = useContext(TokenContext);
|
||||||
|
const [testCase, setTestCase] = useState<CaseType>(defaultTestCase);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchDataEffect() {
|
||||||
|
if (!context.isSignedIn()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!caseId || caseId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await fetchCase(context.token.access_token, Number(caseId));
|
||||||
|
if (data.Steps && data.Steps.length > 0) {
|
||||||
|
data.Steps.sort((a: StepType, b: StepType) => {
|
||||||
|
const stepNoA = a.caseSteps.stepNo;
|
||||||
|
const stepNoB = b.caseSteps.stepNo;
|
||||||
|
return stepNoA - stepNoB;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setTestCase(data);
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Error in effect:', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchDataEffect();
|
||||||
|
}, [context, caseId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
size="3xl"
|
size="5xl"
|
||||||
|
scrollBehavior="outside"
|
||||||
onOpenChange={() => {
|
onOpenChange={() => {
|
||||||
onCancel();
|
onCancel();
|
||||||
}}
|
}}
|
||||||
@@ -48,40 +101,55 @@ export default function showTestCaseDetailDialog({
|
|||||||
|
|
||||||
<div className="w-1/2">
|
<div className="w-1/2">
|
||||||
<p className={'font-bold'}>{messages.type}</p>
|
<p className={'font-bold'}>{messages.type}</p>
|
||||||
<div>{messages[testTypes[testCase.type].uid]}</div>
|
<div>{testTypeMessages[testTypes[testCase.type].uid]}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
{templates[testCase.template].uid === 'text' ? (
|
{templates[testCase.template].uid === 'text' ? (
|
||||||
<div className="flex my-2">
|
<>
|
||||||
<div className="w-1/2">
|
<p className={'font-bold mt-2'}>{messages.testDetail}</p>
|
||||||
<p className={'font-bold'}>{messages.preconditions}</p>
|
<div className="flex my-2">
|
||||||
<div>{testCase.preConditions}</div>
|
<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>
|
||||||
|
</>
|
||||||
<div className="w-1/2">
|
|
||||||
<p className={'font-bold'}>{messages.expectedResult}</p>
|
|
||||||
<div>{testCase.expectedResults}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="flex my-2">
|
<>
|
||||||
|
<p className={'font-bold mt-2'}>{messages.steps}</p>
|
||||||
{testCase.Steps &&
|
{testCase.Steps &&
|
||||||
testCase.Steps.map((step, index) => (
|
testCase.Steps.map((step) => (
|
||||||
<>
|
<div key={step.id} className="flex items-center my-1">
|
||||||
<div className="w-1/2">
|
<Avatar className="me-2" size="sm" name={step.caseSteps.stepNo.toString()} />
|
||||||
<p className={'font-bold'}>{messages.preconditions}</p>
|
<div key={step.id} className="grow flex gap-2">
|
||||||
<div>{step.step}</div>
|
<div className="w-1/2">
|
||||||
|
<Textarea
|
||||||
|
isReadOnly
|
||||||
|
size="sm"
|
||||||
|
variant="flat"
|
||||||
|
label={messages.detailsOfTheStep}
|
||||||
|
value={step.step}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-1/2">
|
||||||
|
<Textarea
|
||||||
|
isReadOnly
|
||||||
|
size="sm"
|
||||||
|
variant="flat"
|
||||||
|
label={messages.expectedResult}
|
||||||
|
value={step.result}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="w-1/2">
|
|
||||||
<p className={'font-bold'}>{messages.expectedResult}</p>
|
|
||||||
<div>{step.result}</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</>
|
||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ import { RunMessages } from '@/types/run';
|
|||||||
import TestCaseDetailDialog from './TestCaseDetailDialog';
|
import TestCaseDetailDialog from './TestCaseDetailDialog';
|
||||||
import { PriorityMessages } from '@/types/priority';
|
import { PriorityMessages } from '@/types/priority';
|
||||||
import TestCasePriority from '@/components/TestCasePriority';
|
import TestCasePriority from '@/components/TestCasePriority';
|
||||||
import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus';
|
import { TestTypeMessages } from '@/types/testType';
|
||||||
|
import { TestRunCaseStatusMessages } from '@/types/status';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
cases: CaseType[];
|
cases: CaseType[];
|
||||||
@@ -45,6 +46,7 @@ type Props = {
|
|||||||
messages: RunMessages;
|
messages: RunMessages;
|
||||||
testRunCaseStatusMessages: TestRunCaseStatusMessages;
|
testRunCaseStatusMessages: TestRunCaseStatusMessages;
|
||||||
priorityMessages: PriorityMessages;
|
priorityMessages: PriorityMessages;
|
||||||
|
testTypeMessages: TestTypeMessages;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function TestCaseSelector({
|
export default function TestCaseSelector({
|
||||||
@@ -57,6 +59,7 @@ export default function TestCaseSelector({
|
|||||||
onExcludeCase,
|
onExcludeCase,
|
||||||
messages,
|
messages,
|
||||||
testRunCaseStatusMessages,
|
testRunCaseStatusMessages,
|
||||||
|
testTypeMessages,
|
||||||
priorityMessages,
|
priorityMessages,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const headerColumns = [
|
const headerColumns = [
|
||||||
@@ -138,7 +141,7 @@ export default function TestCaseSelector({
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant="light"
|
variant="light"
|
||||||
className="data-[hover=true]:bg-transparent"
|
className="data-[hover=true]:bg-transparent"
|
||||||
onPress={() => showTestCaseDetailDialog(testCase)}
|
onPress={() => showTestCaseDetailDialog(testCase.id)}
|
||||||
>
|
>
|
||||||
<span className={NextUiLinkClasses}>{cellValue}</span>
|
<span className={NextUiLinkClasses}>{cellValue}</span>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -244,22 +247,10 @@ export default function TestCaseSelector({
|
|||||||
|
|
||||||
// Test Case Detail
|
// Test Case Detail
|
||||||
const [isTestCaseDetailDialogOpen, setIsTestCaseDetailDialogOpen] = useState(false);
|
const [isTestCaseDetailDialogOpen, setIsTestCaseDetailDialogOpen] = useState(false);
|
||||||
const [showingTestCase, setShowingTestCase] = useState<CaseType>({
|
const [showingTestCaseId, setShowingTestCaseId] = useState<number>(0);
|
||||||
id: 0,
|
const showTestCaseDetailDialog = (showTestCaseId: number) => {
|
||||||
title: '',
|
|
||||||
state: 0,
|
|
||||||
priority: 0,
|
|
||||||
type: 0,
|
|
||||||
automationStatus: 0,
|
|
||||||
description: '',
|
|
||||||
template: 0,
|
|
||||||
preConditions: '',
|
|
||||||
expectedResults: '',
|
|
||||||
folderId: 0,
|
|
||||||
});
|
|
||||||
const showTestCaseDetailDialog = (showTestCase: CaseType) => {
|
|
||||||
setIsTestCaseDetailDialogOpen(true);
|
setIsTestCaseDetailDialogOpen(true);
|
||||||
setShowingTestCase(showTestCase);
|
setShowingTestCaseId(showTestCaseId);
|
||||||
};
|
};
|
||||||
const hideTestCaseDetailDialog = () => {
|
const hideTestCaseDetailDialog = () => {
|
||||||
setIsTestCaseDetailDialogOpen(false);
|
setIsTestCaseDetailDialogOpen(false);
|
||||||
@@ -302,11 +293,12 @@ export default function TestCaseSelector({
|
|||||||
|
|
||||||
<TestCaseDetailDialog
|
<TestCaseDetailDialog
|
||||||
isOpen={isTestCaseDetailDialogOpen}
|
isOpen={isTestCaseDetailDialogOpen}
|
||||||
testCase={showingTestCase}
|
caseId={showingTestCaseId}
|
||||||
onCancel={hideTestCaseDetailDialog}
|
onCancel={hideTestCaseDetailDialog}
|
||||||
onChangeStatus={(showingCaseId, newStatus) => onChangeStatus(showingCaseId, newStatus)}
|
onChangeStatus={(showingCaseId, newStatus) => onChangeStatus(showingCaseId, newStatus)}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
priorityMessages={priorityMessages}
|
priorityMessages={priorityMessages}
|
||||||
|
testTypeMessages={testTypeMessages}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useTranslations } from 'next-intl';
|
|||||||
import { RunMessages } from '@/types/run';
|
import { RunMessages } from '@/types/run';
|
||||||
import { PriorityMessages } from '@/types/priority';
|
import { PriorityMessages } from '@/types/priority';
|
||||||
import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status';
|
import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status';
|
||||||
|
import { TestTypeMessages } from '@/types/testType';
|
||||||
|
|
||||||
export default function Page({ params }: { params: { projectId: string; runId: string; locale: string } }) {
|
export default function Page({ params }: { params: { projectId: string; runId: string; locale: string } }) {
|
||||||
const t = useTranslations('Run');
|
const t = useTranslations('Run');
|
||||||
@@ -26,6 +27,8 @@ export default function Page({ params }: { params: { projectId: string; runId: s
|
|||||||
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'),
|
type: t('type'),
|
||||||
|
testDetail: t('test_detail'),
|
||||||
|
steps: t('steps'),
|
||||||
preconditions: t('preconditions'),
|
preconditions: t('preconditions'),
|
||||||
expectedResult: t('expected_result'),
|
expectedResult: t('expected_result'),
|
||||||
detailsOfTheStep: t('details_of_the_step'),
|
detailsOfTheStep: t('details_of_the_step'),
|
||||||
@@ -59,6 +62,23 @@ export default function Page({ params }: { params: { projectId: string; runId: s
|
|||||||
low: pt('low'),
|
low: pt('low'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tt = useTranslations('Type');
|
||||||
|
const testTypeMessages: TestTypeMessages = {
|
||||||
|
other: tt('other'),
|
||||||
|
security: tt('security'),
|
||||||
|
performance: tt('performance'),
|
||||||
|
accessibility: tt('accessibility'),
|
||||||
|
functional: tt('functional'),
|
||||||
|
acceptance: tt('acceptance'),
|
||||||
|
usability: tt('usability'),
|
||||||
|
smokeSanity: tt('smoke_sanity'),
|
||||||
|
compatibility: tt('compatibility'),
|
||||||
|
destructive: tt('destructive'),
|
||||||
|
regression: tt('regression'),
|
||||||
|
automated: tt('automated'),
|
||||||
|
manual: tt('manual'),
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RunEditor
|
<RunEditor
|
||||||
projectId={params.projectId}
|
projectId={params.projectId}
|
||||||
@@ -67,6 +87,7 @@ export default function Page({ params }: { params: { projectId: string; runId: s
|
|||||||
runStatusMessages={runStatusMessages}
|
runStatusMessages={runStatusMessages}
|
||||||
testRunCaseStatusMessages={testRunCaseStatusMessages}
|
testRunCaseStatusMessages={testRunCaseStatusMessages}
|
||||||
priorityMessages={priorityMessages}
|
priorityMessages={priorityMessages}
|
||||||
|
testTypeMessages={testTypeMessages}
|
||||||
locale={params.locale}
|
locale={params.locale}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -59,20 +59,9 @@ type RunMessages = {
|
|||||||
title: string;
|
title: string;
|
||||||
pleaseEnter: string;
|
pleaseEnter: string;
|
||||||
description: string;
|
description: string;
|
||||||
new: string;
|
|
||||||
inProgress: string;
|
|
||||||
underReview: string;
|
|
||||||
rejected: string;
|
|
||||||
done: string;
|
|
||||||
closed: string;
|
|
||||||
priority: string;
|
priority: string;
|
||||||
status: string;
|
status: string;
|
||||||
actions: string;
|
actions: string;
|
||||||
untested: string;
|
|
||||||
passed: string;
|
|
||||||
failed: string;
|
|
||||||
retest: string;
|
|
||||||
skipped: string;
|
|
||||||
selectTestCase: string;
|
selectTestCase: string;
|
||||||
testCaseSelection: string;
|
testCaseSelection: string;
|
||||||
includeInRun: string;
|
includeInRun: string;
|
||||||
@@ -80,6 +69,8 @@ type RunMessages = {
|
|||||||
noCasesFound: string;
|
noCasesFound: string;
|
||||||
areYouSureLeave: string;
|
areYouSureLeave: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
testDetail: string;
|
||||||
|
steps: string;
|
||||||
preconditions: string;
|
preconditions: string;
|
||||||
expectedResult: string;
|
expectedResult: string;
|
||||||
detailsOfTheStep: string;
|
detailsOfTheStep: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user