From dda2f6feb98ae820b534795b4fb4f121d04f33c7 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sat, 20 Jul 2024 23:04:37 +0900 Subject: [PATCH 01/14] fix: use onPress instead onClick on ListBoxItem --- frontend/src/app/[locale]/HeaderNavbarMenu.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/[locale]/HeaderNavbarMenu.tsx b/frontend/src/app/[locale]/HeaderNavbarMenu.tsx index f787b60..b7c1aa7 100644 --- a/frontend/src/app/[locale]/HeaderNavbarMenu.tsx +++ b/frontend/src/app/[locale]/HeaderNavbarMenu.tsx @@ -143,7 +143,7 @@ export default function HeaderNavbarMenu({ messages, locale }: Props) { {}} /> - setIsMenuOpen(!isMenuOpen)} /> + setIsMenuOpen(!isMenuOpen)} /> @@ -220,7 +220,7 @@ export default function HeaderNavbarMenu({ messages, locale }: Props) { key="signin" startContent={} title={messages.signIn} - onClick={() => { + onPress={() => { router.push('/account/signin', { locale: locale }); setIsMenuOpen(false); }} @@ -229,7 +229,7 @@ export default function HeaderNavbarMenu({ messages, locale }: Props) { key="signup" title={messages.signUp} startContent={} - onClick={() => { + onPress={() => { router.push('/account/signup', { locale: locale }); setIsMenuOpen(false); }} @@ -248,7 +248,7 @@ export default function HeaderNavbarMenu({ messages, locale }: Props) { key={entry.code} startContent={} title={entry.name} - onClick={() => { + onPress={() => { changeLocale(entry.code); setIsMenuOpen(false); }} From cbdd0cb1d41a1c257d508de7f660d20139a57a79 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 10:44:41 +0900 Subject: [PATCH 02/14] feat: test case detail dialog --- frontend/messages/en.json | 22 ++++- frontend/messages/ja.json | 23 ++++- .../[folderId]/cases/[caseId]/page.tsx | 2 +- .../[projectId]/runs/[runId]/RunEditor.tsx | 2 +- .../runs/[runId]/TestCaseDetailDialog.tsx | 98 +++++++++++++++++++ .../runs/[runId]/TestCaseSelector.tsx | 50 +++++++++- .../[projectId]/runs/[runId]/page.tsx | 18 ++++ frontend/types/case.ts | 2 +- frontend/types/run.ts | 18 ++++ 9 files changed, 225 insertions(+), 10 deletions(-) create mode 100644 frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 92cf712..dcdadb9 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -201,12 +201,12 @@ "template": "Template", "test_detail": "Test detail", "preconditions": "Preconditions", + "expected_result": "Expected result", "step": "Step", "text": "Text", "steps": "Steps", "new_step": "New Step", "details_of_the_step": "Details of the step", - "expected_result": "Expected result", "delete_this_step": "Delete this step", "insert_step": "Insert step", "attachments": "Attachments", @@ -272,7 +272,25 @@ "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 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": { "member_management": "Member Management", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index b12a4e0..e56f4e0 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -201,12 +201,12 @@ "template": "テンプレート", "test_detail": "テスト詳細", "preconditions": "前提条件", + "expected_result": "期待結果", "step": "ステップ", "text": "テキスト", "steps": "ステップ", "new_step": "新規ステップ", "details_of_the_step": "ステップ詳細", - "expected_result": "期待結果", "delete_this_step": "このステップを削除", "insert_step": "ステップを挿入", "attachments": "添付ファイル", @@ -272,7 +272,26 @@ "include_in_run": "テストランに含める", "exclude_from_run": "テストランから除外する", "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": { "member_management": "メンバー管理", diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx index e859a4f..cbb9569 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx @@ -43,12 +43,12 @@ export default function Page({ template: t('template'), testDetail: t('test_detail'), preconditions: t('preconditions'), + expectedResult: t('expected_result'), step: t('step'), text: t('text'), steps: t('steps'), newStep: t('new_step'), detailsOfTheStep: t('details_of_the_step'), - expectedResult: t('expected_result'), deleteThisStep: t('delete_this_step'), insertStep: t('insert_step'), attachments: t('attachments'), diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx index 6aa6947..731319f 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx @@ -310,7 +310,7 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props) isDisabled={!context.isProjectReporter(Number(projectId))} selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys} - onStatusChange={handleChangeStatus} + onChangeStatus={handleChangeStatus} onIncludeCase={(includeTestId) => handleIncludeExcludeCase(true, includeTestId)} onExcludeCase={(excludeCaseId) => handleIncludeExcludeCase(false, excludeCaseId)} messages={messages} diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx new file mode 100644 index 0000000..90ca322 --- /dev/null +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx @@ -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 ( + { + onCancel(); + }} + classNames={{ + header: 'border-b-[1px] border-[#e5e5e5]', + body: 'border-b-[1px] border-[#e5e5e5]', + }} + > + + {testCase.title} + +

{messages.description}

+
{testCase.description}
+ +
+
+

{messages.priority}

+ + } + variant="light" + > + {messages[priorities[testCase.priority].uid]} + +
+ +
+

{messages.type}

+
{messages[testTypes[testCase.type].uid]}
+
+
+
+ + {templates[testCase.template].uid === 'text' ? ( +
+
+

{messages.preconditions}

+
{testCase.preConditions}
+
+ +
+

{messages.expectedResult}

+
{testCase.expectedResults}
+
+
+ ) : ( +
+ {testCase.Steps && + testCase.Steps.map((step, index) => ( + <> +
+

{messages.preconditions}

+
{step.step}
+
+ +
+

{messages.expectedResult}

+
{step.result}
+
+ + ))} +
+ )} +
+ + + +
+
+ ); +} diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx index 3d4eaa2..a1deb0c 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx @@ -25,16 +25,18 @@ import { CircleX, CircleSlash2, } from 'lucide-react'; +import { NextUiLinkClasses } from '@/src/navigation'; import { priorities, testRunCaseStatus } from '@/config/selection'; import { CaseType } from '@/types/case'; import { RunMessages } from '@/types/run'; +import TestCaseDetailDialog from './TestCaseDetailDialog'; type Props = { cases: CaseType[]; isDisabled: boolean; selectedKeys: Selection; onSelectionChange: React.Dispatch>; - onStatusChange: (changeCaseId: number, status: number) => {}; + onChangeStatus: (changeCaseId: number, status: number) => {}; onIncludeCase: (includeCaseId: number) => {}; onExcludeCase: (excludeCaseId: number) => {}; messages: RunMessages; @@ -45,7 +47,7 @@ export default function TestCaseSelector({ isDisabled, selectedKeys, onSelectionChange, - onStatusChange, + onChangeStatus, onIncludeCase, onExcludeCase, messages, @@ -124,6 +126,17 @@ export default function TestCaseSelector({ const runStatus = testCase.RunCases && testCase.RunCases.length > 0 ? testCase.RunCases[0].status : 0; switch (columnKey) { + case 'title': + return ( + + ); case 'priority': return (
@@ -154,7 +167,7 @@ export default function TestCaseSelector({ onStatusChange(testCase.id, index)} + onPress={() => onChangeStatus(testCase.id, index)} > {messages[runCaseStatus.uid]} @@ -226,6 +239,29 @@ export default function TestCaseSelector({ onSelectionChange(keys); }; + // Test Case Detail + const [isTestCaseDetailDialogOpen, setIsTestCaseDetailDialogOpen] = useState(false); + const [showingTestCase, setShowingTestCase] = useState({ + 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 ( <>
+ + onChangeStatus(showingCaseId, newStatus)} + messages={messages} + /> ); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx index f53a060..b86c688 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx @@ -37,6 +37,24 @@ export default function Page({ params }: { params: { projectId: string; runId: s excludeFromRun: t('exclude_from_run'), noCasesFound: t('no_cases_found'), 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 ; diff --git a/frontend/types/case.ts b/frontend/types/case.ts index cdba0a8..ff945b6 100644 --- a/frontend/types/case.ts +++ b/frontend/types/case.ts @@ -123,12 +123,12 @@ type CaseMessages = { template: string; testDetail: string; preconditions: string; + expectedResult: string; step: string; text: string; steps: string; newStep: string; detailsOfTheStep: string; - expectedResult: string; deleteThisStep: string; insertStep: string; attachments: string; diff --git a/frontend/types/run.ts b/frontend/types/run.ts index 15285c7..93b72bf 100644 --- a/frontend/types/run.ts +++ b/frontend/types/run.ts @@ -83,6 +83,24 @@ type RunMessages = { excludeFromRun: string; noCasesFound: 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 }; From 63df563b878d255c2a4cff6e73e12014b7989b6e Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 11:18:05 +0900 Subject: [PATCH 03/14] refactor: priority messages duplication --- frontend/components/TestCasePriority.tsx | 17 ++++++++++ frontend/messages/en.json | 6 ++++ frontend/messages/ja.json | 7 +++++ .../[projectId]/runs/[runId]/RunEditor.tsx | 5 ++- .../runs/[runId]/TestCaseDetailDialog.tsx | 31 +++++++++---------- .../runs/[runId]/TestCaseSelector.tsx | 4 +++ .../[projectId]/runs/[runId]/page.tsx | 26 ++++++++++++---- frontend/types/case.ts | 5 --- frontend/types/priority.ts | 7 +++++ 9 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 frontend/components/TestCasePriority.tsx create mode 100644 frontend/types/priority.ts diff --git a/frontend/components/TestCasePriority.tsx b/frontend/components/TestCasePriority.tsx new file mode 100644 index 0000000..bf0e642 --- /dev/null +++ b/frontend/components/TestCasePriority.tsx @@ -0,0 +1,17 @@ +import { Circle } from 'lucide-react'; +import { priorities } from '@/config/selection'; +import { PriorityMessages } from '@/types/priority'; + +type Props = { + priorityValue: number; + priorityMessages: PriorityMessages; +}; + +export default function TestCasePriority({ priorityValue, priorityMessages }: Props) { + return ( +
+ +
{priorityMessages[priorities[priorityValue].uid]}
+
+ ); +} diff --git a/frontend/messages/en.json b/frontend/messages/en.json index dcdadb9..0f4ddfa 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -1,4 +1,10 @@ { + "Priority": { + "critical": "Critical", + "high": "High", + "medium": "Medium", + "low": "Low" + }, "Index": { "get_started": "Get Started", "demo": "Demo", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index e56f4e0..559f8ff 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -1,4 +1,11 @@ { + "Priority": { + "priority": "優先度", + "critical": "致", + "high": "高", + "medium": "中", + "low": "低" + }, "Index": { "get_started": "テスト管理を始める", "demo": "デモ", diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx index 731319f..6a59045 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx @@ -37,6 +37,7 @@ import { fetchFolders } from '../../folders/foldersControl'; import { TokenContext } from '@/utils/TokenProvider'; import { useTheme } from 'next-themes'; import { useFormGuard } from '@/utils/formGuard'; +import { PriorityMessages } from '@/types/priority'; const defaultTestRun = { id: 0, @@ -53,10 +54,11 @@ type Props = { projectId: string; runId: string; messages: RunMessages; + priorityMessages: PriorityMessages; locale: string; }; -export default function RunEditor({ projectId, runId, messages, locale }: Props) { +export default function RunEditor({ projectId, runId, messages, priorityMessages, locale }: Props) { const context = useContext(TokenContext); const { theme, setTheme } = useTheme(); const [testRun, setTestRun] = useState(defaultTestRun); @@ -314,6 +316,7 @@ export default function RunEditor({ projectId, runId, messages, locale }: Props) onIncludeCase={(includeTestId) => handleIncludeExcludeCase(true, includeTestId)} onExcludeCase={(excludeCaseId) => handleIncludeExcludeCase(false, excludeCaseId)} messages={messages} + priorityMessages={priorityMessages} />
diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx index 90ca322..9d1c939 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx @@ -1,8 +1,9 @@ -import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Chip, Divider } from '@nextui-org/react'; +import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react'; +import { testTypes, templates } from '@/config/selection'; +import TestCasePriority from '@/components/TestCasePriority'; import { RunMessages } from '@/types/run'; import { CaseType } from '@/types/case'; -import { Circle } from 'lucide-react'; -import { priorities, testTypes, templates } from '@/config/selection'; +import { PriorityMessages } from '@/types/priority'; type Props = { isOpen: boolean; @@ -10,9 +11,17 @@ type Props = { onCancel: () => void; onChangeStatus: (changeCaseId: number, status: number) => {}; messages: RunMessages; + priorityMessages: PriorityMessages; }; -export default function showTestCaseDetailDialog({ isOpen, testCase, onCancel, onChangeStatus, messages }: Props) { +export default function showTestCaseDetailDialog({ + isOpen, + testCase, + onCancel, + onChangeStatus, + messages, + priorityMessages, +}: Props) { return (

{messages.priority}

- - } - variant="light" - > - {messages[priorities[testCase.priority].uid]} - +
diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx index a1deb0c..4202fda 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx @@ -30,6 +30,7 @@ import { priorities, testRunCaseStatus } from '@/config/selection'; import { CaseType } from '@/types/case'; import { RunMessages } from '@/types/run'; import TestCaseDetailDialog from './TestCaseDetailDialog'; +import { PriorityMessages } from '@/types/priority'; type Props = { cases: CaseType[]; @@ -40,6 +41,7 @@ type Props = { onIncludeCase: (includeCaseId: number) => {}; onExcludeCase: (excludeCaseId: number) => {}; messages: RunMessages; + priorityMessages: PriorityMessages; }; export default function TestCaseSelector({ @@ -51,6 +53,7 @@ export default function TestCaseSelector({ onIncludeCase, onExcludeCase, messages, + priorityMessages, }: Props) { const headerColumns = [ { name: messages.id, uid: 'id', sortable: true }, @@ -303,6 +306,7 @@ export default function TestCaseSelector({ onCancel={hideTestCaseDetailDialog} onChangeStatus={(showingCaseId, newStatus) => onChangeStatus(showingCaseId, newStatus)} messages={messages} + priorityMessages={priorityMessages} /> ); diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx index b86c688..bc8db9b 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx @@ -1,9 +1,11 @@ import RunEditor from './RunEditor'; import { useTranslations } from 'next-intl'; +import { RunMessages } from '@/types/run'; +import { PriorityMessages } from '@/types/priority'; export default function Page({ params }: { params: { projectId: string; runId: string; locale: string } }) { const t = useTranslations('Run'); - const messages = { + const messages: RunMessages = { backToRuns: t('back_to_runs'), updating: t('updating'), update: t('update'), @@ -22,10 +24,6 @@ export default function Page({ params }: { params: { projectId: string; runId: s priority: t('priority'), actions: t('actions'), status: t('status'), - critical: t('critical'), - high: t('high'), - medium: t('medium'), - low: t('low'), untested: t('untested'), passed: t('passed'), failed: t('failed'), @@ -57,5 +55,21 @@ export default function Page({ params }: { params: { projectId: string; runId: s close: t('close'), }; - return ; + const priorityTranslation = useTranslations('Priority'); + const priorityMessages: PriorityMessages = { + critical: priorityTranslation('critical'), + high: priorityTranslation('high'), + medium: priorityTranslation('medium'), + low: priorityTranslation('low'), + }; + + return ( + + ); } diff --git a/frontend/types/case.ts b/frontend/types/case.ts index ff945b6..09da508 100644 --- a/frontend/types/case.ts +++ b/frontend/types/case.ts @@ -101,11 +101,6 @@ type CaseMessages = { pleaseEnterTitle: string; description: string; testCaseDescription: string; - priority: string; - critical: string; - high: string; - medium: string; - low: string; type: string; other: string; security: string; diff --git a/frontend/types/priority.ts b/frontend/types/priority.ts new file mode 100644 index 0000000..b3779e0 --- /dev/null +++ b/frontend/types/priority.ts @@ -0,0 +1,7 @@ +type PriorityMessages = { + critical: string; + high: string; + medium: string; + low: string; +}; +export type { PriorityMessages }; From 74bb379c1ad0ebafc098c3c4188428184fddd402 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:59:49 +0900 Subject: [PATCH 04/14] refactor: priority messages duplication --- frontend/config/selection.ts | 4 +++- frontend/messages/en.json | 18 +--------------- frontend/messages/ja.json | 18 +--------------- .../folders/[folderId]/cases/CasesPane.tsx | 5 ++++- .../[folderId]/cases/TestCaseTable.tsx | 12 +++++------ .../[folderId]/cases/[caseId]/CaseEditor.tsx | 8 ++++--- .../[folderId]/cases/[caseId]/page.tsx | 14 +++++++++---- .../folders/[folderId]/cases/page.tsx | 21 ++++++++++++++----- .../projects/[projectId]/home/ProjectHome.tsx | 6 ++++-- .../home/TestPriorityDonutChart.tsx | 8 +++---- .../projects/[projectId]/home/page.tsx | 20 ++++++++++-------- .../runs/[runId]/TestCaseDetailDialog.tsx | 2 +- .../runs/[runId]/TestCaseSelector.tsx | 13 ++++-------- .../[projectId]/runs/[runId]/page.tsx | 10 ++++----- frontend/types/priority.ts | 11 +++++++++- frontend/types/run.ts | 4 ---- 16 files changed, 84 insertions(+), 90 deletions(-) diff --git a/frontend/config/selection.ts b/frontend/config/selection.ts index a4cf6d7..d54055b 100644 --- a/frontend/config/selection.ts +++ b/frontend/config/selection.ts @@ -1,3 +1,5 @@ +import { PriorityType } from '@/types/priority'; + const roles = [{ uid: 'administrator' }, { uid: 'user' }]; const memberRoles = [{ uid: 'manager' }, { uid: 'developer' }, { uid: 'reporter' }]; @@ -9,7 +11,7 @@ const locales = [ { code: 'ja', name: '日本語' }, ]; -const priorities = [ +const priorities: PriorityType[] = [ { uid: 'critical', color: '#bb3e03', chartColor: '#bb3e03' }, { uid: 'high', color: '#ca6702', chartColor: '#ca6702' }, { uid: 'medium', color: '#ee9b00', chartColor: '#ee9b00' }, diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 0f4ddfa..91034cc 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -133,11 +133,7 @@ "destructive": "Destructive", "regression": "Regression", "automated": "Automated", - "manual": "Manual", - "critical": "Critical", - "high": "High", - "medium": "Medium", - "low": "Low" + "manual": "Manual" }, "Folders": { "folder": "Folder", @@ -166,10 +162,6 @@ "are_you_sure": "Are you sure you want to delete test cases?", "new_test_case": "New Test Case", "status": "Status", - "critical": "Critical", - "high": "High", - "medium": "Medium", - "low": "Low", "no_cases_found": "No test cases found", "case_title": "Test Case Title", "case_description": "Test Case Description", @@ -186,10 +178,6 @@ "description": "Description", "test_case_description": "Test case description", "priority": "Priority", - "critical": "Critical", - "high": "High", - "medium": "Medium", - "low": "Low", "type": "Type", "other": "Other", "security": "Security", @@ -264,10 +252,6 @@ "priority": "Priority", "status": "Status", "actions": "Actions", - "critical": "Critical", - "high": "High", - "medium": "Medium", - "low": "Low", "untested": "Untested", "passed": "Passed", "failed": "Failed", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index 559f8ff..3fd7cb3 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -134,11 +134,7 @@ "destructive": "破壊", "regression": "回帰", "automated": "自動", - "manual": "手動", - "critical": "致", - "high": "高", - "medium": "中", - "low": "低" + "manual": "手動" }, "Folders": { "folder": "フォルダー", @@ -167,10 +163,6 @@ "are_you_sure": "テストケースを削除してもよろしいですか?", "new_test_case": "新規テストケース", "status": "ステータス", - "critical": "致", - "high": "高", - "medium": "中", - "low": "低", "no_cases_found": "テストケースがありません", "case_title": "テストケースタイトル", "case_description": "テストケース詳細", @@ -187,10 +179,6 @@ "description": "詳細", "test_case_description": "テストケース詳細", "priority": "優先度", - "critical": "致", - "high": "高", - "medium": "中", - "low": "低", "type": "タイプ", "other": "その他", "security": "セキュリティ", @@ -265,10 +253,6 @@ "priority": "優先度", "status": "ステータス", "actions": "アクション", - "critical": "致", - "high": "高", - "medium": "中", - "low": "低", "untested": "未実行", "passed": "成功", "failed": "失敗", diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx index bb8bf12..b689d95 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx @@ -6,15 +6,17 @@ import { fetchCases, createCase, deleteCases } from '@/utils/caseControl'; import { CaseType, CasesMessages } from '@/types/case'; import DeleteConfirmDialog from '@/components/DeleteConfirmDialog'; import CaseDialog from './CaseDialog'; +import { PriorityMessages } from '@/types/priority'; type Props = { projectId: string; folderId: string; messages: CasesMessages; + priorityMessages: PriorityMessages; locale: string; }; -export default function CasesPane({ projectId, folderId, messages, locale }: Props) { +export default function CasesPane({ projectId, folderId, messages, priorityMessages, locale }: Props) { const [cases, setCases] = useState([]); const context = useContext(TokenContext); const [isCaseDialogOpen, setIsCaseDialogOpen] = useState(false); @@ -81,6 +83,7 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro onDeleteCase={onDeleteCase} onDeleteCases={onDeleteCases} messages={messages} + priorityMessages={priorityMessages} locale={locale} /> diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx index 6de21ac..e4110a1 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx @@ -17,7 +17,8 @@ import { import { Link, NextUiLinkClasses } from '@/src/navigation'; import { Plus, MoreVertical, Trash, Circle } from 'lucide-react'; import { CaseType, CasesMessages } from '@/types/case'; -import { priorities } from '@/config/selection'; +import { PriorityMessages } from '@/types/priority'; +import TestCasePriority from '@/components/TestCasePriority'; type Props = { projectId: string; @@ -27,6 +28,7 @@ type Props = { onDeleteCase: (caseId: number) => void; onDeleteCases: (caseIds: number[]) => void; messages: CasesMessages; + priorityMessages: PriorityMessages; locale: string; }; @@ -38,6 +40,7 @@ export default function TestCaseTable({ onDeleteCase, onDeleteCases, messages, + priorityMessages, locale, }: Props) { const headerColumns = [ @@ -89,12 +92,7 @@ export default function TestCaseTable({ ); case 'priority': - return ( -
- -
{messages[priorities[cellValue].uid]}
-
- ); + return ; case 'actions': return ( diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx index d9728ef..cb7f5c7 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx @@ -6,12 +6,13 @@ import { Save, Plus, ArrowLeft, Circle } from 'lucide-react'; import { priorities, testTypes, templates } from '@/config/selection'; import CaseStepsEditor from './CaseStepsEditor'; import CaseAttachmentsEditor from './CaseAttachmentsEditor'; -import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case'; import { fetchCase, updateCase } from '@/utils/caseControl'; import { updateSteps } from './stepControl'; import { fetchCreateAttachments, fetchDownloadAttachment, fetchDeleteAttachment } from './attachmentControl'; import { TokenContext } from '@/utils/TokenProvider'; import { useFormGuard } from '@/utils/formGuard'; +import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case'; +import { PriorityMessages } from '@/types/priority'; const defaultTestCase = { id: 0, @@ -36,10 +37,11 @@ type Props = { folderId: string; caseId: string; messages: CaseMessages; + priorityMessages: PriorityMessages; locale: string; }; -export default function CaseEditor({ projectId, folderId, caseId, messages, locale }: Props) { +export default function CaseEditor({ projectId, folderId, caseId, messages, priorityMessages, locale }: Props) { const context = useContext(TokenContext); const [testCase, setTestCase] = useState(defaultTestCase); const [isTitleInvalid, setIsTitleInvalid] = useState(false); @@ -262,7 +264,7 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, loca > {priorities.map((priority, index) => ( - {messages[priority.uid]} + {priorityMessages[priority.uid]} ))} diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx index cbb9569..ceb5ab2 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx @@ -1,3 +1,4 @@ +import { PriorityMessages } from '@/types/priority'; import CaseEditor from './CaseEditor'; import { useTranslations } from 'next-intl'; @@ -22,10 +23,6 @@ export default function Page({ description: t('description'), testCaseDescription: t('test_case_description'), priority: t('priority'), - critical: t('critical'), - high: t('high'), - medium: t('medium'), - low: t('low'), type: t('type'), other: t('other'), security: t('security'), @@ -61,12 +58,21 @@ export default function Page({ areYouSureLeave: t('are_you_sure_leave'), }; + const priorityTranslation = useTranslations('Priority'); + const priorityMessages: PriorityMessages = { + critical: priorityTranslation('critical'), + high: priorityTranslation('high'), + medium: priorityTranslation('medium'), + low: priorityTranslation('low'), + }; + return ( ); diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx index ce43a1c..1ce606c 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/page.tsx @@ -1,3 +1,4 @@ +import { PriorityMessages } from '@/types/priority'; import CasesPane from './CasesPane'; import { useTranslations } from 'next-intl'; @@ -15,10 +16,6 @@ export default function Page({ params }: { params: { projectId: string; folderId areYouSure: t('are_you_sure'), newTestCase: t('new_test_case'), status: t('status'), - critical: t('critical'), - high: t('high'), - medium: t('medium'), - low: t('low'), noCasesFound: t('no_cases_found'), caseTitle: t('case_title'), caseDescription: t('case_description'), @@ -26,9 +23,23 @@ export default function Page({ params }: { params: { projectId: string; folderId pleaseEnter: t('please_enter'), }; + const priorityTranslation = useTranslations('Priority'); + const priorityMessages: PriorityMessages = { + critical: priorityTranslation('critical'), + high: priorityTranslation('high'), + medium: priorityTranslation('medium'), + low: priorityTranslation('low'), + }; + return ( <> - + ); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx index 06f00b5..a0c8bbe 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx @@ -13,6 +13,7 @@ import TestPriorityChart from './TestPriorityDonutChart'; import TestProgressBarChart from './TestProgressColumnChart'; import Config from '@/config/config'; import { useTheme } from 'next-themes'; +import { PriorityMessages } from '@/types/priority'; const apiServer = Config.apiServer; async function fetchProject(jwt: string, projectId: number) { @@ -41,9 +42,10 @@ async function fetchProject(jwt: string, projectId: number) { type Props = { projectId: string; messages: HomeMessages; + priorityMessages: PriorityMessages; }; -export function ProjectHome({ projectId, messages }: Props) { +export function ProjectHome({ projectId, messages, priorityMessages }: Props) { const context = useContext(TokenContext); const { theme, setTheme } = useTheme(); const [project, setProject] = useState({ @@ -134,7 +136,7 @@ export function ProjectHome({ projectId, messages }: Props) {

{messages.byPriority}

- +
diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx index 67330e1..757647e 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestPriorityDonutChart.tsx @@ -3,16 +3,16 @@ import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { priorities } from '@/config/selection'; import { CasePriorityCountType } from '@/types/case'; -import { HomeMessages } from './page'; +import { PriorityMessages } from '@/types/priority'; const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); type Props = { priorityCounts: CasePriorityCountType[]; - messages: HomeMessages; + priorityMessages: PriorityMessages; theme: string; }; -export default function TestPriorityDonutChart({ priorityCounts, messages, theme }: Props) { +export default function TestPriorityDonutChart({ priorityCounts, priorityMessages, theme }: Props) { const [chartData, setChartData] = useState({ series: [], options: { @@ -29,7 +29,7 @@ export default function TestPriorityDonutChart({ priorityCounts, messages, theme return found ? found.count : 0; }); - const labels = priorities.map((entry) => messages[entry.uid]); + const labels = priorities.map((entry) => priorityMessages[entry.uid]); const colors = priorities.map((entry) => entry.chartColor); const legend = { labels: { diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index 73b4c57..385b666 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -1,5 +1,6 @@ import { ProjectHome } from './ProjectHome'; import { useTranslations } from 'next-intl'; +import { PriorityMessages } from '@/types/priority'; export type HomeMessages = { folders: string; @@ -28,10 +29,6 @@ export type HomeMessages = { regression: string; automated: string; manual: string; - critical: string; - high: string; - medium: string; - low: string; }; export default function Page({ params }: { params: { projectId: string } }) { @@ -62,14 +59,19 @@ export default function Page({ params }: { params: { projectId: string } }) { regression: t('regression'), automated: t('automated'), manual: t('manual'), - critical: t('critical'), - high: t('high'), - medium: t('medium'), - low: t('low'), }; + + const pt = useTranslations('Priority'); + const priorityMessages: PriorityMessages = { + critical: pt('critical'), + high: pt('high'), + medium: pt('medium'), + low: pt('low'), + }; + return ( <> - + ); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx index 9d1c939..e84553a 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx @@ -1,9 +1,9 @@ import { Button, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react'; import { testTypes, templates } from '@/config/selection'; -import TestCasePriority from '@/components/TestCasePriority'; import { RunMessages } from '@/types/run'; import { CaseType } from '@/types/case'; import { PriorityMessages } from '@/types/priority'; +import TestCasePriority from '@/components/TestCasePriority'; type Props = { isOpen: boolean; diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx index 4202fda..3f713a8 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx @@ -26,11 +26,12 @@ import { CircleSlash2, } from 'lucide-react'; import { NextUiLinkClasses } from '@/src/navigation'; -import { priorities, testRunCaseStatus } from '@/config/selection'; +import { testRunCaseStatus } from '@/config/selection'; import { CaseType } from '@/types/case'; import { RunMessages } from '@/types/run'; import TestCaseDetailDialog from './TestCaseDetailDialog'; import { PriorityMessages } from '@/types/priority'; +import TestCasePriority from '@/components/TestCasePriority'; type Props = { cases: CaseType[]; @@ -95,7 +96,6 @@ export default function TestCaseSelector({ }, [sortDescriptor, cases]); const notIncludedCaseClass = 'text-neutral-200 dark:text-neutral-600'; - const chipBaseClass = 'flex items-center text-default-600'; const renderStatusIcon = (uid: string) => { if (uid === 'untested') { @@ -142,13 +142,8 @@ export default function TestCaseSelector({ ); case 'priority': return ( -
- -
{messages[priorities[cellValue].uid]}
+
+
); case 'runStatus': diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx index bc8db9b..59a460c 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx @@ -55,12 +55,12 @@ export default function Page({ params }: { params: { projectId: string; runId: s close: t('close'), }; - const priorityTranslation = useTranslations('Priority'); + const pt = useTranslations('Priority'); const priorityMessages: PriorityMessages = { - critical: priorityTranslation('critical'), - high: priorityTranslation('high'), - medium: priorityTranslation('medium'), - low: priorityTranslation('low'), + critical: pt('critical'), + high: pt('high'), + medium: pt('medium'), + low: pt('low'), }; return ( diff --git a/frontend/types/priority.ts b/frontend/types/priority.ts index b3779e0..eabc86a 100644 --- a/frontend/types/priority.ts +++ b/frontend/types/priority.ts @@ -1,7 +1,16 @@ +type PriorityUidType = 'critical' | 'high' | 'medium' | 'low'; + +type PriorityType = { + uid: PriorityUidType; + color: string; + chartColor: string; +}; + type PriorityMessages = { critical: string; high: string; medium: string; low: string; }; -export type { PriorityMessages }; + +export type { PriorityUidType, PriorityType, PriorityMessages }; diff --git a/frontend/types/run.ts b/frontend/types/run.ts index 93b72bf..0f060bb 100644 --- a/frontend/types/run.ts +++ b/frontend/types/run.ts @@ -68,10 +68,6 @@ type RunMessages = { priority: string; status: string; actions: string; - critical: string; - high: string; - medium: string; - low: string; untested: string; passed: string; failed: string; From 1751dd69a251098ba9dc7de3683447dfdd939142 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 14:49:08 +0900 Subject: [PATCH 05/14] refactor: test types messages duplication --- frontend/config/selection.ts | 3 +- frontend/messages/en.json | 56 ++++++------------- frontend/messages/ja.json | 56 ++++++------------- .../[folderId]/cases/[caseId]/CaseEditor.tsx | 14 ++++- .../[folderId]/cases/[caseId]/page.tsx | 32 ++++++----- .../projects/[projectId]/home/ProjectHome.tsx | 12 ++-- .../[projectId]/home/TestTypesDonutChart.tsx | 8 +-- .../projects/[projectId]/home/page.tsx | 52 ++++++++--------- frontend/types/case.ts | 17 ------ frontend/types/run.ts | 13 ----- frontend/types/testType.ts | 37 ++++++++++++ 11 files changed, 137 insertions(+), 163 deletions(-) create mode 100644 frontend/types/testType.ts diff --git a/frontend/config/selection.ts b/frontend/config/selection.ts index d54055b..095aadd 100644 --- a/frontend/config/selection.ts +++ b/frontend/config/selection.ts @@ -1,3 +1,4 @@ +import { TestTypeType } from '@/types/testType'; import { PriorityType } from '@/types/priority'; const roles = [{ uid: 'administrator' }, { uid: 'user' }]; @@ -18,7 +19,7 @@ const priorities: PriorityType[] = [ { uid: 'low', color: '#94d2bd', chartColor: '#94d2bd' }, ]; -const testTypes = [ +const testTypes: TestTypeType[] = [ { uid: 'other', chartColor: categoricalPalette[0] }, { uid: 'security', chartColor: categoricalPalette[1] }, { uid: 'performance', chartColor: categoricalPalette[2] }, diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 91034cc..0f1e7f1 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -5,6 +5,21 @@ "medium": "Medium", "low": "Low" }, + "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" + }, "Index": { "get_started": "Get Started", "demo": "Demo", @@ -120,20 +135,7 @@ "skipped": "Skipped", "test_classification": "Test Classification", "by_type": "By test type", - "by_priority": "By test priority", - "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" + "by_priority": "By test priority" }, "Folders": { "folder": "Folder", @@ -179,19 +181,6 @@ "test_case_description": "Test case description", "priority": "Priority", "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", "template": "Template", "test_detail": "Test detail", "preconditions": "Preconditions", @@ -264,19 +253,6 @@ "no_cases_found": "No cases found", "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", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index 3fd7cb3..955194e 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -6,6 +6,21 @@ "medium": "中", "low": "低" }, + "Type": { + "other": "その他", + "security": "セキュリティ", + "performance": "パフォーマンス", + "accessibility": "アクセシビリティ", + "functional": "機能", + "acceptance": "受け入れ", + "usability": "ユーザビリティ", + "smoke_sanity": "スモーク/サニティ", + "compatibility": "互換性", + "destructive": "破壊", + "regression": "回帰", + "automated": "自動", + "manual": "手動" + }, "Index": { "get_started": "テスト管理を始める", "demo": "デモ", @@ -121,20 +136,7 @@ "skipped": "スキップ", "test_classification": "テスト分類", "by_type": "タイプ別", - "by_priority": "優先度別", - "other": "その他", - "security": "セキュリティ", - "performance": "パフォーマンス", - "accessibility": "アクセシビリティ", - "functional": "機能", - "acceptance": "受け入れ", - "usability": "ユーザビリティ", - "smoke_sanity": "スモーク/サニティ", - "compatibility": "互換性", - "destructive": "破壊", - "regression": "回帰", - "automated": "自動", - "manual": "手動" + "by_priority": "優先度別" }, "Folders": { "folder": "フォルダー", @@ -180,19 +182,6 @@ "test_case_description": "テストケース詳細", "priority": "優先度", "type": "タイプ", - "other": "その他", - "security": "セキュリティ", - "performance": "パフォーマンス", - "accessibility": "アクセシビリティ", - "functional": "機能", - "acceptance": "受け入れ", - "usability": "ユーザビリティ", - "smoke_sanity": "スモーク/サニティ", - "compatibility": "互換性", - "destructive": "破壊", - "regression": "回帰", - "automated": "自動", - "manual": "手動", "template": "テンプレート", "test_detail": "テスト詳細", "preconditions": "前提条件", @@ -265,19 +254,6 @@ "no_cases_found": "テストケースが見つかりません", "are_you_sure_leave": "ページを離れてもよろしいですか", "type": "タイプ", - "other": "その他", - "security": "セキュリティ", - "performance": "パフォーマンス", - "accessibility": "アクセシビリティ", - "functional": "機能", - "acceptance": "受け入れ", - "usability": "ユーザビリティ", - "smoke_sanity": "スモーク/サニティ", - "compatibility": "互換性", - "destructive": "破壊", - "regression": "回帰", - "automated": "自動", - "manual": "手動", "test_detail": "テスト詳細", "preconditions": "前提条件", "expected_result": "期待結果", diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx index cb7f5c7..c956a9e 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/CaseEditor.tsx @@ -13,6 +13,7 @@ import { TokenContext } from '@/utils/TokenProvider'; import { useFormGuard } from '@/utils/formGuard'; import { CaseType, AttachmentType, CaseMessages, StepType } from '@/types/case'; import { PriorityMessages } from '@/types/priority'; +import { TestTypeMessages } from '@/types/testType'; const defaultTestCase = { id: 0, @@ -37,11 +38,20 @@ type Props = { folderId: string; caseId: string; messages: CaseMessages; + testTypeMessages: TestTypeMessages; priorityMessages: PriorityMessages; locale: string; }; -export default function CaseEditor({ projectId, folderId, caseId, messages, priorityMessages, locale }: Props) { +export default function CaseEditor({ + projectId, + folderId, + caseId, + messages, + testTypeMessages, + priorityMessages, + locale, +}: Props) { const context = useContext(TokenContext); const [testCase, setTestCase] = useState(defaultTestCase); const [isTitleInvalid, setIsTitleInvalid] = useState(false); @@ -285,7 +295,7 @@ export default function CaseEditor({ projectId, folderId, caseId, messages, prio > {testTypes.map((type, index) => ( - {messages[type.uid]} + {testTypeMessages[type.uid]} ))} diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx index ceb5ab2..e2ace79 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/[caseId]/page.tsx @@ -1,6 +1,7 @@ import { PriorityMessages } from '@/types/priority'; import CaseEditor from './CaseEditor'; import { useTranslations } from 'next-intl'; +import { TestTypeMessages } from '@/types/testType'; export default function Page({ params, @@ -24,19 +25,6 @@ export default function Page({ testCaseDescription: t('test_case_description'), priority: t('priority'), 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'), template: t('template'), testDetail: t('test_detail'), preconditions: t('preconditions'), @@ -58,6 +46,23 @@ export default function Page({ areYouSureLeave: t('are_you_sure_leave'), }; + 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'), + }; + const priorityTranslation = useTranslations('Priority'); const priorityMessages: PriorityMessages = { critical: priorityTranslation('critical'), @@ -72,6 +77,7 @@ export default function Page({ folderId={params.folderId} caseId={params.caseId} messages={messages} + testTypeMessages={testTypeMessages} priorityMessages={priorityMessages} locale={params.locale} /> diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx index a0c8bbe..1a41551 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx @@ -8,12 +8,13 @@ import { ProgressSeriesType } from '@/types/run'; import { HomeMessages } from './page'; import { TokenContext } from '@/utils/TokenProvider'; import { aggregateBasicInfo, aggregateTestPriority, aggregateTestType, aggregateProgress } from './aggregate'; -import TestTypesChart from './TestTypesDonutChart'; -import TestPriorityChart from './TestPriorityDonutChart'; -import TestProgressBarChart from './TestProgressColumnChart'; import Config from '@/config/config'; import { useTheme } from 'next-themes'; import { PriorityMessages } from '@/types/priority'; +import { TestTypeMessages } from '@/types/testType'; +import TestTypesChart from './TestTypesDonutChart'; +import TestPriorityChart from './TestPriorityDonutChart'; +import TestProgressBarChart from './TestProgressColumnChart'; const apiServer = Config.apiServer; async function fetchProject(jwt: string, projectId: number) { @@ -42,10 +43,11 @@ async function fetchProject(jwt: string, projectId: number) { type Props = { projectId: string; messages: HomeMessages; + testTypeMessages: TestTypeMessages; priorityMessages: PriorityMessages; }; -export function ProjectHome({ projectId, messages, priorityMessages }: Props) { +export function ProjectHome({ projectId, messages, testTypeMessages, priorityMessages }: Props) { const context = useContext(TokenContext); const { theme, setTheme } = useTheme(); const [project, setProject] = useState({ @@ -132,7 +134,7 @@ export function ProjectHome({ projectId, messages, priorityMessages }: Props) {

{messages.byType}

- +

{messages.byPriority}

diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx index a520162..8a2486b 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/TestTypesDonutChart.tsx @@ -3,16 +3,16 @@ import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { testTypes } from '@/config/selection'; import { CaseTypeCountType } from '@/types/case'; -import { HomeMessages } from './page'; +import { TestTypeMessages } from '@/types/testType'; const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); type Props = { typesCounts: CaseTypeCountType[]; - messages: HomeMessages; + testTypeMessages: TestTypeMessages; theme: string; }; -export default function TestTypesDonutChart({ typesCounts, messages, theme }: Props) { +export default function TestTypesDonutChart({ typesCounts, testTypeMessages, theme }: Props) { const [chartData, setChartData] = useState({ series: [], options: { @@ -29,7 +29,7 @@ export default function TestTypesDonutChart({ typesCounts, messages, theme }: Pr return found ? found.count : 0; }); - const labels = testTypes.map((entry) => messages[entry.uid]); + const labels = testTypes.map((entry) => testTypeMessages[entry.uid]); const colors = testTypes.map((entry) => entry.chartColor); const legend = { labels: { diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index 385b666..64a78b3 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -1,6 +1,7 @@ import { ProjectHome } from './ProjectHome'; import { useTranslations } from 'next-intl'; import { PriorityMessages } from '@/types/priority'; +import { TestTypeMessages } from '@/types/testType'; export type HomeMessages = { folders: string; @@ -15,20 +16,6 @@ export type HomeMessages = { testClassification: string; byType: string; byPriority: string; - testTypes: 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; }; export default function Page({ params }: { params: { projectId: string } }) { @@ -46,19 +33,23 @@ export default function Page({ params }: { params: { projectId: string } }) { testClassification: t('test_classification'), byType: t('by_type'), byPriority: t('by_priority'), - 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'), + }; + + 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'), }; const pt = useTranslations('Priority'); @@ -71,7 +62,12 @@ export default function Page({ params }: { params: { projectId: string } }) { return ( <> - + ); } diff --git a/frontend/types/case.ts b/frontend/types/case.ts index 09da508..325eaee 100644 --- a/frontend/types/case.ts +++ b/frontend/types/case.ts @@ -81,10 +81,6 @@ type CasesMessages = { delete: string; newTestCase: string; status: string; - critical: string; - high: string; - medium: string; - low: string; noCasesFound: string; caseTitle: string; caseDescription: string; @@ -102,19 +98,6 @@ type CaseMessages = { description: string; testCaseDescription: 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; template: string; testDetail: string; preconditions: string; diff --git a/frontend/types/run.ts b/frontend/types/run.ts index 0f060bb..d5eaf8a 100644 --- a/frontend/types/run.ts +++ b/frontend/types/run.ts @@ -80,19 +80,6 @@ type RunMessages = { noCasesFound: 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; diff --git a/frontend/types/testType.ts b/frontend/types/testType.ts new file mode 100644 index 0000000..34d735d --- /dev/null +++ b/frontend/types/testType.ts @@ -0,0 +1,37 @@ +type TestTypeUidType = + | 'other' + | 'security' + | 'performance' + | 'accessibility' + | 'functional' + | 'acceptance' + | 'usability' + | 'smokeSanity' + | 'compatibility' + | 'destructive' + | 'regression' + | 'automated' + | 'manual'; + +type TestTypeType = { + uid: TestTypeUidType; + chartColor: string; +}; + +type TestTypeMessages = { + 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; +}; + +export type { TestTypeUidType, TestTypeType, TestTypeMessages }; From f797ae2581db7aed6c78ec6dfc152ade8dae28f0 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:16:40 +0900 Subject: [PATCH 06/14] refactor: test run case status messages duplication --- frontend/config/selection.ts | 25 ++++++++-------- frontend/messages/en.json | 17 +++++------ frontend/messages/ja.json | 17 +++++------ .../projects/[projectId]/home/ProjectHome.tsx | 13 +++++---- .../projects/[projectId]/home/aggregate.ts | 6 ++-- .../projects/[projectId]/home/page.tsx | 21 +++++++------- .../[projectId]/runs/[runId]/RunEditor.tsx | 7 +++-- .../runs/[runId]/RunPregressDonutChart.tsx | 9 +++--- .../runs/[runId]/TestCaseSelector.tsx | 7 +++-- .../[projectId]/runs/[runId]/page.tsx | 29 +++++++------------ frontend/types/testStatus.ts | 17 +++++++++++ 11 files changed, 92 insertions(+), 76 deletions(-) create mode 100644 frontend/types/testStatus.ts diff --git a/frontend/config/selection.ts b/frontend/config/selection.ts index 095aadd..2239feb 100644 --- a/frontend/config/selection.ts +++ b/frontend/config/selection.ts @@ -1,5 +1,6 @@ import { TestTypeType } from '@/types/testType'; import { PriorityType } from '@/types/priority'; +import { TestStatusType } from '@/types/testStatus'; const roles = [{ uid: 'administrator' }, { uid: 'user' }]; @@ -12,6 +13,18 @@ const locales = [ { code: 'ja', name: '日本語' }, ]; +const testRunCaseStatus: TestStatusType[] = [ + { + uid: 'untested', + color: 'primary', + chartColor: '#3ac6e1', + }, + { uid: 'passed', color: 'success', chartColor: '#6ea56c' }, + { uid: 'failed', color: 'danger', chartColor: '#f15f47' }, + { uid: 'retest', color: 'warning', chartColor: '#fba91e' }, + { uid: 'skipped', color: 'primary', chartColor: '#805aab' }, +]; + const priorities: PriorityType[] = [ { uid: 'critical', color: '#bb3e03', chartColor: '#bb3e03' }, { uid: 'high', color: '#ca6702', chartColor: '#ca6702' }, @@ -53,18 +66,6 @@ const testRunStatus = [ { uid: 'closed' }, ]; -const testRunCaseStatus = [ - { - uid: 'untested', - color: 'primary', - chartColor: '#3ac6e1', - }, - { uid: 'passed', color: 'success', chartColor: '#6ea56c' }, - { uid: 'failed', color: 'danger', chartColor: '#f15f47' }, - { uid: 'retest', color: 'warning', chartColor: '#fba91e' }, - { uid: 'skipped', color: 'primary', chartColor: '#805aab' }, -]; - export { roles, memberRoles, diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 0f1e7f1..bd10a03 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -1,4 +1,11 @@ { + "Status": { + "untested": "Untested", + "passed": "Passed", + "failed": "Failed", + "retest": "Retest", + "skipped": "Skipped" + }, "Priority": { "critical": "Critical", "high": "High", @@ -128,11 +135,6 @@ "test_cases": "Test Cases", "test_runs": "Test Runs", "progress": "Progress", - "untested": "Untested", - "passed": "Passed", - "failed": "Failed", - "retest": "Retest", - "skipped": "Skipped", "test_classification": "Test Classification", "by_type": "By test type", "by_priority": "By test priority" @@ -241,11 +243,6 @@ "priority": "Priority", "status": "Status", "actions": "Actions", - "untested": "Untested", - "passed": "Passed", - "failed": "Failed", - "retest": "Retest", - "skipped": "Skipped", "select_test_case": "Select test cases", "test_case_selection": "Test case selection", "include_in_run": "Include in run", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index 955194e..dc622af 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -1,4 +1,11 @@ { + "Status": { + "untested": "未実行", + "passed": "成功", + "failed": "失敗", + "retest": "再テスト", + "skipped": "スキップ" + }, "Priority": { "priority": "優先度", "critical": "致", @@ -129,11 +136,6 @@ "test_cases": "テストケース", "test_runs": "テストラン", "progress": "進捗", - "untested": "未実行", - "passed": "成功", - "failed": "失敗", - "retest": "再テスト", - "skipped": "スキップ", "test_classification": "テスト分類", "by_type": "タイプ別", "by_priority": "優先度別" @@ -242,11 +244,6 @@ "priority": "優先度", "status": "ステータス", "actions": "アクション", - "untested": "未実行", - "passed": "成功", - "failed": "失敗", - "retest": "再テスト", - "skipped": "スキップ", "select_test_case": "テストケースを選択", "test_case_selection": "テストケース選択", "include_in_run": "テストランに含める", diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx index 1a41551..671f70a 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx @@ -10,11 +10,13 @@ import { TokenContext } from '@/utils/TokenProvider'; import { aggregateBasicInfo, aggregateTestPriority, aggregateTestType, aggregateProgress } from './aggregate'; import Config from '@/config/config'; import { useTheme } from 'next-themes'; -import { PriorityMessages } from '@/types/priority'; -import { TestTypeMessages } from '@/types/testType'; import TestTypesChart from './TestTypesDonutChart'; import TestPriorityChart from './TestPriorityDonutChart'; import TestProgressBarChart from './TestProgressColumnChart'; +import { TestStatusMessages } from '@/types/testStatus'; +import { TestTypeMessages } from '@/types/testType'; +import { PriorityMessages } from '@/types/priority'; + const apiServer = Config.apiServer; async function fetchProject(jwt: string, projectId: number) { @@ -43,11 +45,12 @@ async function fetchProject(jwt: string, projectId: number) { type Props = { projectId: string; messages: HomeMessages; + statusMessages: TestStatusMessages; testTypeMessages: TestTypeMessages; priorityMessages: PriorityMessages; }; -export function ProjectHome({ projectId, messages, testTypeMessages, priorityMessages }: Props) { +export function ProjectHome({ projectId, messages, statusMessages, testTypeMessages, priorityMessages }: Props) { const context = useContext(TokenContext); const { theme, setTheme } = useTheme(); const [project, setProject] = useState({ @@ -71,7 +74,7 @@ export function ProjectHome({ projectId, messages, testTypeMessages, priorityMes } try { - const data = await fetchProject(context.token.access_token, projectId); + const data = await fetchProject(context.token.access_token, Number(projectId)); setProject(data); } catch (error: any) { console.error('Error in effect:', error.message); @@ -94,7 +97,7 @@ export function ProjectHome({ projectId, messages, testTypeMessages, priorityMes const priorityRet = aggregateTestPriority(project); setPriorityCounts([...priorityRet]); - const { series, categories } = aggregateProgress(project, messages); + const { series, categories } = aggregateProgress(project, statusMessages); setProgressSeries([...series]); setProgressCategories([...categories]); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts index aca7a3b..c2630f5 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts @@ -1,6 +1,6 @@ import { ProjectType } from '@/types/project'; import { testTypes, priorities, testRunCaseStatus } from '@/config/selection'; -import { HomeMessages } from './page'; +import { TestStatusMessages } from '@/types/testStatus'; // aggregate folder, case, run mum function aggregateBasicInfo(project: ProjectType) { @@ -50,9 +50,9 @@ function aggregateTestPriority(project: ProjectType) { return result; } -function aggregateProgress(project: ProjectType, messages: HomeMessages) { +function aggregateProgress(project: ProjectType, statusMessages: TestStatusMessages) { let series = testRunCaseStatus.map((status) => { - return { name: messages[status.uid], data: [] }; + return { name: statusMessages[status.uid], data: [] }; }); let categories = []; diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index 64a78b3..116fccd 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -2,17 +2,13 @@ import { ProjectHome } from './ProjectHome'; import { useTranslations } from 'next-intl'; import { PriorityMessages } from '@/types/priority'; import { TestTypeMessages } from '@/types/testType'; +import { TestStatusMessages } from '@/types/testStatus'; export type HomeMessages = { folders: string; testCases: string; testRuns: string; progress: string; - untested: string; - passed: string; - failed: string; - retest: string; - skipped: string; testClassification: string; byType: string; byPriority: string; @@ -25,16 +21,20 @@ export default function Page({ params }: { params: { projectId: string } }) { testCases: t('test_cases'), testRuns: t('test_runs'), progress: t('progress'), - untested: t('untested'), - passed: t('passed'), - failed: t('failed'), - retest: t('retest'), - skipped: t('skipped'), testClassification: t('test_classification'), byType: t('by_type'), byPriority: t('by_priority'), }; + const st = useTranslations('Status'); + const statusMessages: TestStatusMessages = { + untested: st('untested'), + passed: st('passed'), + failed: st('failed'), + retest: st('retest'), + skipped: st('skipped'), + }; + const tt = useTranslations('Type'); const testTypeMessages: TestTypeMessages = { other: tt('other'), @@ -65,6 +65,7 @@ export default function Page({ params }: { params: { projectId: string } }) { diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx index 6a59045..9dbe7cb 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx @@ -38,6 +38,7 @@ import { TokenContext } from '@/utils/TokenProvider'; import { useTheme } from 'next-themes'; import { useFormGuard } from '@/utils/formGuard'; import { PriorityMessages } from '@/types/priority'; +import { TestStatusMessages } from '@/types/testStatus'; const defaultTestRun = { id: 0, @@ -54,11 +55,12 @@ type Props = { projectId: string; runId: string; messages: RunMessages; + statusMessages: TestStatusMessages; priorityMessages: PriorityMessages; locale: string; }; -export default function RunEditor({ projectId, runId, messages, priorityMessages, locale }: Props) { +export default function RunEditor({ projectId, runId, messages, statusMessages, priorityMessages, locale }: Props) { const context = useContext(TokenContext); const { theme, setTheme } = useTheme(); const [testRun, setTestRun] = useState(defaultTestRun); @@ -204,7 +206,7 @@ export default function RunEditor({ projectId, runId, messages, priorityMessages
- +
@@ -316,6 +318,7 @@ export default function RunEditor({ projectId, runId, messages, priorityMessages onIncludeCase={(includeTestId) => handleIncludeExcludeCase(true, includeTestId)} onExcludeCase={(excludeCaseId) => handleIncludeExcludeCase(false, excludeCaseId)} messages={messages} + statusMessages={statusMessages} priorityMessages={priorityMessages} />
diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx index c492a45..b7b8831 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx @@ -2,16 +2,17 @@ import React from 'react'; import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { testRunCaseStatus } from '@/config/selection'; -import { RunStatusCountType, RunMessages } from '@/types/run'; +import { RunStatusCountType } from '@/types/run'; +import { TestStatusMessages } from '@/types/testStatus'; const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); type Props = { statusCounts: RunStatusCountType[]; - messages: RunMessages; + statusMessages: TestStatusMessages; theme: string | undefined; }; -export default function RunProgressDounut({ statusCounts, messages, theme }: Props) { +export default function RunProgressDounut({ statusCounts, statusMessages, theme }: Props) { const [chartData, setChartData] = useState({ series: [], options: { @@ -28,7 +29,7 @@ export default function RunProgressDounut({ statusCounts, messages, theme }: Pro return found ? found.count : 0; }); - const labels = testRunCaseStatus.map((entry) => messages[entry.uid]); + const labels = testRunCaseStatus.map((entry) => statusMessages[entry.uid]); const colors = testRunCaseStatus.map((entry) => entry.chartColor); const legend = { labels: { diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx index 3f713a8..88bdb52 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx @@ -32,6 +32,7 @@ import { RunMessages } from '@/types/run'; import TestCaseDetailDialog from './TestCaseDetailDialog'; import { PriorityMessages } from '@/types/priority'; import TestCasePriority from '@/components/TestCasePriority'; +import { TestStatusMessages } from '@/types/testStatus'; type Props = { cases: CaseType[]; @@ -42,6 +43,7 @@ type Props = { onIncludeCase: (includeCaseId: number) => {}; onExcludeCase: (excludeCaseId: number) => {}; messages: RunMessages; + statusMessages: TestStatusMessages; priorityMessages: PriorityMessages; }; @@ -54,6 +56,7 @@ export default function TestCaseSelector({ onIncludeCase, onExcludeCase, messages, + statusMessages, priorityMessages, }: Props) { const headerColumns = [ @@ -157,7 +160,7 @@ export default function TestCaseSelector({ startContent={isIncluded && renderStatusIcon(testRunCaseStatus[runStatus].uid)} endContent={isIncluded && } > - {isIncluded && messages[testRunCaseStatus[runStatus].uid]} + {isIncluded && statusMessages[testRunCaseStatus[runStatus].uid]} @@ -167,7 +170,7 @@ export default function TestCaseSelector({ startContent={renderStatusIcon(runCaseStatus.uid)} onPress={() => onChangeStatus(testCase.id, index)} > - {messages[runCaseStatus.uid]} + {statusMessages[runCaseStatus.uid]} ))} diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx index 59a460c..efcd317 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx @@ -2,6 +2,7 @@ import RunEditor from './RunEditor'; import { useTranslations } from 'next-intl'; import { RunMessages } from '@/types/run'; import { PriorityMessages } from '@/types/priority'; +import { TestStatusMessages } from '@/types/testStatus'; export default function Page({ params }: { params: { projectId: string; runId: string; locale: string } }) { const t = useTranslations('Run'); @@ -24,11 +25,6 @@ export default function Page({ params }: { params: { projectId: string; runId: s priority: t('priority'), actions: t('actions'), status: t('status'), - untested: t('untested'), - passed: t('passed'), - failed: t('failed'), - retest: t('retest'), - skipped: t('skipped'), selectTestCase: t('select_test_case'), testCaseSelection: t('test_case_selection'), includeInRun: t('include_in_run'), @@ -36,25 +32,21 @@ export default function Page({ params }: { params: { projectId: string; runId: s noCasesFound: t('no_cases_found'), 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'), }; + const st = useTranslations('Status'); + const statusMessages: TestStatusMessages = { + untested: st('untested'), + passed: st('passed'), + failed: st('failed'), + retest: st('retest'), + skipped: st('skipped'), + }; + const pt = useTranslations('Priority'); const priorityMessages: PriorityMessages = { critical: pt('critical'), @@ -68,6 +60,7 @@ export default function Page({ params }: { params: { projectId: string; runId: s projectId={params.projectId} runId={params.runId} messages={messages} + statusMessages={statusMessages} priorityMessages={priorityMessages} locale={params.locale} /> diff --git a/frontend/types/testStatus.ts b/frontend/types/testStatus.ts new file mode 100644 index 0000000..bf7a247 --- /dev/null +++ b/frontend/types/testStatus.ts @@ -0,0 +1,17 @@ +type TestStatusUidType = 'untested' | 'passed' | 'failed' | 'retest' | 'skipped'; + +type TestStatusType = { + uid: TestStatusUidType; + color: string; + chartColor: string; +}; + +type TestStatusMessages = { + untested: string; + passed: string; + failed: string; + retest: string; + skipped: string; +}; + +export type { TestStatusUidType, TestStatusType, TestStatusMessages }; From 1da19ed43c195e8dc783e6ac6000fe2e57f0f4f0 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:30:04 +0900 Subject: [PATCH 07/14] refactor: test run case status messages duplication --- frontend/config/selection.ts | 24 ++++++++++--------- frontend/messages/en.json | 2 +- frontend/messages/ja.json | 2 +- .../projects/[projectId]/home/ProjectHome.tsx | 14 +++++++---- .../projects/[projectId]/home/aggregate.ts | 6 ++--- .../projects/[projectId]/home/page.tsx | 18 +++++++------- .../[projectId]/runs/[runId]/RunEditor.tsx | 21 ++++++++++++---- .../runs/[runId]/RunPregressDonutChart.tsx | 8 +++---- .../runs/[runId]/TestCaseSelector.tsx | 12 ++++++---- .../[projectId]/runs/[runId]/page.tsx | 18 +++++++------- frontend/types/testRunCaseStatus.ts | 18 ++++++++++++++ frontend/types/testStatus.ts | 17 ------------- 12 files changed, 91 insertions(+), 69 deletions(-) create mode 100644 frontend/types/testRunCaseStatus.ts delete mode 100644 frontend/types/testStatus.ts diff --git a/frontend/config/selection.ts b/frontend/config/selection.ts index 2239feb..98bb76e 100644 --- a/frontend/config/selection.ts +++ b/frontend/config/selection.ts @@ -1,6 +1,6 @@ import { TestTypeType } from '@/types/testType'; import { PriorityType } from '@/types/priority'; -import { TestStatusType } from '@/types/testStatus'; +import { TestRunCaseStatusType } from '@/types/testRunCaseStatus'; const roles = [{ uid: 'administrator' }, { uid: 'user' }]; @@ -13,7 +13,18 @@ const locales = [ { code: 'ja', name: '日本語' }, ]; -const testRunCaseStatus: TestStatusType[] = [ +// The status of each test run +const testRunStatus = [ + { uid: 'new' }, + { uid: 'inProgress' }, + { uid: 'underReview' }, + { uid: 'rejected' }, + { uid: 'done' }, + { uid: 'closed' }, +]; + +// The status of each test case in test run +const testRunCaseStatus: TestRunCaseStatusType[] = [ { uid: 'untested', color: 'primary', @@ -57,15 +68,6 @@ const automationStatus = [ const templates = [{ uid: 'text' }, { uid: 'step' }]; -const testRunStatus = [ - { uid: 'new' }, - { uid: 'inProgress' }, - { uid: 'underReview' }, - { uid: 'rejected' }, - { uid: 'done' }, - { uid: 'closed' }, -]; - export { roles, memberRoles, diff --git a/frontend/messages/en.json b/frontend/messages/en.json index bd10a03..4aebf1f 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -1,5 +1,5 @@ { - "Status": { + "RunCaseStatus": { "untested": "Untested", "passed": "Passed", "failed": "Failed", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index dc622af..37e11d2 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -1,5 +1,5 @@ { - "Status": { + "RunCaseStatus": { "untested": "未実行", "passed": "成功", "failed": "失敗", diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx index 671f70a..102b568 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx @@ -13,7 +13,7 @@ import { useTheme } from 'next-themes'; import TestTypesChart from './TestTypesDonutChart'; import TestPriorityChart from './TestPriorityDonutChart'; import TestProgressBarChart from './TestProgressColumnChart'; -import { TestStatusMessages } from '@/types/testStatus'; +import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; import { TestTypeMessages } from '@/types/testType'; import { PriorityMessages } from '@/types/priority'; @@ -45,12 +45,18 @@ async function fetchProject(jwt: string, projectId: number) { type Props = { projectId: string; messages: HomeMessages; - statusMessages: TestStatusMessages; + testRunCaseStatusMessages: TestRunCaseStatusMessages; testTypeMessages: TestTypeMessages; priorityMessages: PriorityMessages; }; -export function ProjectHome({ projectId, messages, statusMessages, testTypeMessages, priorityMessages }: Props) { +export function ProjectHome({ + projectId, + messages, + testRunCaseStatusMessages, + testTypeMessages, + priorityMessages, +}: Props) { const context = useContext(TokenContext); const { theme, setTheme } = useTheme(); const [project, setProject] = useState({ @@ -97,7 +103,7 @@ export function ProjectHome({ projectId, messages, statusMessages, testTypeMessa const priorityRet = aggregateTestPriority(project); setPriorityCounts([...priorityRet]); - const { series, categories } = aggregateProgress(project, statusMessages); + const { series, categories } = aggregateProgress(project, testRunCaseStatusMessages); setProgressSeries([...series]); setProgressCategories([...categories]); } diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts index c2630f5..474c168 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts @@ -1,6 +1,6 @@ import { ProjectType } from '@/types/project'; import { testTypes, priorities, testRunCaseStatus } from '@/config/selection'; -import { TestStatusMessages } from '@/types/testStatus'; +import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; // aggregate folder, case, run mum function aggregateBasicInfo(project: ProjectType) { @@ -50,9 +50,9 @@ function aggregateTestPriority(project: ProjectType) { return result; } -function aggregateProgress(project: ProjectType, statusMessages: TestStatusMessages) { +function aggregateProgress(project: ProjectType, testRunCaseStatusMessages: TestRunCaseStatusMessages) { let series = testRunCaseStatus.map((status) => { - return { name: statusMessages[status.uid], data: [] }; + return { name: testRunCaseStatusMessages[status.uid], data: [] }; }); let categories = []; diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index 116fccd..895d758 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -2,7 +2,7 @@ import { ProjectHome } from './ProjectHome'; import { useTranslations } from 'next-intl'; import { PriorityMessages } from '@/types/priority'; import { TestTypeMessages } from '@/types/testType'; -import { TestStatusMessages } from '@/types/testStatus'; +import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; export type HomeMessages = { folders: string; @@ -26,13 +26,13 @@ export default function Page({ params }: { params: { projectId: string } }) { byPriority: t('by_priority'), }; - const st = useTranslations('Status'); - const statusMessages: TestStatusMessages = { - untested: st('untested'), - passed: st('passed'), - failed: st('failed'), - retest: st('retest'), - skipped: st('skipped'), + const rcst = useTranslations('RunCaseStatus'); + const testRunCaseStatusMessages: TestRunCaseStatusMessages = { + untested: rcst('untested'), + passed: rcst('passed'), + failed: rcst('failed'), + retest: rcst('retest'), + skipped: rcst('skipped'), }; const tt = useTranslations('Type'); @@ -65,7 +65,7 @@ export default function Page({ params }: { params: { projectId: string } }) { diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx index 9dbe7cb..320108c 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx @@ -38,7 +38,7 @@ import { TokenContext } from '@/utils/TokenProvider'; import { useTheme } from 'next-themes'; import { useFormGuard } from '@/utils/formGuard'; import { PriorityMessages } from '@/types/priority'; -import { TestStatusMessages } from '@/types/testStatus'; +import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; const defaultTestRun = { id: 0, @@ -55,12 +55,19 @@ type Props = { projectId: string; runId: string; messages: RunMessages; - statusMessages: TestStatusMessages; + testRunCaseStatusMessages: TestRunCaseStatusMessages; priorityMessages: PriorityMessages; locale: string; }; -export default function RunEditor({ projectId, runId, messages, statusMessages, priorityMessages, locale }: Props) { +export default function RunEditor({ + projectId, + runId, + messages, + testRunCaseStatusMessages, + priorityMessages, + locale, +}: Props) { const context = useContext(TokenContext); const { theme, setTheme } = useTheme(); const [testRun, setTestRun] = useState(defaultTestRun); @@ -206,7 +213,11 @@ export default function RunEditor({ projectId, runId, messages, statusMessages, - +
@@ -318,7 +329,7 @@ export default function RunEditor({ projectId, runId, messages, statusMessages, onIncludeCase={(includeTestId) => handleIncludeExcludeCase(true, includeTestId)} onExcludeCase={(excludeCaseId) => handleIncludeExcludeCase(false, excludeCaseId)} messages={messages} - statusMessages={statusMessages} + testRunCaseStatusMessages={testRunCaseStatusMessages} priorityMessages={priorityMessages} />
diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx index b7b8831..6c3f0a2 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx @@ -3,16 +3,16 @@ import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { testRunCaseStatus } from '@/config/selection'; import { RunStatusCountType } from '@/types/run'; -import { TestStatusMessages } from '@/types/testStatus'; +import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); type Props = { statusCounts: RunStatusCountType[]; - statusMessages: TestStatusMessages; + testRunCaseStatusMessages: TestRunCaseStatusMessages; theme: string | undefined; }; -export default function RunProgressDounut({ statusCounts, statusMessages, theme }: Props) { +export default function RunProgressDounut({ statusCounts, testRunCaseStatusMessages, theme }: Props) { const [chartData, setChartData] = useState({ series: [], options: { @@ -29,7 +29,7 @@ export default function RunProgressDounut({ statusCounts, statusMessages, theme return found ? found.count : 0; }); - const labels = testRunCaseStatus.map((entry) => statusMessages[entry.uid]); + const labels = testRunCaseStatus.map((entry) => testRunCaseStatusMessages[entry.uid]); const colors = testRunCaseStatus.map((entry) => entry.chartColor); const legend = { labels: { diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx index 88bdb52..7d8f0d6 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseSelector.tsx @@ -32,7 +32,7 @@ import { RunMessages } from '@/types/run'; import TestCaseDetailDialog from './TestCaseDetailDialog'; import { PriorityMessages } from '@/types/priority'; import TestCasePriority from '@/components/TestCasePriority'; -import { TestStatusMessages } from '@/types/testStatus'; +import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; type Props = { cases: CaseType[]; @@ -43,7 +43,7 @@ type Props = { onIncludeCase: (includeCaseId: number) => {}; onExcludeCase: (excludeCaseId: number) => {}; messages: RunMessages; - statusMessages: TestStatusMessages; + testRunCaseStatusMessages: TestRunCaseStatusMessages; priorityMessages: PriorityMessages; }; @@ -56,7 +56,7 @@ export default function TestCaseSelector({ onIncludeCase, onExcludeCase, messages, - statusMessages, + testRunCaseStatusMessages, priorityMessages, }: Props) { const headerColumns = [ @@ -160,7 +160,9 @@ export default function TestCaseSelector({ startContent={isIncluded && renderStatusIcon(testRunCaseStatus[runStatus].uid)} endContent={isIncluded && } > - {isIncluded && statusMessages[testRunCaseStatus[runStatus].uid]} + + {isIncluded && testRunCaseStatusMessages[testRunCaseStatus[runStatus].uid]} + @@ -170,7 +172,7 @@ export default function TestCaseSelector({ startContent={renderStatusIcon(runCaseStatus.uid)} onPress={() => onChangeStatus(testCase.id, index)} > - {statusMessages[runCaseStatus.uid]} + {testRunCaseStatusMessages[runCaseStatus.uid]} ))} diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx index efcd317..c53f855 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx @@ -2,7 +2,7 @@ import RunEditor from './RunEditor'; import { useTranslations } from 'next-intl'; import { RunMessages } from '@/types/run'; import { PriorityMessages } from '@/types/priority'; -import { TestStatusMessages } from '@/types/testStatus'; +import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; export default function Page({ params }: { params: { projectId: string; runId: string; locale: string } }) { const t = useTranslations('Run'); @@ -38,13 +38,13 @@ export default function Page({ params }: { params: { projectId: string; runId: s close: t('close'), }; - const st = useTranslations('Status'); - const statusMessages: TestStatusMessages = { - untested: st('untested'), - passed: st('passed'), - failed: st('failed'), - retest: st('retest'), - skipped: st('skipped'), + const rcst = useTranslations('RunCaseStatus'); + const testRunCaseStatusMessages: TestRunCaseStatusMessages = { + untested: rcst('untested'), + passed: rcst('passed'), + failed: rcst('failed'), + retest: rcst('retest'), + skipped: rcst('skipped'), }; const pt = useTranslations('Priority'); @@ -60,7 +60,7 @@ export default function Page({ params }: { params: { projectId: string; runId: s projectId={params.projectId} runId={params.runId} messages={messages} - statusMessages={statusMessages} + testRunCaseStatusMessages={testRunCaseStatusMessages} priorityMessages={priorityMessages} locale={params.locale} /> diff --git a/frontend/types/testRunCaseStatus.ts b/frontend/types/testRunCaseStatus.ts new file mode 100644 index 0000000..f370963 --- /dev/null +++ b/frontend/types/testRunCaseStatus.ts @@ -0,0 +1,18 @@ +// The status of each test case in test run +type TestRunCaseStatusUidType = 'untested' | 'passed' | 'failed' | 'retest' | 'skipped'; + +type TestRunCaseStatusType = { + uid: TestRunCaseStatusUidType; + color: string; + chartColor: string; +}; + +type TestRunCaseStatusMessages = { + untested: string; + passed: string; + failed: string; + retest: string; + skipped: string; +}; + +export type { TestRunCaseStatusUidType, TestRunCaseStatusType, TestRunCaseStatusMessages }; diff --git a/frontend/types/testStatus.ts b/frontend/types/testStatus.ts deleted file mode 100644 index bf7a247..0000000 --- a/frontend/types/testStatus.ts +++ /dev/null @@ -1,17 +0,0 @@ -type TestStatusUidType = 'untested' | 'passed' | 'failed' | 'retest' | 'skipped'; - -type TestStatusType = { - uid: TestStatusUidType; - color: string; - chartColor: string; -}; - -type TestStatusMessages = { - untested: string; - passed: string; - failed: string; - retest: string; - skipped: string; -}; - -export type { TestStatusUidType, TestStatusType, TestStatusMessages }; From 32ee0231b073f7e73fadfdf32d4ec15efdd4cfd1 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:46:06 +0900 Subject: [PATCH 08/14] refactor: test run status messages duplication --- frontend/config/selection.ts | 4 +- frontend/messages/en.json | 14 ++++--- frontend/messages/ja.json | 14 ++++--- .../projects/[projectId]/home/ProjectHome.tsx | 2 +- .../projects/[projectId]/home/aggregate.ts | 2 +- .../projects/[projectId]/home/page.tsx | 2 +- .../[projectId]/runs/[runId]/RunEditor.tsx | 6 ++- .../runs/[runId]/RunPregressDonutChart.tsx | 2 +- .../[projectId]/runs/[runId]/page.tsx | 19 +++++---- frontend/types/status.ts | 41 +++++++++++++++++++ frontend/types/testRunCaseStatus.ts | 18 -------- 11 files changed, 79 insertions(+), 45 deletions(-) create mode 100644 frontend/types/status.ts delete mode 100644 frontend/types/testRunCaseStatus.ts diff --git a/frontend/config/selection.ts b/frontend/config/selection.ts index 98bb76e..06c2b64 100644 --- a/frontend/config/selection.ts +++ b/frontend/config/selection.ts @@ -1,6 +1,6 @@ +import { RunStatusType, TestRunCaseStatusType } from '@/types/status'; import { TestTypeType } from '@/types/testType'; import { PriorityType } from '@/types/priority'; -import { TestRunCaseStatusType } from '@/types/testRunCaseStatus'; const roles = [{ uid: 'administrator' }, { uid: 'user' }]; @@ -14,7 +14,7 @@ const locales = [ ]; // The status of each test run -const testRunStatus = [ +const testRunStatus: RunStatusType[] = [ { uid: 'new' }, { uid: 'inProgress' }, { uid: 'underReview' }, diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 4aebf1f..dcb0910 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -1,4 +1,12 @@ { + "RunStatus": { + "new": "New", + "inProgress": "In progress", + "underReview": "Under review", + "rejected": "Rejected", + "done": "Done", + "closed": "Closed" + }, "RunCaseStatus": { "untested": "Untested", "passed": "Passed", @@ -234,12 +242,6 @@ "title": "Title", "please_enter": "Please enter run name", "description": "Description", - "new": "New", - "inProgress": "In progress", - "underReview": "Under review", - "rejected": "Rejected", - "done": "Done", - "closed": "Closed", "priority": "Priority", "status": "Status", "actions": "Actions", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index 37e11d2..a5c419a 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -1,4 +1,12 @@ { + "RunStatus": { + "new": "新規", + "inProgress": "進行中", + "underReview": "レビュー中", + "rejected": "却下", + "done": "完了", + "closed": "クローズ" + }, "RunCaseStatus": { "untested": "未実行", "passed": "成功", @@ -234,12 +242,6 @@ "id": "ID", "title": "タイトル", "description": "詳細", - "new": "新規", - "inProgress": "進行中", - "underReview": "レビュー中", - "rejected": "却下", - "done": "完了", - "closed": "クローズ", "please_enter": "タイトルを入力してください", "priority": "優先度", "status": "ステータス", diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx index 102b568..4f98ff6 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/ProjectHome.tsx @@ -13,7 +13,7 @@ import { useTheme } from 'next-themes'; import TestTypesChart from './TestTypesDonutChart'; import TestPriorityChart from './TestPriorityDonutChart'; import TestProgressBarChart from './TestProgressColumnChart'; -import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; +import { TestRunCaseStatusMessages } from '@/types/status'; import { TestTypeMessages } from '@/types/testType'; import { PriorityMessages } from '@/types/priority'; diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts index 474c168..41c7ffc 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts +++ b/frontend/src/app/[locale]/projects/[projectId]/home/aggregate.ts @@ -1,6 +1,6 @@ import { ProjectType } from '@/types/project'; import { testTypes, priorities, testRunCaseStatus } from '@/config/selection'; -import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; +import { TestRunCaseStatusMessages } from '@/types/status'; // aggregate folder, case, run mum function aggregateBasicInfo(project: ProjectType) { diff --git a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx index 895d758..dc862f8 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/home/page.tsx @@ -2,7 +2,7 @@ import { ProjectHome } from './ProjectHome'; import { useTranslations } from 'next-intl'; import { PriorityMessages } from '@/types/priority'; import { TestTypeMessages } from '@/types/testType'; -import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; +import { TestRunCaseStatusMessages } from '@/types/status'; export type HomeMessages = { folders: string; diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx index 320108c..7acdab7 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx @@ -38,7 +38,7 @@ import { TokenContext } from '@/utils/TokenProvider'; import { useTheme } from 'next-themes'; import { useFormGuard } from '@/utils/formGuard'; import { PriorityMessages } from '@/types/priority'; -import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; +import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status'; const defaultTestRun = { id: 0, @@ -55,6 +55,7 @@ type Props = { projectId: string; runId: string; messages: RunMessages; + runStatusMessages: RunStatusMessages; testRunCaseStatusMessages: TestRunCaseStatusMessages; priorityMessages: PriorityMessages; locale: string; @@ -64,6 +65,7 @@ export default function RunEditor({ projectId, runId, messages, + runStatusMessages, testRunCaseStatusMessages, priorityMessages, locale, @@ -261,7 +263,7 @@ export default function RunEditor({ > {testRunStatus.map((status, index) => ( - {messages[status.uid]} + {runStatusMessages[status.uid]} ))} diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx index 6c3f0a2..46109c8 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunPregressDonutChart.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react'; import dynamic from 'next/dynamic'; import { testRunCaseStatus } from '@/config/selection'; import { RunStatusCountType } from '@/types/run'; -import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; +import { TestRunCaseStatusMessages } from '@/types/status'; const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); type Props = { diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx index c53f855..408b68f 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/page.tsx @@ -2,7 +2,7 @@ import RunEditor from './RunEditor'; import { useTranslations } from 'next-intl'; import { RunMessages } from '@/types/run'; import { PriorityMessages } from '@/types/priority'; -import { TestRunCaseStatusMessages } from '@/types/testRunCaseStatus'; +import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status'; export default function Page({ params }: { params: { projectId: string; runId: string; locale: string } }) { const t = useTranslations('Run'); @@ -16,12 +16,6 @@ export default function Page({ params }: { params: { projectId: string; runId: s title: t('title'), pleaseEnter: t('please_enter'), description: t('description'), - new: t('new'), - inProgress: t('inProgress'), - underReview: t('underReview'), - rejected: t('rejected'), - done: t('done'), - closed: t('closed'), priority: t('priority'), actions: t('actions'), status: t('status'), @@ -38,6 +32,16 @@ export default function Page({ params }: { params: { projectId: string; runId: s close: t('close'), }; + const rst = useTranslations('RunStatus'); + const runStatusMessages: RunStatusMessages = { + new: rst('new'), + inProgress: rst('inProgress'), + underReview: rst('underReview'), + rejected: rst('rejected'), + done: rst('done'), + closed: rst('closed'), + }; + const rcst = useTranslations('RunCaseStatus'); const testRunCaseStatusMessages: TestRunCaseStatusMessages = { untested: rcst('untested'), @@ -60,6 +64,7 @@ export default function Page({ params }: { params: { projectId: string; runId: s projectId={params.projectId} runId={params.runId} messages={messages} + runStatusMessages={runStatusMessages} testRunCaseStatusMessages={testRunCaseStatusMessages} priorityMessages={priorityMessages} locale={params.locale} diff --git a/frontend/types/status.ts b/frontend/types/status.ts new file mode 100644 index 0000000..e498b10 --- /dev/null +++ b/frontend/types/status.ts @@ -0,0 +1,41 @@ +// The status of each test run +type RunStatusUidType = 'new' | 'inProgress' | 'underReview' | 'rejected' | 'done' | 'closed'; + +type RunStatusType = { + uid: RunStatusUidType; +}; + +type RunStatusMessages = { + new: string; + inProgress: string; + underReview: string; + rejected: string; + done: string; + closed: string; +}; + +// The status of each test case in test run +type TestRunCaseStatusUidType = 'untested' | 'passed' | 'failed' | 'retest' | 'skipped'; + +type TestRunCaseStatusType = { + uid: TestRunCaseStatusUidType; + color: string; + chartColor: string; +}; + +type TestRunCaseStatusMessages = { + untested: string; + passed: string; + failed: string; + retest: string; + skipped: string; +}; + +export type { + RunStatusUidType, + RunStatusType, + RunStatusMessages, + TestRunCaseStatusUidType, + TestRunCaseStatusType, + TestRunCaseStatusMessages, +}; diff --git a/frontend/types/testRunCaseStatus.ts b/frontend/types/testRunCaseStatus.ts deleted file mode 100644 index f370963..0000000 --- a/frontend/types/testRunCaseStatus.ts +++ /dev/null @@ -1,18 +0,0 @@ -// The status of each test case in test run -type TestRunCaseStatusUidType = 'untested' | 'passed' | 'failed' | 'retest' | 'skipped'; - -type TestRunCaseStatusType = { - uid: TestRunCaseStatusUidType; - color: string; - chartColor: string; -}; - -type TestRunCaseStatusMessages = { - untested: string; - passed: string; - failed: string; - retest: string; - skipped: string; -}; - -export type { TestRunCaseStatusUidType, TestRunCaseStatusType, TestRunCaseStatusMessages }; From f03222e49c3c24c4b9e709bdaca6fbd9255ffb9f Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 20:44:12 +0900 Subject: [PATCH 09/14] fix: Change jwt expiration time from 1h to 24h --- backend/routes/users/signin.js | 4 ++-- backend/routes/users/signup.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/routes/users/signin.js b/backend/routes/users/signin.js index 9f16026..3b740f4 100644 --- a/backend/routes/users/signin.js +++ b/backend/routes/users/signin.js @@ -27,9 +27,9 @@ module.exports = function (sequelize) { return res.status(401).json({ error: 'Authentication failed' }); } const accessToken = jwt.sign({ userId: user.id }, secretKey, { - expiresIn: '1h', + expiresIn: '24h', }); - const expiresAt = Date.now() + 3600 * 1000; // expire date(ms) + const expiresAt = Date.now() + 3600 * 1000 * 24; // expire date(ms) res.status(200).json({ access_token: accessToken, expires_at: expiresAt, user }); } catch (error) { diff --git a/backend/routes/users/signup.js b/backend/routes/users/signup.js index ee7ed6e..8398f29 100644 --- a/backend/routes/users/signup.js +++ b/backend/routes/users/signup.js @@ -29,9 +29,9 @@ module.exports = function (sequelize) { }); const accessToken = jwt.sign({ userId: user.id }, secretKey, { - expiresIn: '1h', + expiresIn: '24h', }); - const expiresAt = Date.now() + 3600 * 1000; // expire date(ms) + const expiresAt = Date.now() + 3600 * 1000 * 24; // expire date(ms) user.password = undefined; res.status(200).json({ access_token: accessToken, expires_at: expiresAt, user }); From 5f095e1cf339eebbda147a02a55aa413730fe864 Mon Sep 17 00:00:00 2001 From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com> Date: Sun, 21 Jul 2024 21:42:02 +0900 Subject: [PATCH 10/14] feat: test case detail dialog --- frontend/messages/en.json | 2 + frontend/messages/ja.json | 1 + .../[projectId]/runs/[runId]/RunEditor.tsx | 4 + .../runs/[runId]/TestCaseDetailDialog.tsx | 128 ++++++++++++++---- .../runs/[runId]/TestCaseSelector.tsx | 28 ++-- .../[projectId]/runs/[runId]/page.tsx | 21 +++ frontend/types/run.ts | 13 +- 7 files changed, 138 insertions(+), 59 deletions(-) diff --git a/frontend/messages/en.json b/frontend/messages/en.json index dcb0910..598c61b 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -252,6 +252,8 @@ "no_cases_found": "No cases found", "are_you_sure_leave": "Are you sure you want to leave the page?", "type": "Type", + "test_detail": "Test detail", + "steps": "Steps", "preconditions": "Preconditions", "expected_result": "Expected result", "details_of_the_step": "Details of the step", diff --git a/frontend/messages/ja.json b/frontend/messages/ja.json index a5c419a..9f4567e 100644 --- a/frontend/messages/ja.json +++ b/frontend/messages/ja.json @@ -254,6 +254,7 @@ "are_you_sure_leave": "ページを離れてもよろしいですか", "type": "タイプ", "test_detail": "テスト詳細", + "steps": "ステップ", "preconditions": "前提条件", "expected_result": "期待結果", "details_of_the_step": "ステップ詳細", diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx index 7acdab7..098bc4f 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/RunEditor.tsx @@ -39,6 +39,7 @@ import { useTheme } from 'next-themes'; import { useFormGuard } from '@/utils/formGuard'; import { PriorityMessages } from '@/types/priority'; import { RunStatusMessages, TestRunCaseStatusMessages } from '@/types/status'; +import { TestTypeMessages } from '@/types/testType'; const defaultTestRun = { id: 0, @@ -58,6 +59,7 @@ type Props = { runStatusMessages: RunStatusMessages; testRunCaseStatusMessages: TestRunCaseStatusMessages; priorityMessages: PriorityMessages; + testTypeMessages: TestTypeMessages; locale: string; }; @@ -68,6 +70,7 @@ export default function RunEditor({ runStatusMessages, testRunCaseStatusMessages, priorityMessages, + testTypeMessages, locale, }: Props) { const context = useContext(TokenContext); @@ -333,6 +336,7 @@ export default function RunEditor({ messages={messages} testRunCaseStatusMessages={testRunCaseStatusMessages} priorityMessages={priorityMessages} + testTypeMessages={testTypeMessages} /> diff --git a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx index e84553a..61ba36c 100644 --- a/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx +++ b/frontend/src/app/[locale]/projects/[projectId]/runs/[runId]/TestCaseDetailDialog.tsx @@ -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 { RunMessages } from '@/types/run'; -import { CaseType } from '@/types/case'; +import { CaseType, StepType } from '@/types/case'; import { PriorityMessages } from '@/types/priority'; import TestCasePriority from '@/components/TestCasePriority'; +import { TokenContext } from '@/utils/TokenProvider'; +import { fetchCase } from '@/utils/caseControl'; +import { TestTypeMessages } from '@/types/testType'; type Props = { isOpen: boolean; - testCase: CaseType; + caseId: number; onCancel: () => void; onChangeStatus: (changeCaseId: number, status: number) => {}; messages: RunMessages; + testTypeMessages: TestTypeMessages; 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, - testCase, + caseId, onCancel, onChangeStatus, messages, + testTypeMessages, priorityMessages, }: Props) { + const context = useContext(TokenContext); + const [testCase, setTestCase] = useState(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 ( { onCancel(); }} @@ -48,40 +101,55 @@ export default function showTestCaseDetailDialog({

{messages.type}

-
{messages[testTypes[testCase.type].uid]}
+
{testTypeMessages[testTypes[testCase.type].uid]}
{templates[testCase.template].uid === 'text' ? ( -
-
-

{messages.preconditions}

-
{testCase.preConditions}
+ <> +

{messages.testDetail}

+
+
+

{messages.preconditions}

+
{testCase.preConditions}
+
+
+

{messages.expectedResult}

+
{testCase.expectedResults}
+
- -
-

{messages.expectedResult}

-
{testCase.expectedResults}
-
-
+ ) : ( -
+ <> +

{messages.steps}

{testCase.Steps && - testCase.Steps.map((step, index) => ( - <> -
-

{messages.preconditions}

-
{step.step}
+ testCase.Steps.map((step) => ( +
+ +
+
+