feat(测试计划): 测试计划独立报告接口用例分析&接口场景分析&测试计划执行接口调整

This commit is contained in:
xinxin.wu 2024-06-13 18:29:42 +08:00 committed by 刘瑞斌
parent f1f48388c0
commit 5f36c2343e
12 changed files with 276 additions and 173 deletions

View File

@ -3,7 +3,12 @@ import * as reportUrl from '@/api/requrls/test-plan/report';
import type { GetShareId } from '@/models/apiTest/report';
import { CommonList, TableQueryParams } from '@/models/common';
import { FeatureCaseItem, ReportBugItem, UpdateReportDetailParams } from '@/models/testPlan/report';
import {
ApiOrScenarioCaseItem,
FeatureCaseItem,
ReportBugItem,
UpdateReportDetailParams,
} from '@/models/testPlan/report';
// 报告列表
export function reportList(data: TableQueryParams) {
@ -79,5 +84,21 @@ export function planGetShareHref(id: string) {
export function getShareValidity(id: string) {
return MSR.get({ url: `${reportUrl.GetShareValidityUrl}/${id}` });
}
// 测试计划-独立报告-接口用例
export function getApiPage(data: TableQueryParams) {
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportIndependentApiUrl, data });
}
// 测试计划-报告-获取分享链接时效
export function getScenarioPage(data: TableQueryParams) {
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportIndependentScenarioUrl, data });
}
// 测试计划-独立报告-接口用例
export function getShareApiPage(data: TableQueryParams) {
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportShareApiUrl, data });
}
// 测试计划-报告-获取分享链接时效
export function getShareScenarioPage(data: TableQueryParams) {
return MSR.post<CommonList<ApiOrScenarioCaseItem>>({ url: reportUrl.ReportShareScenarioUrl, data });
}
export default {};

View File

