feat(接口测试): 接口测试联调请求体展示
This commit is contained in:
parent
ec07c38eb1
commit
e66789c0b5
|
@ -398,6 +398,23 @@
|
|||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.diffMode,
|
||||
(newDiffMode) => {
|
||||
if (newDiffMode) {
|
||||
if (editor) {
|
||||
editor.dispose();
|
||||
}
|
||||
initDiffEditor(props.originalValue, props.modelValue);
|
||||
} else {
|
||||
if (diffEditor) {
|
||||
diffEditor.dispose();
|
||||
}
|
||||
init();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (editor) {
|
||||
editor.dispose();
|
||||
|
|
|
@ -564,10 +564,12 @@
|
|||
() => attrs.data,
|
||||
(val) => {
|
||||
if (val) {
|
||||
const minTagWidth = 60; // 确保标签行没有标签标题正常展示宽度最少为60
|
||||
currentColumns.value.forEach((column) => {
|
||||
const dataIndex = column.dataIndex as string;
|
||||
if (column.isTag || column.isStringTag) {
|
||||
columnLastWidthMap.value[dataIndex] = getMaxRowTagWidth((val as TableData[]) || [], dataIndex);
|
||||
const lastWidth = getMaxRowTagWidth((val as TableData[]) || [], dataIndex);
|
||||
columnLastWidthMap.value[dataIndex] = lastWidth < minTagWidth ? minTagWidth : lastWidth;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,35 +57,33 @@
|
|||
{{ t('case.notSetData') }}
|
||||
</div>
|
||||
<!-- 请求体 -->
|
||||
<div class="title flex items-center justify-between">
|
||||
<div class="detail-item-title-text">
|
||||
{{ `${t('apiTestManagement.requestBody')}-${previewDetail?.body?.bodyType}` }}
|
||||
<div v-for="item of requestBodyList" :key="item.value">
|
||||
<div v-if="showDiff(item.value)" class="title">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div
|
||||
v-if="showDiff(item.value) && hiddenEmptyTable(item.value)"
|
||||
:style="{ 'padding-bottom': `${getBottomDistance(item.value)}px` }"
|
||||
>
|
||||
<MsFormTable
|
||||
:columns="getBodyColumns(item.value)"
|
||||
:data="getBodyTableData(item.value)"
|
||||
:selectable="false"
|
||||
:show-setting="true"
|
||||
:table-key="TableKeyEnum.API_TEST_DEBUG_FORM_DATA"
|
||||
:diff-mode="props.mode"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="showDiff(item.value) && !hiddenEmptyTable(item.value)"
|
||||
class="not-setting-data"
|
||||
:style="{ height: `${getBottomDistance(item.value, true)}px` }"
|
||||
>
|
||||
{{ t('case.notSetData') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
(previewDetail?.body?.bodyType === RequestBodyFormat.FORM_DATA ||
|
||||
previewDetail?.body?.bodyType === RequestBodyFormat.WWW_FORM) &&
|
||||
showDiff(previewDetail?.body?.bodyType) &&
|
||||
hiddenEmptyTable(previewDetail?.body?.bodyType)
|
||||
"
|
||||
:style="{ 'padding-bottom': `${getBottomDistance(previewDetail.value?.body?.bodyType)}px` }"
|
||||
>
|
||||
<MsFormTable
|
||||
:columns="bodyColumns"
|
||||
:data="bodyTableData"
|
||||
:selectable="false"
|
||||
:show-setting="true"
|
||||
:table-key="TableKeyEnum.API_TEST_DEBUG_FORM_DATA"
|
||||
:diff-mode="props.mode"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="showDiff(previewDetail?.body?.bodyType) && !hiddenEmptyTable(previewDetail?.body?.bodyType)"
|
||||
class="not-setting-data"
|
||||
:style="{ height: `${getBottomDistance(previewDetail?.body?.bodyType, true)}px` }"
|
||||
>
|
||||
{{ t('case.notSetData') }}
|
||||
<div class="title">
|
||||
{{ `${t('apiTestManagement.requestBody')}-JSON` }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -113,6 +111,17 @@
|
|||
|
||||
const previewDetail = ref<RequestParam>(props.detail);
|
||||
|
||||
const requestBodyList = ref([
|
||||
{
|
||||
value: RequestBodyFormat.FORM_DATA,
|
||||
title: `${t('apiTestManagement.requestBody')}-FORM_DATA`,
|
||||
},
|
||||
{
|
||||
value: RequestBodyFormat.WWW_FORM,
|
||||
title: `${t('apiTestManagement.requestBody')}-WWW_FORM`,
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* 请求头
|
||||
*/
|
||||
|
@ -213,8 +222,9 @@
|
|||
/**
|
||||
* 请求体
|
||||
*/
|
||||
const bodyColumns = computed<FormTableColumn[]>(() => {
|
||||
if ([RequestBodyFormat.FORM_DATA, RequestBodyFormat.WWW_FORM].includes(previewDetail.value?.body?.bodyType)) {
|
||||
|
||||
function getBodyColumns(bodyType: RequestBodyFormat): FormTableColumn[] {
|
||||
if ([RequestBodyFormat.FORM_DATA, RequestBodyFormat.WWW_FORM].includes(bodyType)) {
|
||||
return [
|
||||
{
|
||||
title: 'apiTestManagement.paramName',
|
||||
|
@ -300,12 +310,12 @@
|
|||
showTooltip: true,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
const bodyTableData = computed(() => {
|
||||
switch (previewDetail.value?.body?.bodyType) {
|
||||
function getBodyTableData(bodyType: string) {
|
||||
switch (bodyType) {
|
||||
case RequestBodyFormat.FORM_DATA:
|
||||
return (previewDetail.value.body.formDataBody?.formValues || [])
|
||||
return (previewDetail.value.body?.formDataBody?.formValues || [])
|
||||
.map((e) => ({
|
||||
...e,
|
||||
value: e.paramType === RequestParamsType.FILE ? e.files?.map((file) => file.fileName).join('、') : e.value,
|
||||
|
@ -323,7 +333,7 @@
|
|||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const typeKey = computed(() => (props.isApi ? 'api' : 'case'));
|
||||
|
||||
|
|
|
@ -1,38 +1,46 @@
|
|||
<template>
|
||||
<template
|
||||
v-if="
|
||||
[RequestBodyFormat.JSON, RequestBodyFormat.RAW, RequestBodyFormat.XML].includes(
|
||||
previewDefinedDetail?.body?.bodyType
|
||||
)
|
||||
"
|
||||
>
|
||||
<MsCodeEditor
|
||||
v-if="previewDefinedDetail?.body?.bodyType === RequestBodyFormat.JSON"
|
||||
:model-value="bodyCaseCode"
|
||||
theme="vs"
|
||||
height="200px"
|
||||
:language="bodyCodeLanguage"
|
||||
:show-full-screen="false"
|
||||
:show-theme-change="false"
|
||||
read-only
|
||||
is-adaptive
|
||||
diff-mode
|
||||
:original-value="bodyDefinedCode"
|
||||
>
|
||||
<template #rightTitle>
|
||||
<a-button
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary p-[0_8px]"
|
||||
size="mini"
|
||||
@click="copyScript(bodyDefinedCode)"
|
||||
>
|
||||
<template #icon>
|
||||
<MsIcon type="icon-icon_copy_outlined" class="text-var(--color-text-4)" size="12" />
|
||||
</template>
|
||||
</a-button>
|
||||
</template>
|
||||
</MsCodeEditor>
|
||||
</template>
|
||||
<div v-if="showDiffEditor" :class="`${bodyCaseCode && bodyDefinedCode ? '' : 'grid grid-cols-2 gap-[24px]'}`">
|
||||
<div v-if="!bodyDefinedCode && bodyCaseCode" class="no-case-data h-full">
|
||||
{{ t('case.notSetData') }}
|
||||
</div>
|
||||
<template v-if="showDiffEditor">
|
||||
<MsCodeEditor
|
||||
:model-value="showDiffEditor"
|
||||
theme="vs"
|
||||
height="200px"
|
||||
:class="`${bodyCaseCode ? '' : 'no-case-data-bg'} w-full`"
|
||||
:language="bodyCodeLanguage"
|
||||
:show-full-screen="false"
|
||||
:show-theme-change="false"
|
||||
read-only
|
||||
is-adaptive
|
||||
:diff-mode="diffMode"
|
||||
:original-value="bodyDefinedCode"
|
||||
>
|
||||
<template #rightTitle>
|
||||
<a-button
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary p-[0_8px]"
|
||||
size="mini"
|
||||
@click="copyScript(bodyDefinedCode)"
|
||||
>
|
||||
<template #icon>
|
||||
<MsIcon type="icon-icon_copy_outlined" class="text-var(--color-text-4)" size="12" />
|
||||
</template>
|
||||
</a-button>
|
||||
</template>
|
||||
</MsCodeEditor>
|
||||
</template>
|
||||
<div v-if="!bodyCaseCode && bodyDefinedCode" class="no-case-data h-full"> {{ t('case.notSetData') }} </div>
|
||||
</div>
|
||||
<div v-else class="grid grid-cols-2 gap-[24px]">
|
||||
<div v-if="!bodyCaseCode && !bodyDefinedCode" class="no-json-case-data no-case-data">
|
||||
{{ t('case.notSetData') }}
|
||||
</div>
|
||||
<div v-if="!bodyCaseCode && !bodyDefinedCode" class="no-json-case-data no-case-data">
|
||||
{{ t('case.notSetData') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -82,8 +90,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
const getBodyCode = (body: ExecuteBody) => {
|
||||
switch (body?.bodyType) {
|
||||
const getBodyCode = (body: ExecuteBody, bodyType: RequestBodyFormat) => {
|
||||
switch (bodyType) {
|
||||
case RequestBodyFormat.FORM_DATA:
|
||||
return body.formDataBody?.formValues?.map((item: any) => `${item.key}:${item.value}`).join('\n');
|
||||
case RequestBodyFormat.WWW_FORM:
|
||||
|
@ -91,7 +99,7 @@
|
|||
case RequestBodyFormat.RAW:
|
||||
return body.rawBody?.value;
|
||||
case RequestBodyFormat.JSON:
|
||||
return body.jsonBody?.jsonValue;
|
||||
return body?.jsonBody?.jsonValue;
|
||||
case RequestBodyFormat.XML:
|
||||
return body.xmlBody?.value;
|
||||
default:
|
||||
|
@ -100,10 +108,16 @@
|
|||
};
|
||||
|
||||
// 接口定义Code
|
||||
const bodyDefinedCode = computed(() => getBodyCode(previewDefinedDetail.value?.body));
|
||||
const bodyDefinedCode = computed(() => getBodyCode(previewDefinedDetail.value?.body, RequestBodyFormat.JSON));
|
||||
|
||||
// 用例Code
|
||||
const bodyCaseCode = computed(() => getBodyCode(previewCaseDetail.value?.body));
|
||||
const bodyCaseCode = computed(() => getBodyCode(previewCaseDetail.value?.body, RequestBodyFormat.JSON));
|
||||
|
||||
const diffMode = computed(() => {
|
||||
return !!(bodyDefinedCode.value && bodyCaseCode.value) || (!bodyDefinedCode.value && !bodyCaseCode.value);
|
||||
});
|
||||
|
||||
const showDiffEditor = computed(() => bodyCaseCode.value || bodyDefinedCode.value);
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.definedDetail) {
|
||||
|
@ -115,4 +129,20 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped lang="less">
|
||||
.no-case-data {
|
||||
height: 100% !important;
|
||||
border: 1px solid var(--color-border-2);
|
||||
border-radius: 4px;
|
||||
@apply flex items-center justify-center;
|
||||
&.no-json-case-data {
|
||||
min-height: 200px;
|
||||
@apply h-full;
|
||||
}
|
||||
}
|
||||
.no-case-data-bg {
|
||||
:deep(.view-line) {
|
||||
background: rgb(var(--success-1)) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -64,27 +64,30 @@
|
|||
</div>
|
||||
<!-- 对比 -->
|
||||
<div class="diff-container">
|
||||
<a-spin class="h-full w-full" :loading="loading">
|
||||
<div class="diff-normal">
|
||||
<div class="diff-item">
|
||||
<div class="title-type"> [{{ apiDetailInfo?.num }}] {{ apiDetailInfo?.name }} </div>
|
||||
<DiffItem
|
||||
:diff-distance-map="diffDistanceMap"
|
||||
mode="add"
|
||||
is-api
|
||||
:detail="apiDefinedRequest as RequestParam"
|
||||
/>
|
||||
<MsCard simple auto-height no-content-padding>
|
||||
<a-spin class="h-full w-full p-4" :loading="loading">
|
||||
<div class="diff-normal">
|
||||
<div class="diff-item">
|
||||
<div class="title-type"> [{{ apiDetailInfo?.num }}] {{ apiDetailInfo?.name }} </div>
|
||||
<DiffItem
|
||||
:diff-distance-map="diffDistanceMap"
|
||||
mode="add"
|
||||
is-api
|
||||
:detail="apiDefinedRequest as RequestParam"
|
||||
/>
|
||||
</div>
|
||||
<div class="diff-item ml-[24px]">
|
||||
<div class="title-type"> [{{ caseDetail?.num }}] {{ caseDetail?.name }} </div>
|
||||
<DiffItem :diff-distance-map="diffDistanceMap" mode="delete" :detail="caseDetail as RequestParam" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="diff-item ml-[24px]">
|
||||
<div class="title-type"> [{{ caseDetail?.num }}] {{ caseDetail?.name }} </div>
|
||||
<DiffItem :diff-distance-map="diffDistanceMap" mode="delete" :detail="caseDetail as RequestParam" />
|
||||
</div>
|
||||
</div>
|
||||
<DiffRequestBody
|
||||
:defined-detail="apiDefinedRequest as RequestParam"
|
||||
:case-detail="caseDetail as RequestParam"
|
||||
/>
|
||||
</a-spin>
|
||||
|
||||
<DiffRequestBody
|
||||
:defined-detail="apiDefinedRequest as RequestParam"
|
||||
:case-detail="caseDetail as RequestParam"
|
||||
/>
|
||||
</a-spin>
|
||||
</MsCard>
|
||||
</div>
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
@ -94,6 +97,7 @@
|
|||
import { Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import { TabItem } from '@/components/pure/ms-editable-tab/types';
|
||||
import DiffItem from './diffItem.vue';
|
||||
|
@ -239,7 +243,6 @@
|
|||
|
||||
// 设置对比水平对齐间距绝对值
|
||||
const disAbs = Math.abs(caseData.length - definedData.length);
|
||||
|
||||
diffDistanceMap.value[typeKey] = {
|
||||
case: caseData.length < definedData.length ? disAbs : 0,
|
||||
api: caseData.length > definedData.length ? disAbs : 0,
|
||||
|
@ -254,6 +257,35 @@
|
|||
};
|
||||
}
|
||||
|
||||
function getBodyData(bodyType: string) {
|
||||
switch (bodyType) {
|
||||
// FORM_DATA格式
|
||||
case RequestBodyFormat.FORM_DATA:
|
||||
const bodyFormDataDiffObj = setDiff(
|
||||
apiDefinedRequest.value.body.formDataBody?.formValues as any,
|
||||
caseDetail.value.body.formDataBody?.formValues,
|
||||
RequestBodyFormat.FORM_DATA
|
||||
);
|
||||
apiDefinedRequest.value.body.formDataBody.formValues =
|
||||
bodyFormDataDiffObj.definedData as ExecuteRequestCommonParam[];
|
||||
caseDetail.value.body.formDataBody.formValues = bodyFormDataDiffObj.caseData;
|
||||
break;
|
||||
// WWW_FORM格式
|
||||
case RequestBodyFormat.WWW_FORM:
|
||||
const bodyWwwFormDiffObj = setDiff(
|
||||
apiDefinedRequest.value.body.wwwFormBody?.formValues as any,
|
||||
caseDetail.value.body.wwwFormBody?.formValues,
|
||||
RequestBodyFormat.WWW_FORM
|
||||
);
|
||||
apiDefinedRequest.value.body.wwwFormBody.formValues =
|
||||
bodyWwwFormDiffObj.definedData as ExecuteRequestCommonParam[];
|
||||
caseDetail.value.body.wwwFormBody.formValues = bodyWwwFormDiffObj.caseData;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对比数据
|
||||
function processData() {
|
||||
// 处理请求头
|
||||
|
@ -283,39 +315,21 @@
|
|||
caseDetail.value.rest = restDiffObj.caseData;
|
||||
}
|
||||
// 处理请求体
|
||||
if (apiDefinedRequest.value?.body?.bodyType) {
|
||||
switch (apiDefinedRequest.value?.body?.bodyType) {
|
||||
// FORM_DATA格式
|
||||
case RequestBodyFormat.FORM_DATA:
|
||||
const bodyFormDataDiffObj = setDiff(
|
||||
apiDefinedRequest.value.body.formDataBody?.formValues as any,
|
||||
caseDetail.value.body.formDataBody?.formValues,
|
||||
RequestBodyFormat.FORM_DATA
|
||||
);
|
||||
apiDefinedRequest.value.body.formDataBody.formValues =
|
||||
bodyFormDataDiffObj.definedData as ExecuteRequestCommonParam[];
|
||||
caseDetail.value.body.formDataBody.formValues = bodyFormDataDiffObj.caseData;
|
||||
break;
|
||||
// WWW_FORM格式
|
||||
case RequestBodyFormat.WWW_FORM:
|
||||
const bodyWwwFormDiffObj = setDiff(
|
||||
apiDefinedRequest.value.body.wwwFormBody?.formValues as any,
|
||||
caseDetail.value.body.wwwFormBody?.formValues,
|
||||
RequestBodyFormat.WWW_FORM
|
||||
);
|
||||
apiDefinedRequest.value.body.wwwFormBody.formValues =
|
||||
bodyWwwFormDiffObj.definedData as ExecuteRequestCommonParam[];
|
||||
caseDetail.value.body.wwwFormBody.formValues = bodyWwwFormDiffObj.caseData;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
getBodyData(RequestBodyFormat.FORM_DATA);
|
||||
getBodyData(RequestBodyFormat.WWW_FORM);
|
||||
}
|
||||
// 获取用例详情
|
||||
async function getCaseDetailInfo(id: string) {
|
||||
try {
|
||||
const res = await getCaseDetail(id);
|
||||
const result = await diffDataRequest(id);
|
||||
const { caseRequest, apiRequest } = result;
|
||||
caseDetail.value = {
|
||||
...caseDetail.value,
|
||||
...caseRequest,
|
||||
num: caseDetail.value.num,
|
||||
};
|
||||
apiDefinedRequest.value = apiRequest;
|
||||
let parseRequestBodyResult;
|
||||
if (res.protocol === 'HTTP') {
|
||||
parseRequestBodyResult = parseRequestBodyFiles(res.request.body); // 解析请求体中的文件,将详情中的文件 id 集合收集,更新时以判断文件是否删除以及是否新上传的文件
|
||||
|
@ -324,6 +338,8 @@
|
|||
...cloneDeep(defaultCaseParams as RequestParam),
|
||||
...({
|
||||
...res,
|
||||
...caseRequest,
|
||||
num: res.num,
|
||||
url: res.path,
|
||||
...parseRequestBodyResult,
|
||||
} as Partial<TabItem>),
|
||||
|
@ -345,28 +361,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function getDiffDataRequest(activeApiCaseId: string) {
|
||||
try {
|
||||
const result = await diffDataRequest(activeApiCaseId);
|
||||
const { caseRequest, apiRequest } = result;
|
||||
caseDetail.value = {
|
||||
...caseDetail.value,
|
||||
...caseRequest,
|
||||
num: caseDetail.value.num,
|
||||
};
|
||||
apiDefinedRequest.value = apiRequest;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
async function getRequestDetail(definedId: string, apiCaseId: string) {
|
||||
loading.value = true;
|
||||
try {
|
||||
await Promise.all([getApiDetail(definedId), getCaseDetailInfo(apiCaseId)]);
|
||||
await getDiffDataRequest(props.activeApiCaseId);
|
||||
processData();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -430,12 +429,8 @@
|
|||
}
|
||||
}
|
||||
.diff-container {
|
||||
padding: 16px;
|
||||
padding: 0 16px;
|
||||
min-height: calc(100vh - 110px);
|
||||
border-radius: 12px;
|
||||
background: white;
|
||||
box-shadow: 0 0 10px rgba(120 56 135/ 5%);
|
||||
@apply mx-4;
|
||||
.diff-normal {
|
||||
@apply flex;
|
||||
.diff-item {
|
||||
|
|
Loading…
Reference in New Issue