fix(接口管理): 用例执行渲染出响应数据
This commit is contained in:
parent
d85c5d3ee5
commit
9b0a28ac9f
|
@ -234,26 +234,26 @@
|
|||
</div>
|
||||
</div>
|
||||
</a-collapse-item>
|
||||
<a-spin :loading="previewDetail.executeLoading" class="w-full">
|
||||
<a-collapse-item
|
||||
v-if="
|
||||
previewDetail.responseDefinition &&
|
||||
previewDetail.responseDefinition.length > 0 &&
|
||||
props.detail.protocol === 'HTTP'
|
||||
"
|
||||
key="response"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-[4px]">
|
||||
<div v-if="activeDetailKey.includes('response')" class="down-icon">
|
||||
<icon-down :size="10" class="block" />
|
||||
</div>
|
||||
<div v-else class="h-[16px] w-[16px] !rounded-full p-[4px]">
|
||||
<icon-right :size="10" class="block" />
|
||||
</div>
|
||||
<div class="font-medium">{{ t('apiTestManagement.responseContent') }}</div>
|
||||
<a-collapse-item
|
||||
v-if="
|
||||
previewDetail.responseDefinition &&
|
||||
previewDetail.responseDefinition.length > 0 &&
|
||||
props.detail.protocol === 'HTTP'
|
||||
"
|
||||
key="response"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-[4px]">
|
||||
<div v-if="activeDetailKey.includes('response')" class="down-icon">
|
||||
<icon-down :size="10" class="block" />
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="h-[16px] w-[16px] !rounded-full p-[4px]">
|
||||
<icon-right :size="10" class="block" />
|
||||
</div>
|
||||
<div class="font-medium">{{ t('apiTestManagement.responseContent') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="!props.isCase">
|
||||
<MsEditableTab
|
||||
v-model:active-tab="activeResponse"
|
||||
:tabs="previewDetail.responseDefinition?.map((e) => ({ ...e, closable: false })) || []"
|
||||
|
@ -313,8 +313,23 @@
|
|||
</div>
|
||||
<MsFormTable :columns="responseHeaderColumns" :data="activeResponse?.headers || []" :selectable="false" />
|
||||
</div>
|
||||
</a-collapse-item>
|
||||
</a-spin>
|
||||
</template>
|
||||
<a-spin v-else :loading="previewDetail.executeLoading" class="h-[calc(100%-45px)] w-full pb-[18px]">
|
||||
<result
|
||||
v-show="
|
||||
previewDetail.protocol === 'HTTP' || previewDetail.response?.requestResults[0]?.responseResult.responseCode
|
||||
"
|
||||
v-model:active-tab="previewDetail.responseActiveTab"
|
||||
:request-result="previewDetail.response?.requestResults[0]"
|
||||
:console="previewDetail.response?.console"
|
||||
:is-http-protocol="previewDetail.protocol === 'HTTP'"
|
||||
:is-priority-local-exec="props.isPriorityLocalExec"
|
||||
:request-url="previewDetail.url"
|
||||
is-definition
|
||||
@execute="emit('execute', props.isPriorityLocalExec ? 'localExec' : 'serverExec')"
|
||||
/>
|
||||
</a-spin>
|
||||
</a-collapse-item>
|
||||
</a-collapse>
|
||||
</template>
|
||||
|
||||
|
@ -330,6 +345,7 @@
|
|||
import MsFormTable, { FormTableColumn } from '@/components/pure/ms-form-table/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import { ResponseItem } from '@/views/api-test/components/requestComposition/response/edit.vue';
|
||||
import result from '@/views/api-test/components/requestComposition/response/result.vue';
|
||||
|
||||
import { getPluginScript } from '@/api/modules/api-test/common';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -343,6 +359,10 @@
|
|||
isCase?: boolean; // case详情
|
||||
detail: RequestParam;
|
||||
protocols: ProtocolItem[];
|
||||
isPriorityLocalExec?: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'execute', val: 'localExec' | 'serverExec'): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
<template #extra>
|
||||
<div class="flex gap-[12px]">
|
||||
<environmentSelect v-if="props.isDrawer" ref="environmentSelectRef" />
|
||||
<execute v-model:detail="caseDetail" :environment-id="environmentId as string" />
|
||||
<execute
|
||||
ref="executeRef"
|
||||
v-model:detail="caseDetail"
|
||||
:environment-id="environmentId as string"
|
||||
is-case-detail
|
||||
/>
|
||||
<a-dropdown position="br" :hide-on-select="false" @select="handleSelect">
|
||||
<a-button v-if="!props.isDrawer">{{ t('common.operation') }}</a-button>
|
||||
<template #content>
|
||||
|
@ -45,7 +50,13 @@
|
|||
<caseLevel :case-level="value as CaseLevel" />
|
||||
</template>
|
||||
</MsDetailCard>
|
||||
<detailTab :detail="caseDetail" :protocols="protocols as ProtocolItem[]" is-case />
|
||||
<detailTab
|
||||
:detail="caseDetail"
|
||||
:protocols="protocols as ProtocolItem[]"
|
||||
:is-priority-local-exec="isPriorityLocalExec"
|
||||
is-case
|
||||
@execute="(val: 'localExec' | 'serverExec')=>executeRef?.execute(val)"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="reference" :title="t('apiTestManagement.reference')" class="px-[18px] py-[16px]">
|
||||
<tab-case-dependency :source-id="caseDetail.id" />
|
||||
|
@ -213,6 +224,9 @@
|
|||
props.isDrawer ? currentEnvConfigByDrawer.value?.id : currentEnvConfigByInject?.value?.id
|
||||
);
|
||||
|
||||
const executeRef = ref<InstanceType<typeof execute>>();
|
||||
const isPriorityLocalExec = computed(() => executeRef.value?.isPriorityLocalExec ?? false);
|
||||
|
||||
defineExpose({
|
||||
editCase,
|
||||
share,
|
||||
|
@ -248,4 +262,7 @@
|
|||
color: rgb(var(--danger-6));
|
||||
}
|
||||
}
|
||||
:deep(.monaco-editor) {
|
||||
height: 212px !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
@select="execute"
|
||||
>
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.localExec') : t('apiTestDebug.serverExec') }}
|
||||
<template v-if="hasLocalExec" #icon>
|
||||
<template #icon>
|
||||
<icon-down />
|
||||
</template>
|
||||
<template v-if="hasLocalExec" #content>
|
||||
<template #content>
|
||||
<a-doption :value="isPriorityLocalExec ? 'serverExec' : 'localExec'">
|
||||
{{ isPriorityLocalExec ? t('apiTestDebug.serverExec') : t('apiTestDebug.localExec') }}
|
||||
</a-doption>
|
||||
|
@ -28,15 +28,17 @@
|
|||
import { localExecuteApiDebug } from '@/api/modules/api-test/common';
|
||||
import { debugCase, runCase } from '@/api/modules/api-test/management';
|
||||
import { getSocket } from '@/api/modules/project-management/commonScript';
|
||||
import { getLocalConfig } from '@/api/modules/user/index';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import { LocalConfig } from '@/models/user';
|
||||
|
||||
import { defaultResponse } from '@/views/api-test/components/config';
|
||||
|
||||
const props = defineProps<{
|
||||
environmentId: string;
|
||||
request?: (...args) => Record<string, any>;
|
||||
isCaseDetail?: boolean;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -46,31 +48,13 @@
|
|||
required: true,
|
||||
});
|
||||
|
||||
const hasLocalExec = ref(false); // 是否配置了api本地执行
|
||||
const isPriorityLocalExec = ref(false); // 是否优先本地执行
|
||||
const localExecuteUrl = ref('');
|
||||
const apiLocalExec = inject<Ref<LocalConfig>>('apiLocalExec');
|
||||
const isPriorityLocalExec = ref(apiLocalExec?.value.enable || false); // 是否优先本地执行
|
||||
const localExecuteUrl = ref(apiLocalExec?.value.userUrl || '');
|
||||
const reportId = ref('');
|
||||
const websocket = ref<WebSocket>();
|
||||
const temporaryResponseMap = {}; // 缓存websocket返回的报告内容,避免执行接口后切换tab导致报告丢失
|
||||
|
||||
async function initLocalConfig() {
|
||||
if (hasLocalExec.value) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await getLocalConfig(); // TODO: 会报错
|
||||
const apiLocalExec = res.find((e) => e.type === 'API');
|
||||
if (apiLocalExec) {
|
||||
hasLocalExec.value = true;
|
||||
isPriorityLocalExec.value = apiLocalExec.enable || false;
|
||||
localExecuteUrl.value = apiLocalExec.userUrl || '';
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启websocket监听,接收执行结果
|
||||
*/
|
||||
|
@ -85,8 +69,7 @@
|
|||
if (data.msgType === 'EXEC_RESULT') {
|
||||
if (caseDetail.value.reportId === data.reportId) {
|
||||
// 判断当前查看的tab是否是当前返回的报告的tab,是的话直接赋值
|
||||
// TODO: 渲染出用例详情的响应数据
|
||||
caseDetail.value.response = data.taskResult; // 渲染出创建用例抽屉的响应数据
|
||||
caseDetail.value.response = data.taskResult; // 渲染出用例详情和创建用例抽屉的响应数据
|
||||
caseDetail.value.executeLoading = false;
|
||||
} else {
|
||||
// 不是则需要把报告缓存起来,等切换到对应的tab再赋值
|
||||
|
@ -114,28 +97,28 @@
|
|||
reportId: reportId.value,
|
||||
};
|
||||
debugSocket(executeType); // 开启websocket
|
||||
if ((caseDetail.value.id as string).startsWith('c')) {
|
||||
// 还没创建
|
||||
res = await debugCase({
|
||||
request: makeRequestParams?.request,
|
||||
linkFileIds: makeRequestParams?.linkFileIds,
|
||||
uploadFileIds: makeRequestParams?.uploadFileIds,
|
||||
id: `case-${Date.now()}`,
|
||||
projectId: appStore.currentProjectId,
|
||||
...params,
|
||||
});
|
||||
} else {
|
||||
if (!(caseDetail.value.id as string).startsWith('c') && executeType === 'serverExec') {
|
||||
// 已创建的服务端
|
||||
res = await runCase({
|
||||
request: caseDetail.value.request,
|
||||
request: props.isCaseDetail ? caseDetail.value.request : makeRequestParams?.request,
|
||||
id: caseDetail.value.id as string,
|
||||
projectId: caseDetail.value.projectId,
|
||||
linkFileIds: caseDetail.value.linkFileIds,
|
||||
uploadFileIds: caseDetail.value.uploadFileIds,
|
||||
...params,
|
||||
});
|
||||
} else {
|
||||
res = await debugCase({
|
||||
request: props.isCaseDetail ? caseDetail.value.request : makeRequestParams?.request,
|
||||
linkFileIds: makeRequestParams?.linkFileIds,
|
||||
uploadFileIds: makeRequestParams?.uploadFileIds,
|
||||
id: `case-${Date.now()}`,
|
||||
projectId: appStore.currentProjectId,
|
||||
...params,
|
||||
});
|
||||
}
|
||||
if (executeType === 'localExec') {
|
||||
await localExecuteApiDebug(localExecuteUrl.value, res); // TODO: 会报错
|
||||
await localExecuteApiDebug(localExecuteUrl.value, res);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -149,8 +132,9 @@
|
|||
caseDetail.value.executeLoading = false;
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
initLocalConfig();
|
||||
defineExpose({
|
||||
isPriorityLocalExec,
|
||||
execute,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
|
||||
// import MockTable from '@/views/api-test/management/components/management/mock/mockTable.vue';
|
||||
import { getEnvironment, getEnvList, getProtocolList } from '@/api/modules/api-test/common';
|
||||
import { getLocalConfig } from '@/api/modules/user/index';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import router from '@/router';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
@ -77,6 +78,7 @@
|
|||
import { ProtocolItem } from '@/models/apiTest/common';
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
import { EnvConfig } from '@/models/projectManagement/environmental';
|
||||
import { LocalConfig } from '@/models/user';
|
||||
import {
|
||||
RequestAuthType,
|
||||
RequestComposition,
|
||||
|
@ -328,15 +330,28 @@
|
|||
}
|
||||
}
|
||||
|
||||
const apiLocalExec = ref<Record<string, any> | LocalConfig | undefined>({});
|
||||
async function initLocalConfig() {
|
||||
try {
|
||||
const res = await getLocalConfig(); // TODO: 会报错
|
||||
apiLocalExec.value = res.find((e) => e.type === 'API');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
initEnvList();
|
||||
initProtocolList();
|
||||
initLocalConfig();
|
||||
});
|
||||
|
||||
/** 向孙组件提供属性 */
|
||||
provide('currentEnvConfig', readonly(currentEnvConfig));
|
||||
provide('defaultCaseParams', readonly(defaultCaseParams));
|
||||
provide('protocols', readonly(protocols));
|
||||
provide('apiLocalExec', readonly(apiLocalExec));
|
||||
|
||||
defineExpose({
|
||||
newTab,
|
||||
|
|
Loading…
Reference in New Issue