@ -15,6 +15,7 @@ import {
BatchDisassociateApiScenarioUrl,
BatchDisassociateCaseUrl,
BatchEditTestPlanUrl,
BatchExecutePlanUrl,
BatchMoveApiCaseUrl,
BatchMoveApiScenarioUrl,
BatchMoveFeatureCaseUrl,
@ -36,7 +37,7 @@ import {
dragPlanOnGroupUrl,
EditPlanMinderUrl,
ExecuteHistoryUrl,
ExecutePlanUrl,
ExecuteSinglePlanUrl,
followPlanUrl,
GenerateReportUrl,
GetApiCaseModuleCountUrl,
@ -90,6 +91,7 @@ import type {
AssociateCaseRequestType,
BatchApiCaseParams,
BatchExecuteFeatureCaseParams,
BatchExecutePlan,
BatchFeatureCaseParams,
BatchMoveApiCaseParams,
BatchUpdateApiCaseExecutorParams,
@ -423,9 +425,13 @@ export function dragPlanOnGroup(data: DragSortParams) {
export function configSchedule(data: CreateTask) {
return MSR.post({ url: ConfigScheduleUrl, data });
}
// 测试计划-计划&计划组-执行
export function executeSinglePlan(data: ExecutePlan) {
return MSR.post({ url: ExecuteSinglePlanUrl, data });
}
// 测试计划-计划&计划组-执行&批量执行
export function executePlanOrGroup(data: ExecutePlan) {
return MSR.post({ url: ExecutePlanUrl, data });
export function executePlanOrGroup(data: BatchExecutePlan) {
return MSR.post({ url: BatchExecutePlanUrl, data });
}
// 测试计划-计划&计划组-执行&批量执行
export function deleteScheduleTask(testPlanId: string) {

View File

@ -28,3 +28,11 @@ export const PlanGetShareHrefDetailUrl = '/test-plan/report/share/get';
export const GetShareValidityUrl = '/test-plan/report/share/get-share-time';
// 测试计划-报告-详情-富文本编辑器上传图片文件
export const EditorUploadFileUrl = '/test-plan/report/upload/md/file';
// 测试计划-独立报告-接口用例
export const ReportIndependentApiUrl = '/test-plan/report/detail/api/case/page';
// 测试计划-独立报告-场景用例
export const ReportIndependentScenarioUrl = '/test-plan/report/detail/scenario/case/page';
// 测试计划-独立报告-接口用例-分享
export const ReportShareApiUrl = '/test-plan/report/share/detail/api/case/page';
// 测试计划-独立报告-场景用例-分享
export const ReportShareScenarioUrl = '/test-plan/report/share/detail/scenario/case/page';

View File

@ -96,8 +96,10 @@ export const TestPlanGroupOptionsUrl = 'test-plan/group-list';
export const dragPlanOnGroupUrl = '/test-plan/sort';
// 测试计划-创建定时任务
export const ConfigScheduleUrl = '/test-plan/schedule-config';
// 测试计划-计划&计划组-执行
export const ExecuteSinglePlanUrl = '/test-plan-execute/single';
// 测试计划-计划&计划组-执行&批量执行
export const ExecutePlanUrl = '/test-plan-execute/start';
export const BatchExecutePlanUrl = '/test-plan-execute/batch';
// 测试计划-删除定时任务
export const DeleteScheduleTaskUrl = 'test-plan/schedule-config-delete';

View File

@ -128,4 +128,36 @@ export const statusConfig: StatusListType[] = [
},
];
export const commonConfig = {
tooltip: {
show: false,
trigger: 'item',
},
legend: {
show: false,
},
};
export const seriesConfig = {
name: '',
type: 'pie',
radius: ['62%', '80%'],
center: ['50%', '50%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center',
},
emphasis: {
label: {
show: false,
fontSize: 40,
fontWeight: 'bold',
},
},
labelLine: {
show: false,
},
};
export default {};

View File

@ -23,3 +23,15 @@ export interface UpdateReportDetailParams {
summary: string;
richTextTmpFileIds: string[];
}
export interface ApiOrScenarioCaseItem {
id: string;
num: number;
name: string;
moduleName: string;
priority: string;
executeResult: string;
executeUser: string;
bugCount: number;
reportId: string;
}

View File

@ -367,10 +367,15 @@ export interface CreateTask {
cron: string;
runConfig: { runMode: 'SERIAL' | 'PARALLEL' };
}
export interface ExecutePlan {
projectId: string;
executeIds: string[];
executeMode: RunModeType;
export interface BatchExecutePlan {
projectId?: string;
executeIds?: string[];
runMode: RunModeType;
executionSource: string;
}
export interface ExecutePlan extends BatchExecutePlan {
executeId: string;
}
export interface PlanMinderNodeData extends MinderJsonNodeData {

View File

@ -131,7 +131,7 @@
<TabTestPlan :case-id="detail.id" />
</template>
<template v-if="activeTab === 'comments'">
<TabComment ref="commentRef" :case-id="detail.id" />
<TabComment ref="commentRef" :case-id="detail.id" :comment-value="detail.commentList" />
</template>
<template v-if="activeTab === 'changeHistory'">
<TabChangeHistory :case-id="detail.id" />

View File

@ -62,6 +62,7 @@
const props = defineProps<{
caseId: string;
commentValue: { id: string; name: string }[];
}>();
const activeComment = ref('caseComment');
@ -191,14 +192,6 @@
}
}
);
// watch(
// () => activeTab.value,
// (val) => {
// if (val === 'comments') {
// getAllCommentList();
// }
// }
// );
async function handleUploadImage(file: File) {
const { data } = await editorUploadFile({
@ -223,6 +216,10 @@
defineExpose({
getAllCommentList,
});
onBeforeMount(() => {
activeComment.value = props.commentValue.find((item) => Number(item.name) > 0)?.id || 'caseComment';
});
</script>
<style scoped lang="less">

View File

@ -1,10 +1,10 @@
<template>
<MsBaseTable v-bind="propsRes" v-on="propsEvent">
<template #num="{ record }">
<MsButton type="text">{{ record.num }}</MsButton>
<MsButton type="text" @click="showReport(record)">{{ record.num }}</MsButton>
</template>
<template #[FilterSlotNameEnum.CASE_MANAGEMENT_CASE_LEVEL]="{ filterContent }">
<CaseLevel :case-level="filterContent.value" />
<caseLevel :case-level="filterContent.value" />
</template>
<template #caseLevel="{ record }">
<CaseLevel :case-level="record.caseLevel" />
@ -14,43 +14,43 @@
</template>
<template #lastExecResult="{ record }">
<ExecuteResult :execute-result="record.lastExecResult" />
<MsIcon
<!-- TOTO 暂时不上 -->
<!-- <MsIcon
v-show="record.lastExecResult !== LastExecuteResults.PENDING"
type="icon-icon_take-action_outlined"
class="ml-[8px] cursor-pointer text-[rgb(var(--primary-5))]"
size="16"
@click="showReport(record)"
/>
/> -->
</template>
</MsBaseTable>
<CaseAndScenarioReportDrawer v-model:visible="reportVisible" :report-id="apiReportId" do-not-show-share />
</template>
<script setup lang="ts">
import { onBeforeMount } from 'vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
import CaseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
import { getReportBugList, getReportShareBugList } from '@/api/modules/test-plan/report';
import { getPlanDetailApiCaseList } from '@/api/modules/test-plan/testPlan';
import { useTableStore } from '@/store';
import { getApiPage, getShareApiPage } from '@/api/modules/test-plan/report';
import type { PlanDetailApiScenarioItem } from '@/models/testPlan/testPlan';
import { ApiOrScenarioCaseItem } from '@/models/testPlan/report';
import { LastExecuteResults } from '@/enums/caseEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { casePriorityOptions } from '@/views/api-test/components/config';
import { executionResultMap, getCaseLevels } from '@/views/case-management/caseManagementFeature/components/utils';
import { executionResultMap } from '@/views/case-management/caseManagementFeature/components/utils';
const props = defineProps<{
reportId: string;
shareId?: string;
}>();
const tableStore = useTableStore();
const columns: MsTableColumn = [
{
title: 'ID',
@ -68,7 +68,7 @@
},
{
title: 'report.detail.level',
dataIndex: 'caseLevel',
dataIndex: 'priority',
slotName: 'caseLevel',
filterConfig: {
options: casePriorityOptions,
@ -92,7 +92,7 @@
},
{
title: 'common.belongModule',
dataIndex: 'moduleId',
dataIndex: 'moduleName',
showTooltip: true,
width: 200,
showDrag: true,
@ -107,14 +107,7 @@
},
{
title: 'testPlan.featureCase.executor',
dataIndex: 'executeUserName',
showTooltip: true,
width: 130,
showDrag: true,
},
{
title: 'testPlan.featureCase.executor',
dataIndex: 'executeUserName',
dataIndex: 'executeUser',
showTooltip: true,
width: 130,
showDrag: true,
@ -127,15 +120,24 @@
showDrag: true,
},
];
const reportBugList = () => {
return !props.shareId ? getPlanDetailApiCaseList : getReportShareBugList;
const reportApiList = () => {
return !props.shareId ? getShareApiPage : getApiPage;
};
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getPlanDetailApiCaseList, {
scroll: { x: '100%' },
columns,
tableKey: TableKeyEnum.TEST_PLAN_REPORT_DETAIL_BUG,
showSelectorAll: false,
});
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
reportApiList(),
{
scroll: { x: '100%' },
columns,
tableKey: TableKeyEnum.TEST_PLAN_REPORT_DETAIL_BUG,
showSelectorAll: false,
},
(record) => {
return {
...record,
lastExecResult: record.executeResult ?? LastExecuteResults.PENDING,
};
}
);
async function loadCaseList() {
setLoadListParams({ reportId: props.reportId, shareId: props.shareId ?? undefined });
@ -151,12 +153,10 @@
//
const reportVisible = ref(false);
const apiReportId = ref('');
const apiReportId = ref<string>('');
function showReport(record: PlanDetailApiScenarioItem) {
function showReport(record: ApiOrScenarioCaseItem) {
reportVisible.value = true;
apiReportId.value = record.lastExecReportId;
apiReportId.value = record.reportId;
}
await tableStore.initColumn(TableKeyEnum.TEST_PLAN_REPORT_DETAIL_BUG, columns, 'drawer');
</script>

View File

@ -14,7 +14,7 @@
<SetReportChart
size="160px"
:legend-data="legendData"
:options="charOptions"
:options="executeCharOptions"
:request-total="getIndicators(detail.caseTotal) || 0"
/>
</div>
@ -66,18 +66,18 @@
<div class="text-[12px] !text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
<a-popover position="bottom" content-class="response-popover-content">
<div class="flex justify-center text-[18px] font-medium">
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ functionCasePassRate }} </div>
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ apiCasePassRate }} </div>
</div>
<template #content>
<div class="min-w-[95px] max-w-[400px] p-4 text-[14px]">
<div class="text-[12px] font-medium text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ functionCasePassRate }}</div>
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ apiCasePassRate }}</div>
</div>
</template>
</a-popover>
</div>
<div class="flex h-full w-full min-w-[150px] items-center justify-center">
<MsChart width="150px" height="150px" :options="functionCaseOptions"
<MsChart width="150px" height="150px" :options="apiCaseOptions"
/></div>
</div>
</div>
@ -96,18 +96,18 @@
<div class="text-[12px] !text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
<a-popover position="bottom" content-class="response-popover-content">
<div class="flex justify-center text-[18px] font-medium">
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ functionCasePassRate }} </div>
<div class="one-line-text max-w-[80px] text-[var(--color-text-1)]">{{ scenarioCasePassRate }} </div>
</div>
<template #content>
<div class="min-w-[95px] max-w-[400px] p-4 text-[14px]">
<div class="text-[12px] font-medium text-[var(--color-text-4)]">{{ t('report.passRate') }}</div>
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ functionCasePassRate }}</div>
<div class="mt-2 text-[18px] font-medium text-[var(--color-text-1)]">{{ scenarioCasePassRate }}</div>
</div>
</template>
</a-popover>
</div>
<div class="flex h-full w-full min-w-[150px] items-center justify-center">
<MsChart width="150px" height="150px" :options="functionCaseOptions"
<MsChart width="150px" height="150px" :options="scenarioCaseOptions"
/></div>
</div>
</div>
@ -157,7 +157,7 @@
import Summary from '@/views/test-plan/report/detail/component/summary.vue';
import { updateReportDetail } from '@/api/modules/test-plan/report';
import { defaultReportDetail, statusConfig } from '@/config/testPlan';
import { commonConfig, defaultCount, defaultReportDetail, seriesConfig, statusConfig } from '@/config/testPlan';
import { useI18n } from '@/hooks/useI18n';
import { addCommasToNumber } from '@/utils';
@ -196,34 +196,11 @@
const legendData = ref<LegendData[]>([]);
const charOptions = ref({
tooltip: {
show: false,
trigger: 'item',
},
legend: {
show: false,
},
//
const executeCharOptions = ref({
...commonConfig,
series: {
name: '',
type: 'pie',
radius: ['62%', '80%'],
center: ['50%', '50%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center',
},
emphasis: {
label: {
show: false,
fontSize: 40,
fontWeight: 'bold',
},
},
labelLine: {
show: false,
},
...seriesConfig,
data: [
{
value: 0,
@ -264,33 +241,43 @@
},
});
//
const functionCaseOptions = ref({
tooltip: {
show: false,
trigger: 'item',
},
legend: {
show: false,
},
...commonConfig,
series: {
name: '',
type: 'pie',
radius: ['62%', '80%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center',
},
emphasis: {
label: {
show: false,
fontSize: 40,
fontWeight: 'bold',
...seriesConfig,
data: [
{
value: 0,
name: t('common.success'),
itemStyle: {
color: '#00C261',
},
},
},
labelLine: {
show: false,
},
],
},
});
//
const apiCaseOptions = ref({
...commonConfig,
series: {
...seriesConfig,
data: [
{
value: 0,
name: t('common.success'),
itemStyle: {
color: '#00C261',
},
},
],
},
});
//
const scenarioCaseOptions = ref({
...commonConfig,
series: {
...seriesConfig,
data: [
{
value: 0,
@ -303,9 +290,9 @@
},
});
//
function initOptionsData() {
charOptions.value.series.data = statusConfig.map((item: StatusListType) => {
//
function initExecuteOptions() {
executeCharOptions.value.series.data = statusConfig.map((item: StatusListType) => {
return {
value: detail.value.executeCount[item.value] || 0,
name: t(item.label),
@ -325,15 +312,17 @@
rote: `${Number.isNaN(rate) ? 0 : rate.toFixed(2)}%`,
};
}) as unknown as LegendData[];
}
//
function getPassRateData(caseDetailCount: countDetail) {
const caseCountDetail = caseDetailCount || defaultCount;
const passRateData = statusConfig.filter((item) => ['success'].includes(item.value));
const { functionalCount } = detail.value;
const { success } = functionalCount;
const { success } = caseCountDetail;
const valueList = success ? statusConfig : passRateData;
functionCaseOptions.value.series.data = valueList.map((item: StatusListType) => {
return valueList.map((item: StatusListType) => {
return {
value: detail.value.functionalCount[item.value] || 0,
value: caseCountDetail[item.value] || 0,
name: t(item.label),
itemStyle: {
color: success ? item.color : '#D4D4D8',
@ -344,6 +333,15 @@
});
}
//
function initOptionsData() {
initExecuteOptions();
const { functionalCount, apiCaseCount, apiScenarioCount } = detail.value;
functionCaseOptions.value.series.data = getPassRateData(functionalCount);
apiCaseOptions.value.series.data = getPassRateData(apiCaseCount);
scenarioCaseOptions.value.series.data = getPassRateData(apiScenarioCount);
}
async function handleUpdateReportDetail() {
try {
await updateReportDetail({
@ -387,11 +385,51 @@
},
]);
function getSummaryDetail(detailCount: countDetail) {
if (detailCount) {
const { success, error, fakeError, pending, block } = detailCount;
//
const hasExecutedCase = success + error + fakeError + block;
//
const caseTotal = hasExecutedCase + pending;
//
const executedCount = (hasExecutedCase / caseTotal) * 100;
const apiExecutedRate = `${Number.isNaN(executedCount) ? 0 : executedCount.toFixed(2)}%`;
//
const successCount = (success / caseTotal) * 100;
const successRate = `${Number.isNaN(successCount) ? 0 : successCount.toFixed(2)}%`;
return {
hasExecutedCase,
caseTotal,
apiExecutedRate,
successRate,
pending,
success,
};
}
return {
hasExecutedCase: 0,
caseTotal: 0,
apiExecutedRate: 0,
successRate: 0,
pending: 0,
success: 0,
};
}
const functionCasePassRate = computed(() => {
const { functionalCount } = detail.value;
const { success, error, pending, block } = functionalCount;
const successRate = (success / (success + error + pending + block)) * 100;
return `${Number.isNaN(successRate) ? 0 : successRate.toFixed(2)}%`;
const apiCaseDetail = getSummaryDetail(detail.value.functionalCount || defaultCount);
return apiCaseDetail.successRate;
});
const apiCasePassRate = computed(() => {
const apiCaseDetail = getSummaryDetail(detail.value.apiCaseCount || defaultCount);
return apiCaseDetail.successRate;
});
const scenarioCasePassRate = computed(() => {
const apiScenarioDetail = getSummaryDetail(detail.value.apiScenarioCount || defaultCount);
return apiScenarioDetail.successRate;
});
const activeTab = ref('bug');
@ -431,38 +469,6 @@
});
});
function getSummaryDetail(detailCount: countDetail) {
if (detailCount) {
const { success, error, fakeError, pending, block } = detailCount;
//
const hasExecutedCase = success + error + fakeError + block;
//
const caseTotal = hasExecutedCase + pending;
//
const executedCount = (hasExecutedCase / caseTotal) * 100;
const apiExecutedRate = `${Number.isNaN(executedCount) ? 0 : executedCount.toFixed(2)}%`;
//
const successCount = (success / caseTotal) * 100;
const successRate = `${Number.isNaN(successCount) ? 0 : successCount.toFixed(2)}%`;
return {
hasExecutedCase,
caseTotal,
apiExecutedRate,
successRate,
pending,
success,
};
}
return {
hasExecutedCase: 0,
caseTotal: 0,
apiExecutedRate: 0,
successRate: 0,
pending: 0,
success: 0,
};
}
const summaryContent = computed(() => {
const { functionalCount, apiCaseCount, apiScenarioCount } = detail.value;
const functionalCaseDetail = getSummaryDetail(functionalCount);

View File

@ -288,7 +288,7 @@
<template #title>
{{ t('testPlan.testPlanIndex.batchExecution') }}
</template>
<a-radio-group v-model="executeForm.executeMode">
<a-radio-group v-model="executeForm.runMode">
<a-radio value="SERIAL">{{ t('testPlan.testPlanIndex.serial') }}</a-radio>
<a-radio value="PARALLEL">{{ t('testPlan.testPlanIndex.parallel') }}</a-radio>
</a-radio-group>
@ -373,6 +373,7 @@
deleteScheduleTask,
dragPlanOnGroup,
executePlanOrGroup,
executeSinglePlan,
getPlanPassRate,
getTestPlanDetail,
getTestPlanList,
@ -389,6 +390,7 @@
import { DragSortParams, ModuleTreeNode, TableQueryParams } from '@/models/common';
import type {
AddTestPlanParams,
BatchExecutePlan,
BatchMoveParams,
CreateTask,
ExecutePlan,
@ -431,13 +433,14 @@
const hasOperationPermission = computed(() =>
hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE', 'PROJECT_TEST_PLAN:READ+EXECUTE', 'PROJECT_TEST_PLAN:READ+ADD'])
);
const showType = ref<keyof typeof testPlanTypeEnum>(testPlanTypeEnum.ALL);
const columns: MsTableColumn = [
{
title: 'testPlan.testPlanIndex.ID',
slotName: 'num',
dataIndex: 'num',
width: 150,
width: 180,
showInTable: true,
showDrag: false,
showTooltip: true,
@ -581,8 +584,6 @@
}
}
const showType = ref<keyof typeof testPlanTypeEnum>(testPlanTypeEnum.ALL);
//
function hasIndent(record: TestPlanItem) {
return (showType.value === 'ALL' || showType.value === 'GROUP') &&
@ -873,19 +874,18 @@
/**
* 批量执行
*/
const initExecuteForm: ExecutePlan = {
const initExecuteForm: BatchExecutePlan = {
projectId: appStore.currentProjectId,
executeIds: [],
executeMode: 'SERIAL',
runMode: 'SERIAL',
executionSource: 'JENKINS',
};
const executeForm = ref<ExecutePlan>(cloneDeep(initExecuteForm));
const executeForm = ref<BatchExecutePlan>(cloneDeep(initExecuteForm));
const executeVisible = ref<boolean>(false);
function handleExecute(isBatch: boolean) {
if (isBatch) {
executeForm.value.executeIds = batchParams.value.selectedIds || [];
}
function handleExecute() {
executeForm.value.executeIds = batchParams.value.selectedIds || [];
executeVisible.value = true;
}
@ -915,13 +915,27 @@
}
}
async function singleExecute(id: string) {
try {
const params: ExecutePlan = {
executeId: id,
runMode: 'SERIAL',
executionSource: 'JENKINS',
};
await executeSinglePlan(params);
Message.success(t('case.detail.execute.success'));
fetchData();
} catch (error) {
console.log(error);
}
}
//
function executePlan(record: TestPlanItem) {
const { type, id } = record;
if (type === testPlanTypeEnum.GROUP) {
handleExecute(false);
executeForm.value.executeIds = [id];
singleExecute(record.id);
return;
}
if (type === testPlanTypeEnum.TEST_PLAN) {
@ -936,8 +950,7 @@
},
});
} else {
executeForm.value.executeIds = [id];
executeHandler();
singleExecute(record.id);
}
}
}
@ -1019,6 +1032,7 @@
},
type: showType.value,
scheduleOpen: enable,
editColumn: 'SCHEDULE',
};
await batchEditTestPlan(params);
Message.success(
@ -1143,7 +1157,7 @@
batchParams.value = params;
switch (event.eventTag) {
case 'execute':
handleExecute(true);
handleExecute();
break;
case 'copy':
handleCopyOrMove('copy');