feat(接口场景): 场景执行优化&部分问题修复

This commit is contained in:
baiqi 2024-03-27 14:52:24 +08:00 committed by Craftsman
parent f195c3595b
commit 0be3be4a28
12 changed files with 73 additions and 44 deletions

View File

@ -149,7 +149,7 @@
import { ExecuteAssertionConfig } from '@/models/apiTest/common'; import { ExecuteAssertionConfig } from '@/models/apiTest/common';
import { ResponseAssertionType, ResponseBodyAssertionType } from '@/enums/apiEnum'; import { ResponseAssertionType, ResponseBodyAssertionType } from '@/enums/apiEnum';
import { ExecuteAssertion, MsAssertionItem } from './type'; import { MsAssertionItem } from './type';
defineOptions({ defineOptions({
name: 'MsAssertion', name: 'MsAssertion',

View File

@ -247,6 +247,7 @@ export enum ScenarioExecuteStatus {
EXECUTING = 'EXECUTING', EXECUTING = 'EXECUTING',
FAILED = 'FAILED', FAILED = 'FAILED',
STOP = 'STOP', STOP = 'STOP',
UN_EXECUTE = 'UN_EXECUTE',
} }
// 场景步骤类型 // 场景步骤类型
export enum ScenarioStepType { export enum ScenarioStepType {

View File

@ -43,23 +43,6 @@ export interface ApiScenarioGetModuleParams {
refId?: string; refId?: string;
} }
// 场景修改参数
export interface ApiScenarioUpdateDTO {
id: string | number;
name?: string;
priority?: string;
status?: ApiScenarioStatus;
moduleId?: string | number;
description?: string;
tags?: string[];
grouped?: boolean;
environmentId?: string;
uploadFileIds?: string[];
linkFileIds?: string[];
deleteFileIds?: string[];
unLinkFileIds?: string[];
}
// 场景详情 // 场景详情
export interface ApiScenarioTableItem { export interface ApiScenarioTableItem {
id: string; id: string;
@ -408,3 +391,19 @@ export interface ApiScenarioDebugRequest {
linkFileIds: string[]; linkFileIds: string[];
frontendDebug?: boolean; frontendDebug?: boolean;
} }
// 场景修改参数
export interface ApiScenarioUpdateDTO extends Partial<Scenario> {
id: string | number;
name?: string;
status?: ApiScenarioStatus;
moduleId?: string | number;
description?: string;
tags?: string[];
grouped?: boolean;
environmentId?: string;
uploadFileIds?: string[];
linkFileIds?: string[];
deleteFileIds?: string[];
unLinkFileIds?: string[];
}

View File

@ -217,7 +217,7 @@
<postcondition <postcondition
v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION" v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION"
v-model:config="requestVModel.children[0].postProcessorConfig" v-model:config="requestVModel.children[0].postProcessorConfig"
:response="requestVModel.response?.requestResults[0]?.responseResult.body" :response="props.stepResponses?.[requestVModel.stepId].responseResult.body"
:layout="activeLayout" :layout="activeLayout"
:disabled="!isEditableApi" :disabled="!isEditableApi"
:second-box-height="secondBoxHeight" :second-box-height="secondBoxHeight"
@ -227,6 +227,7 @@
<assertion <assertion
v-else-if="requestVModel.activeTab === RequestComposition.ASSERTION" v-else-if="requestVModel.activeTab === RequestComposition.ASSERTION"
v-model:params="requestVModel.children[0].assertionConfig.assertions" v-model:params="requestVModel.children[0].assertionConfig.assertions"
:response="props.stepResponses?.[requestVModel.stepId].responseResult.body"
is-definition is-definition
:disabled="!isEditableApi" :disabled="!isEditableApi"
:assertion-config="requestVModel.children[0].assertionConfig" :assertion-config="requestVModel.children[0].assertionConfig"

View File

@ -362,7 +362,7 @@
...props.request, ...props.request,
response: { response: {
requestResults: [props.stepResponses?.[props.request?.stepId] || defaultResponse.requestResults[0]], requestResults: [props.stepResponses?.[props.request?.stepId] || defaultResponse.requestResults[0]],
console: props.stepResponses?.[props.request?.stepId].console || '', console: props.stepResponses?.[props.request?.stepId]?.console || '',
}, },
}; };
if (isQuote.value || isCopyNeedInit.value) { if (isQuote.value || isCopyNeedInit.value) {

View File

@ -1,5 +1,5 @@
<template> <template>
<MsTag :self-style="status.style" :size="props.size"> {{ status.text }}</MsTag> <MsTag v-if="status" :self-style="status.style" :size="props.size"> {{ status.text }}</MsTag>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -10,7 +10,7 @@
import { ScenarioExecuteStatus } from '@/enums/apiEnum'; import { ScenarioExecuteStatus } from '@/enums/apiEnum';
const props = defineProps<{ const props = defineProps<{
status: ScenarioExecuteStatus; status?: ScenarioExecuteStatus;
size?: Size; size?: Size;
}>(); }>();
@ -37,16 +37,23 @@
color: 'rgb(var(--success-6))', color: 'rgb(var(--success-6))',
text: 'common.success', text: 'common.success',
}, },
[ScenarioExecuteStatus.UN_EXECUTE]: {
bgColor: 'var(--color-text-4)',
color: 'var(--color-text-n9)',
text: 'apiScenario.unExecute',
},
}; };
const status = computed(() => { const status = computed(() => {
const config = statusMap[props.status]; if (props.status) {
return { const config = statusMap[props.status];
style: { return {
backgroundColor: config?.bgColor, style: {
color: config?.color, backgroundColor: config?.bgColor,
}, color: config?.color,
text: t(config?.text), },
}; text: t(config?.text),
};
}
}); });
</script> </script>

View File

@ -16,7 +16,7 @@ export const defaultLoopController = {
variable: '', // 变量名 variable: '', // 变量名
}, },
msCountController: { msCountController: {
loops: 0, // 循环次数 loops: 1, // 循环次数
loopTime: 0, // 循环间隔时间 loopTime: 0, // 循环间隔时间
}, },
whileController: { whileController: {

View File

@ -10,7 +10,7 @@
/> />
<a-tooltip <a-tooltip
v-if="innerData.loopType === ScenarioStepLoopTypeEnum.LOOP_COUNT" v-if="innerData.loopType === ScenarioStepLoopTypeEnum.LOOP_COUNT"
:content="innerData.msCountController.loops.toString()" :content="innerData.msCountController.loops?.toString()"
:disabled="!innerData.msCountController.loops" :disabled="!innerData.msCountController.loops"
> >
<a-input-number <a-input-number
@ -18,7 +18,7 @@
class="w-[80px] px-[8px]" class="w-[80px] px-[8px]"
size="mini" size="mini"
:step="1" :step="1"
:min="0" :min="1"
hide-button hide-button
:precision="0" :precision="0"
model-event="input" model-event="input"
@ -118,7 +118,10 @@
> >
</a-input> </a-input>
</a-tooltip> </a-tooltip>
<a-tooltip :content="innerData.whileController.timeout.toString()" :disabled="!innerData.whileController.timeout"> <a-tooltip
:content="innerData.whileController.timeout?.toString()"
:disabled="!innerData.whileController.timeout"
>
<a-input-number <a-input-number
v-model:model-value="innerData.whileController.timeout" v-model:model-value="innerData.whileController.timeout"
class="w-[100px] px-[8px]" class="w-[100px] px-[8px]"
@ -138,7 +141,7 @@
</template> </template>
<a-tooltip <a-tooltip
v-if="innerData.loopType !== ScenarioStepLoopTypeEnum.WHILE" v-if="innerData.loopType !== ScenarioStepLoopTypeEnum.WHILE"
:content="innerData.forEachController.loopTime.toString()" :content="innerData.forEachController.loopTime?.toString()"
:disabled="!innerData.forEachController.loopTime" :disabled="!innerData.forEachController.loopTime"
> >
<a-input-number <a-input-number

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="flex items-center gap-[4px]" draggable="false"> <div class="flex items-center gap-[4px]" draggable="false">
<a-tooltip :content="innerData.delay.toString()" :disabled="!innerData.delay"> <a-tooltip :content="innerData.delay?.toString()" :disabled="!innerData.delay">
<a-input-number <a-input-number
v-model:model-value="innerData.delay" v-model:model-value="innerData.delay"
class="max-w-[500px] px-[8px]" class="max-w-[500px] px-[8px]"

View File

@ -177,13 +177,15 @@
</template> </template>
<template #extraEnd="step"> <template #extraEnd="step">
<a-popover <a-popover
v-if="step.executeStatus && checkStepIsApi(step)" v-if="
getExecuteStatus(step) === ScenarioExecuteStatus.SUCCESS ||
getExecuteStatus(step) === ScenarioExecuteStatus.FAILED
"
position="br" position="br"
content-class="scenario-step-response-popover" content-class="scenario-step-response-popover"
:disabled="![ScenarioExecuteStatus.SUCCESS, ScenarioExecuteStatus.FAILED].includes(step.executeStatus)"
@popup-visible-change="handleResponsePopoverVisibleChange($event, step)" @popup-visible-change="handleResponsePopoverVisibleChange($event, step)"
> >
<executeStatus :status="getExecuteStatus(step) || step.executeStatus" size="small" /> <executeStatus :status="getExecuteStatus(step)" size="small" />
<template #content> <template #content>
<responseResult <responseResult
:active-tab="ResponseComposition.BODY" :active-tab="ResponseComposition.BODY"
@ -204,11 +206,7 @@
</responseResult> </responseResult>
</template> </template>
</a-popover> </a-popover>
<executeStatus <executeStatus v-else-if="step.executeStatus" :status="getExecuteStatus(step)" size="small" />
v-else-if="step.executeStatus"
:status="getExecuteStatus(step) || step.executeStatus"
size="small"
/>
</template> </template>
<template v-if="steps.length === 0 && stepKeyword.trim() !== ''" #empty> <template v-if="steps.length === 0 && stepKeyword.trim() !== ''" #empty>
<div <div
@ -793,6 +791,12 @@
scenarioConfig: scenario.value.scenarioConfig, scenarioConfig: scenario.value.scenarioConfig,
frontendDebug: executeType === 'localExec', frontendDebug: executeType === 'localExec',
...executeParams, ...executeParams,
steps: mapTree(executeParams.steps, (node) => {
return {
...node,
parent: null, // axios
};
}),
}); });
if (executeType === 'localExec' && localExecuteUrl) { if (executeType === 'localExec' && localExecuteUrl) {
await localExecuteApiDebug(localExecuteUrl, res); await localExecuteApiDebug(localExecuteUrl, res);

View File

@ -223,6 +223,12 @@
if (activeScenarioTab.value.isNew) { if (activeScenarioTab.value.isNew) {
const res = await addScenario({ const res = await addScenario({
...activeScenarioTab.value, ...activeScenarioTab.value,
steps: mapTree(activeScenarioTab.value.steps, (node) => {
return {
...node,
parent: null, // axios
};
}),
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
environmentId: currentEnvConfig.value?.id || '', environmentId: currentEnvConfig.value?.id || '',
}); });
@ -246,6 +252,12 @@
await updateScenario({ await updateScenario({
...activeScenarioTab.value, ...activeScenarioTab.value,
environmentId: currentEnvConfig.value?.id || '', environmentId: currentEnvConfig.value?.id || '',
steps: mapTree(activeScenarioTab.value.steps, (node) => {
return {
...node,
parent: null, // axios
};
}),
}); });
} }
Message.success(activeScenarioTab.value.isNew ? t('common.createSuccess') : t('common.saveSuccess')); Message.success(activeScenarioTab.value.isNew ? t('common.createSuccess') : t('common.saveSuccess'));
@ -394,6 +406,7 @@
}); });
} }
if (executeType === 'localExec' && localExecuteUrl) { if (executeType === 'localExec' && localExecuteUrl) {
// debug
await localExecuteApiDebug(localExecuteUrl, res); await localExecuteApiDebug(localExecuteUrl, res);
} }
} catch (error) { } catch (error) {

View File

@ -137,6 +137,7 @@ export default {
'apiScenario.saveAsApi': '保存为新接口', 'apiScenario.saveAsApi': '保存为新接口',
'apiScenario.scenarioLevel': '场景等级', 'apiScenario.scenarioLevel': '场景等级',
'apiScenario.running': '执行中', 'apiScenario.running': '执行中',
'apiScenario.unExecute': '未执行',
'apiScenario.response': '响应内容', 'apiScenario.response': '响应内容',
// 执行历史 // 执行历史
'apiScenario.executeHistory.searchPlaceholder': '通过ID或名称搜索', 'apiScenario.executeHistory.searchPlaceholder': '通过ID或名称搜索',