feat(测试计划): 测试计划详情-接口用例&接口场景-执行

This commit is contained in:
teukkk 2024-06-12 15:07:58 +08:00 committed by Craftsman
parent d89b550c50
commit 39febe26dd
8 changed files with 139 additions and 9 deletions

View File

@ -12,6 +12,8 @@ import {
BatchDisassociateCaseUrl, BatchDisassociateCaseUrl,
BatchEditTestPlanUrl, BatchEditTestPlanUrl,
batchMovePlanUrl, batchMovePlanUrl,
BatchRunApiCaseUrl,
BatchRunApiScenarioUrl,
BatchRunCaseUrl, BatchRunCaseUrl,
BatchUpdateApiCaseExecutorUrl, BatchUpdateApiCaseExecutorUrl,
BatchUpdateApiScenarioExecutorUrl, BatchUpdateApiScenarioExecutorUrl,
@ -51,6 +53,8 @@ import {
planDetailBugPageUrl, planDetailBugPageUrl,
PlanDetailExecuteHistoryUrl, PlanDetailExecuteHistoryUrl,
planPassRateUrl, planPassRateUrl,
RunApiCaseUrl,
RunApiScenarioUrl,
RunFeatureCaseUrl, RunFeatureCaseUrl,
SortApiCaseUrl, SortApiCaseUrl,
SortApiScenarioUrl, SortApiScenarioUrl,
@ -296,6 +300,10 @@ export const sortApiCase = (data: SortApiCaseParams) => {
export function disassociateApiCase(data: DisassociateCaseParams) { export function disassociateApiCase(data: DisassociateCaseParams) {
return MSR.post({ url: DisassociateApiCaseUrl, data }); return MSR.post({ url: DisassociateApiCaseUrl, data });
} }
// 计划详情-接口用例列表-执行
export function runApiCase(id: string, reportId?: string) {
return MSR.get({ url: `${RunApiCaseUrl}/${id}`, params: reportId });
}
// 计划详情-接口用例列表-批量取消关联用例 // 计划详情-接口用例列表-批量取消关联用例
export function batchDisassociateApiCase(data: BatchApiCaseParams) { export function batchDisassociateApiCase(data: BatchApiCaseParams) {
return MSR.post({ url: BatchDisassociateApiCaseUrl, data }); return MSR.post({ url: BatchDisassociateApiCaseUrl, data });
@ -304,6 +312,10 @@ export function batchDisassociateApiCase(data: BatchApiCaseParams) {
export function batchUpdateApiCaseExecutor(data: BatchUpdateApiCaseExecutorParams) { export function batchUpdateApiCaseExecutor(data: BatchUpdateApiCaseExecutorParams) {
return MSR.post({ url: BatchUpdateApiCaseExecutorUrl, data }); return MSR.post({ url: BatchUpdateApiCaseExecutorUrl, data });
} }
// 计划详情-接口用例列表-批量执行
export function batchRunApiCase(data: BatchApiCaseParams) {
return MSR.post({ url: BatchRunApiCaseUrl, data });
}
// 计划详情-接口场景列表 // 计划详情-接口场景列表
export function getPlanDetailApiScenarioList(data: PlanDetailApiScenarioQueryParams) { export function getPlanDetailApiScenarioList(data: PlanDetailApiScenarioQueryParams) {
return MSR.post<CommonList<PlanDetailApiScenarioItem>>({ url: GetPlanDetailApiScenarioListUrl, data }); return MSR.post<CommonList<PlanDetailApiScenarioItem>>({ url: GetPlanDetailApiScenarioListUrl, data });
@ -320,6 +332,10 @@ export function getApiScenarioModuleCount(data: PlanDetailApiScenarioQueryParams
export const sortApiScenario = (data: SortApiCaseParams) => { export const sortApiScenario = (data: SortApiCaseParams) => {
return MSR.post({ url: SortApiScenarioUrl, data }); return MSR.post({ url: SortApiScenarioUrl, data });
}; };
// 计划详情-接口场景列表-执行
export function runApiScenario(id: string, reportId?: string) {
return MSR.get({ url: `${RunApiScenarioUrl}/${id}`, params: reportId });
}
// 计划详情-接口场景列表-取消关联用例 // 计划详情-接口场景列表-取消关联用例
export function disassociateApiScenario(data: DisassociateCaseParams) { export function disassociateApiScenario(data: DisassociateCaseParams) {
return MSR.post({ url: DisassociateApiScenarioUrl, data }); return MSR.post({ url: DisassociateApiScenarioUrl, data });
@ -332,6 +348,10 @@ export function batchDisassociateApiScenario(data: BatchApiCaseParams) {
export function batchUpdateApiScenarioExecutor(data: BatchUpdateApiCaseExecutorParams) { export function batchUpdateApiScenarioExecutor(data: BatchUpdateApiCaseExecutorParams) {
return MSR.post({ url: BatchUpdateApiScenarioExecutorUrl, data }); return MSR.post({ url: BatchUpdateApiScenarioExecutorUrl, data });
} }
// 计划详情-接口场景列表-批量执行
export function batchRunApiScenario(data: BatchApiCaseParams) {
return MSR.post({ url: BatchRunApiScenarioUrl, data });
}
// 计划详情-执行历史 TODO 联调 // 计划详情-执行历史 TODO 联调
export function getPlanDetailExecuteHistory(data: PlanDetailFeatureCaseListQueryParams) { export function getPlanDetailExecuteHistory(data: PlanDetailFeatureCaseListQueryParams) {
return MSR.post<CommonList<PlanDetailExecuteHistoryItem>>({ url: PlanDetailExecuteHistoryUrl, data }); return MSR.post<CommonList<PlanDetailExecuteHistoryItem>>({ url: PlanDetailExecuteHistoryUrl, data });

View File

@ -107,12 +107,16 @@ export const GetApiCaseModuleUrl = '/test-plan/api/case/tree';
export const GetApiCaseModuleCountUrl = '/test-plan/api/case/module/count'; export const GetApiCaseModuleCountUrl = '/test-plan/api/case/module/count';
// 计划详情-接口用例列表-拖拽排序 // 计划详情-接口用例列表-拖拽排序
export const SortApiCaseUrl = '/test-plan/api/case/sort'; export const SortApiCaseUrl = '/test-plan/api/case/sort';
// 计划详情-接口用例列表-执行
export const RunApiCaseUrl = '/test-plan/api/case/run';
// 计划详情-接口用例列表-取消关联用例 // 计划详情-接口用例列表-取消关联用例
export const DisassociateApiCaseUrl = '/test-plan/api/case/disassociate'; export const DisassociateApiCaseUrl = '/test-plan/api/case/disassociate';
// 计划详情-接口用例列表-批量取消关联用例 // 计划详情-接口用例列表-批量取消关联用例
export const BatchDisassociateApiCaseUrl = '/test-plan/api/case/batch/disassociate'; export const BatchDisassociateApiCaseUrl = '/test-plan/api/case/batch/disassociate';
// 计划详情-接口用例列表-批量更新执行人 // 计划详情-接口用例列表-批量更新执行人
export const BatchUpdateApiCaseExecutorUrl = '/test-plan/api/case/batch/update/executor'; export const BatchUpdateApiCaseExecutorUrl = '/test-plan/api/case/batch/update/executor';
// 计划详情-接口用例列表-批量执行
export const BatchRunApiCaseUrl = '/test-plan/api/case/batch/run';
// 计划详情-接口场景列表 // 计划详情-接口场景列表
export const GetPlanDetailApiScenarioListUrl = '/test-plan/api/scenario/page'; export const GetPlanDetailApiScenarioListUrl = '/test-plan/api/scenario/page';
@ -122,12 +126,16 @@ export const GetApiScenarioModuleUrl = '/test-plan/api/scenario/tree';
export const GetApiScenarioModuleCountUrl = '/test-plan/api/scenario/module/count'; export const GetApiScenarioModuleCountUrl = '/test-plan/api/scenario/module/count';
// 计划详情-接口场景列表-拖拽排序 // 计划详情-接口场景列表-拖拽排序
export const SortApiScenarioUrl = '/test-plan/api/scenario/sort'; export const SortApiScenarioUrl = '/test-plan/api/scenario/sort';
// 计划详情-接口场景列表-执行
export const RunApiScenarioUrl = '/test-plan/api/scenario/run';
// 计划详情-接口场景列表-取消关联用例 // 计划详情-接口场景列表-取消关联用例
export const DisassociateApiScenarioUrl = '/test-plan/api/scenario/disassociate'; export const DisassociateApiScenarioUrl = '/test-plan/api/scenario/disassociate';
// 计划详情-接口场景列表-批量取消关联用例 // 计划详情-接口场景列表-批量取消关联用例
export const BatchDisassociateApiScenarioUrl = '/test-plan/api/scenario/batch/disassociate'; export const BatchDisassociateApiScenarioUrl = '/test-plan/api/scenario/batch/disassociate';
// 计划详情-接口场景列表-批量更新执行人 // 计划详情-接口场景列表-批量更新执行人
export const BatchUpdateApiScenarioExecutorUrl = '/test-plan/api/scenario/batch/update/executor'; export const BatchUpdateApiScenarioExecutorUrl = '/test-plan/api/scenario/batch/update/executor';
// 计划详情-接口场景列表-批量执行
export const BatchRunApiScenarioUrl = '/test-plan/api/scenario/batch/run';
// 测试规划脑图 // 测试规划脑图
export const GetPlanMinderUrl = '/test-plan/mind/data'; export const GetPlanMinderUrl = '/test-plan/mind/data';

View File

@ -56,6 +56,7 @@ export default {
'common.operationFailed': 'Operation failed', 'common.operationFailed': 'Operation failed',
'common.removeSuccess': 'Remove success', 'common.removeSuccess': 'Remove success',
'common.removeFailed': 'Remove failed', 'common.removeFailed': 'Remove failed',
'common.executionSuccess': 'Execution success',
'common.admin': 'Admin', 'common.admin': 'Admin',
'common.revokeDelete': 'Revoke delete', 'common.revokeDelete': 'Revoke delete',
'common.revokeDeleteSuccess': 'Revoke delete success', 'common.revokeDeleteSuccess': 'Revoke delete success',

View File

@ -57,6 +57,7 @@ export default {
'common.operationFailed': '操作失败', 'common.operationFailed': '操作失败',
'common.removeSuccess': '移除成功', 'common.removeSuccess': '移除成功',
'common.removeFailed': '移除失败', 'common.removeFailed': '移除失败',
'common.executionSuccess': '执行成功',
'common.admin': '管理员', 'common.admin': '管理员',
'common.revokeDelete': '撤销删除', 'common.revokeDelete': '撤销删除',
'common.revokeDeleteSuccess': '已撤销删除', 'common.revokeDeleteSuccess': '已撤销删除',

View File

@ -287,6 +287,7 @@ export interface PlanDetailApiCaseItem {
executeUser: string; executeUser: string;
executeUserName: string; executeUserName: string;
priority: string; priority: string;
protocol: string;
path: string; path: string;
projectId: string; projectId: string;
projectName: string; projectName: string;

View File

@ -9,7 +9,7 @@
show-full-screen show-full-screen
> >
<template #tbutton> <template #tbutton>
<a-dropdown position="br" @select="shareHandler"> <a-dropdown v-if="!props.doNotShowShare" position="br" @select="shareHandler">
<MsButton <MsButton
v-permission="['PROJECT_API_REPORT:READ+SHARE']" v-permission="['PROJECT_API_REPORT:READ+SHARE']"
type="icon" type="icon"
@ -53,6 +53,7 @@
const props = defineProps<{ const props = defineProps<{
reportId: string; reportId: string;
isScenario?: boolean; isScenario?: boolean;
doNotShowShare?: boolean; //
}>(); }>();
const appStore = useAppStore(); const appStore = useAppStore();

View File

@ -23,6 +23,9 @@
@selected-change="handleTableSelect" @selected-change="handleTableSelect"
@filter-change="getModuleCount" @filter-change="getModuleCount"
> >
<template #protocol="{ record }">
<ApiMethodName :method="record.protocol" />
</template>
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL]="{ filterContent }"> <template #[FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL]="{ filterContent }">
<CaseLevel :case-level="filterContent.value" /> <CaseLevel :case-level="filterContent.value" />
</template> </template>
@ -46,7 +49,12 @@
<apiStatus :status="record.status" /> <apiStatus :status="record.status" />
</template> </template>
<template v-if="props.canEdit" #operation="{ record }"> <template v-if="props.canEdit" #operation="{ record }">
<MsButton v-permission="['PROJECT_TEST_PLAN:READ+EXECUTE']" type="text" class="!mr-0"> <MsButton
v-permission="['PROJECT_TEST_PLAN:READ+EXECUTE']"
type="text"
class="!mr-0"
@click="handleRun(record)"
>
{{ t('common.execute') }} {{ t('common.execute') }}
</MsButton> </MsButton>
<a-divider v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']" direction="vertical" :margin="8"></a-divider> <a-divider v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']" direction="vertical" :margin="8"></a-divider>
@ -64,7 +72,7 @@
</MsPopconfirm> </MsPopconfirm>
</template> </template>
</MsBaseTable> </MsBaseTable>
<ReportDrawer v-model:visible="reportVisible" :report-id="reportId" /> <CaseAndScenarioReportDrawer v-model:visible="reportVisible" :report-id="reportId" do-not-show-share />
<!-- 批量修改执行人 --> <!-- 批量修改执行人 -->
<BatchUpdateExecutorModal <BatchUpdateExecutorModal
v-model:visible="batchUpdateExecutorModalVisible" v-model:visible="batchUpdateExecutorModalVisible"
@ -93,15 +101,18 @@
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue'; import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
import ApiMethodName from '@/views/api-test/components/apiMethodName.vue';
import apiStatus from '@/views/api-test/components/apiStatus.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue';
import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue'; import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue';
import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue';
import { import {
batchDisassociateApiCase, batchDisassociateApiCase,
batchRunApiCase,
batchUpdateApiCaseExecutor, batchUpdateApiCaseExecutor,
disassociateApiCase, disassociateApiCase,
getPlanDetailApiCaseList, getPlanDetailApiCaseList,
runApiCase,
sortApiCase, sortApiCase,
} from '@/api/modules/test-plan/testPlan'; } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
@ -176,6 +187,13 @@
showTooltip: true, showTooltip: true,
columnSelectorDisabled: true, columnSelectorDisabled: true,
}, },
{
title: 'apiTestManagement.protocol',
dataIndex: 'protocol',
slotName: 'protocol',
width: 150,
showDrag: true,
},
{ {
title: 'case.caseLevel', title: 'case.caseLevel',
dataIndex: 'priority', dataIndex: 'priority',
@ -271,7 +289,7 @@
selectable: hasOperationPermission.value, selectable: hasOperationPermission.value,
}); });
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable( const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setLoading } = useTable(
getPlanDetailApiCaseList, getPlanDetailApiCaseList,
tableProps.value, tableProps.value,
(record) => { (record) => {
@ -455,6 +473,44 @@
} }
} }
//
async function handleRun(record: PlanDetailApiCaseItem) {
try {
setLoading(true);
await runApiCase(record.id);
Message.success(t('common.executionSuccess'));
resetSelectorAndCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
setLoading(false);
}
}
//
async function handleBatchRun() {
try {
setLoading(true);
const tableParams = await getTableParams(true);
await batchRunApiCase({
selectIds: tableSelected.value as string[],
selectAll: batchParams.value.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
...tableParams,
});
Message.success(t('common.executionSuccess'));
resetSelectorAndCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
setLoading(false);
}
}
// //
function handleBatchDisassociateCase() { function handleBatchDisassociateCase() {
openModal({ openModal({
@ -498,6 +554,7 @@
const tableParams = await getTableParams(true); const tableParams = await getTableParams(true);
switch (event.eventTag) { switch (event.eventTag) {
case 'execute': case 'execute':
handleBatchRun();
break; break;
case 'disassociate': case 'disassociate':
handleBatchDisassociateCase(); handleBatchDisassociateCase();

View File

@ -49,7 +49,7 @@
<apiStatus :status="record.status" /> <apiStatus :status="record.status" />
</template> </template>
<template v-if="props.canEdit" #operation="{ record }"> <template v-if="props.canEdit" #operation="{ record }">
<MsButton v-permission="['PROJECT_TEST_PLAN:READ+EXECUTE']" type="text" class="!mr-0"> <MsButton v-permission="['PROJECT_TEST_PLAN:READ+EXECUTE']" type="text" class="!mr-0" @click="handleRun">
{{ t('common.execute') }} {{ t('common.execute') }}
</MsButton> </MsButton>
<a-divider v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']" direction="vertical" :margin="8"></a-divider> <a-divider v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']" direction="vertical" :margin="8"></a-divider>
@ -67,7 +67,7 @@
</MsPopconfirm> </MsPopconfirm>
</template> </template>
</MsBaseTable> </MsBaseTable>
<ReportDrawer v-model:visible="reportVisible" :report-id="reportId" /> <CaseAndScenarioReportDrawer v-model:visible="reportVisible" :report-id="reportId" do-not-show-share />
<!-- 批量修改执行人 --> <!-- 批量修改执行人 -->
<BatchUpdateExecutorModal <BatchUpdateExecutorModal
v-model:visible="batchUpdateExecutorModalVisible" v-model:visible="batchUpdateExecutorModalVisible"
@ -97,14 +97,16 @@
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue'; import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
import apiStatus from '@/views/api-test/components/apiStatus.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue';
import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue'; import BatchUpdateExecutorModal from '@/views/test-plan/testPlan/components/batchUpdateExecutorModal.vue';
import ReportDrawer from '@/views/test-plan/testPlan/detail/reportDrawer.vue';
import { import {
batchDisassociateApiScenario, batchDisassociateApiScenario,
batchRunApiScenario,
batchUpdateApiScenarioExecutor, batchUpdateApiScenarioExecutor,
disassociateApiScenario, disassociateApiScenario,
getPlanDetailApiScenarioList, getPlanDetailApiScenarioList,
runApiScenario,
sortApiScenario, sortApiScenario,
} from '@/api/modules/test-plan/testPlan'; } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
@ -270,7 +272,7 @@
selectable: hasOperationPermission.value, selectable: hasOperationPermission.value,
}); });
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable( const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector, setLoading } = useTable(
getPlanDetailApiScenarioList, getPlanDetailApiScenarioList,
tableProps.value, tableProps.value,
(record) => { (record) => {
@ -456,6 +458,44 @@
} }
} }
//
async function handleRun(record: PlanDetailApiScenarioItem) {
try {
setLoading(true);
await runApiScenario(record.id);
Message.success(t('common.executionSuccess'));
resetSelectorAndCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
setLoading(false);
}
}
//
async function handleBatchRun() {
try {
setLoading(true);
const tableParams = await getTableParams(true);
await batchRunApiScenario({
selectIds: tableSelected.value as string[],
selectAll: batchParams.value.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
...tableParams,
});
Message.success(t('common.executionSuccess'));
resetSelectorAndCaseList();
emit('refresh');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
setLoading(false);
}
}
// //
function handleBatchDisassociateCase() { function handleBatchDisassociateCase() {
openModal({ openModal({
@ -499,6 +539,7 @@
const tableParams = await getTableParams(true); const tableParams = await getTableParams(true);
switch (event.eventTag) { switch (event.eventTag) {
case 'execute': case 'execute':
handleBatchRun();
break; break;
case 'disassociate': case 'disassociate':
handleBatchDisassociateCase(); handleBatchDisassociateCase();