fix: 修改全局组件断言相关问题

This commit is contained in:
xinxin.wu 2024-03-26 14:28:19 +08:00 committed by 刘瑞斌
parent c18652c809
commit 7f32e69ea2
13 changed files with 114 additions and 174 deletions

View File

@ -1,14 +1,14 @@
<template>
<div class="flex w-full flex-col">
<div>
<a-radio-group v-model:model-value="activeTab" type="button" size="small">
<a-radio-group v-model:model-value="condition.assertionBodyType" type="button" size="small">
<a-radio v-for="item of responseRadios" :key="item.value" :value="item.value">
{{ t(item.label) }}
</a-radio>
</a-radio-group>
</div>
<!-- jsonPath开始 -->
<div v-if="activeTab === ResponseBodyAssertionType.JSON_PATH" class="mt-[16px]">
<div v-if="condition.assertionBodyType === ResponseBodyAssertionType.JSON_PATH" class="mt-[16px]">
<paramsTable
ref="extractParamsTableRef"
v-model:params="condition.jsonPathAssertion.assertions"
@ -91,7 +91,7 @@
</div>
<!-- jsonPath结束 -->
<!-- xPath开始 -->
<div v-if="activeTab === ResponseBodyAssertionType.XPATH" class="mt-[16px]">
<div v-if="condition.assertionBodyType === ResponseBodyAssertionType.XPATH" class="mt-[16px]">
<div class="text-[var(--color-text-1)]">{{ t('ms.assertion.responseContentType') }}</div>
<a-radio-group
v-model="condition.xpathAssertion.responseFormat"
@ -184,7 +184,7 @@
</div>
<!-- xPath结束 -->
<!-- document开始 -->
<div v-if="activeTab === ResponseBodyAssertionType.DOCUMENT" class="relative mt-[16px]">
<div v-if="condition.assertionBodyType === ResponseBodyAssertionType.DOCUMENT" class="relative mt-[16px]">
<div class="text-[var(--color-text-1)]">
{{ t('ms.assertion.responseContentType') }}
</div>
@ -248,7 +248,7 @@
</div>
<!-- document结束 -->
<!-- 正则开始 -->
<div v-if="activeTab === ResponseBodyAssertionType.REGEX" class="mt-[16px]">
<div v-if="condition.assertionBodyType === ResponseBodyAssertionType.REGEX" class="mt-[16px]">
<paramsTable
ref="extractParamsTableRef"
v-model:params="condition.regexAssertion.assertions"
@ -330,10 +330,6 @@
</paramsTable>
</div>
<!-- 正则结束 -->
<!-- 这一版断言里边的脚本不需要 -->
<!-- <div v-if="activeTab === ResponseBodyAssertionType.SCRIPT" class="mt-[16px]">
<conditionContent v-model:data="condition.script" :height-used="600" is-build-in class="mt-[16px]" />
</div> -->
</div>
<fastExtraction
v-model:visible="fastExtractionVisible"
@ -350,12 +346,10 @@
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import { TableOperationColumn } from '../../ms-user-group-comp/authTable.vue';
import conditionContent from '@/views/api-test/components/condition/content.vue';
import fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
import moreSetting from '@/views/api-test/components/fastExtraction/moreSetting.vue';
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
import { conditionTypeNameMap } from '@/config/apiTest';
import { useI18n } from '@/hooks/useI18n';
import {
countNodes,
@ -374,8 +368,6 @@
XPathExtract,
} from '@/models/apiTest/common';
import {
RequestConditionProcessor,
RequestConditionScriptLanguage,
RequestExtractEnvType,
RequestExtractExpressionEnum,
RequestExtractExpressionRuleType,
@ -385,26 +377,31 @@
ResponseBodyXPathAssertionFormat,
} from '@/enums/apiEnum';
const { t } = useI18n();
interface Param {
[key: string]: any;
}
const emit = defineEmits<{
// (e: 'update:data', data: ExecuteConditionProcessor): void;
(e: 'copy'): void;
(e: 'delete', id: number): void;
(e: 'change', param: Param): void;
}>();
const { t } = useI18n();
const rootId = 0; // 1970-01-01 00:00:00 UTC
const props = defineProps<{
data: Param;
response?: string;
disabled?: boolean;
}>();
const emit = defineEmits<{
(e: 'update:data', data: ExecuteConditionProcessor): void;
(e: 'copy'): void;
(e: 'delete', id: number): void;
(e: 'change', param: Param): void;
}>();
const condition = useVModel(props, 'data', emit);
const rootId = 0; // 1970-01-01 00:00:00 UTC
const activeTab = ref(ResponseBodyAssertionType.JSON_PATH);
const activeResponseFormat = ref('XML');
const defaultParamItem = {
jsonPathAssertion: {
assertions: [],
@ -414,26 +411,8 @@
regexAssertion: {
assertions: [],
},
// TODO
// documentAssertion: {
// jsonAssertion: [
// {
// id: rootId,
// paramsName: 'root',
// mustInclude: false,
// typeChecking: false,
// paramType: 'object',
// matchCondition: '',
// matchValue: '',
// },
// ],
// responseFormat: 'JSON',
// followApi: false,
// },
};
const condition = useVModel(props, 'data', emit);
const extractParamsTableRef = ref<InstanceType<typeof paramsTable>>();
const fastExtractionVisible = ref(false);
const disabledExpressionSuffix = ref(false);
@ -521,7 +500,7 @@
case ResponseBodyAssertionType.JSON_PATH:
condition.value.jsonPathAssertion.assertions = data;
if (!isInit) {
emit('change', { ...condition.value, assertionBodyType: activeTab.value });
emit('change', { ...condition.value });
}
break;
@ -530,7 +509,6 @@
if (!isInit) {
emit('change', {
...condition.value,
assertionBodyType: activeTab.value,
});
}
break;
@ -540,7 +518,7 @@
case ResponseBodyAssertionType.REGEX:
condition.value.regexAssertion.assertions = data;
if (!isInit) {
emit('change', { ...defaultParamItem, ...condition.value, assertionBodyType: activeTab.value });
emit('change', { ...defaultParamItem, ...condition.value });
}
break;
default:
@ -642,6 +620,7 @@
align: 'right',
},
];
const documentDefaultParamItem = {
id: new Date().getTime(),
paramsName: '',
@ -731,7 +710,7 @@
...record,
id: new Date().getTime().toString(),
});
emit('change', { ...condition.value, assertionBodyType: activeTab.value });
// emit('change', { ...condition.value });
}
break;
@ -743,11 +722,9 @@
id: new Date().getTime().toString(),
});
}
emit('change', {
...condition.value,
assertionBodyType: activeTab.value,
responseFormat: activeResponseFormat.value,
});
// emit('change', {
// ...condition.value,
// });
break;
case ResponseBodyAssertionType.DOCUMENT:
condition.value.documentAssertion.jsonAssertion.push({
@ -763,7 +740,7 @@
id: new Date().getTime().toString(),
});
}
emit('change', { ...condition.value, assertionBodyType: activeTab.value });
// emit('change', { ...condition.value});
break;
default:
break;
@ -886,6 +863,7 @@
}
}
};
const handleScriptChange = (data: ExecuteConditionProcessor) => {
condition.value.script = data;
};

View File

@ -6,7 +6,7 @@
height: 'calc(100vh - 490px)',
}"
>
<conditionContent v-model:data="condition" :disabled="disabled" is-build-in @change="handleChange" />
<conditionContent v-model:data="condition" />
</a-scrollbar>
</div>
</template>
@ -26,20 +26,26 @@
interface ScriptTabProps {
data: any;
disabled?: boolean;
// disabled?: boolean;
}
const props = defineProps<ScriptTabProps>();
const emit = defineEmits<{
(e: 'change', val: ScriptItem): void; //
(e: 'update:data'): void; //
}>();
function handleChange() {
// eslint-disable-next-line no-use-before-define
emit('change', { ...condition.value });
}
const condition = useVModel(props, 'data', emit);
// function handleChange() {
// // eslint-disable-next-line no-use-before-define
// emit('update:data');
// emit('change', { ...condition.value });
// }
const currentEnvConfig = ref({});
async function initEnvironment() {
if (store.currentId) {
currentEnvConfig.value = await getEnvironment(store.currentId);
@ -47,6 +53,7 @@
}
/** 向孙组件提供属性 */
provide('currentEnvConfig', readonly(currentEnvConfig));
onBeforeMount(() => {
initEnvironment();
});

View File

@ -26,14 +26,8 @@
</div>
</div>
<div v-if="showBody" class="ms-assertion-body w-full">
<a-scrollbar
:style="{
overflow: 'auto',
height: 'calc(100vh - 458px)',
width: '100%',
}"
>
<VueDraggable v-model="assertions" class="ms-assertion-body-left" ghost-class="ghost" handle=".sort-handle">
<div class="ms-assertion-body-left h-full w-[20%] min-w-[220px]">
<VueDraggable v-model="assertions" ghost-class="ghost" handle=".sort-handle">
<div
v-for="(item, index) in assertions"
:key="item.id"
@ -75,25 +69,32 @@
</div>
</div>
</VueDraggable>
</a-scrollbar>
<section class="ms-assertion-body-right h-full">
</div>
<div
class="ms-assertion-body-right h-full"
:class="{
'p-4': getCurrentItemState.assertionType !== ResponseAssertionType.SCRIPT,
'border border-solid border-[var(--color-text-n8)]':
getCurrentItemState.assertionType !== ResponseAssertionType.SCRIPT,
}"
>
<!-- 响应头 -->
<ResponseHeaderTab
v-if="valueKey === ResponseAssertionType.RESPONSE_HEADER"
v-if="getCurrentItemState.assertionType === ResponseAssertionType.RESPONSE_HEADER"
v-model:data="getCurrentItemState"
:disabled="props.disabled"
@change="handleChange"
/>
<!-- 状态码 -->
<StatusCodeTab
v-if="valueKey === ResponseAssertionType.RESPONSE_CODE"
v-if="getCurrentItemState.assertionType === ResponseAssertionType.RESPONSE_CODE"
v-model:data="getCurrentItemState"
:disabled="props.disabled"
@change="handleChange"
/>
<!-- 响应体 -->
<ResponseBodyTab
v-if="valueKey === ResponseAssertionType.RESPONSE_BODY"
v-if="getCurrentItemState.assertionType === ResponseAssertionType.RESPONSE_BODY"
v-model:data="getCurrentItemState"
:disabled="props.disabled"
:response="props.response"
@ -101,27 +102,26 @@
/>
<!-- 响应时间 -->
<ResponseTimeTab
v-if="valueKey === ResponseAssertionType.RESPONSE_TIME"
v-if="getCurrentItemState.assertionType === ResponseAssertionType.RESPONSE_TIME"
v-model:data="getCurrentItemState"
:disabled="props.disabled"
@change="handleChange"
/>
<!-- 变量 -->
<VariableTab
v-if="valueKey === ResponseAssertionType.VARIABLE"
v-if="getCurrentItemState.assertionType === ResponseAssertionType.VARIABLE"
v-model:data="getCurrentItemState"
:disabled="props.disabled"
@change="handleChange"
/>
<!-- 脚本 -->
<ScriptTab
v-if="valueKey === ResponseAssertionType.SCRIPT"
v-if="getCurrentItemState.assertionType === ResponseAssertionType.SCRIPT"
v-model:data="getCurrentItemState"
:disabled="props.disabled"
@change="handleChange"
/>
<!-- </a-scrollbar> -->
</section>
</div>
</div>
</div>
</template>
@ -159,7 +159,9 @@
// key
const focusKey = ref<string>('');
//
const assertions = defineModel<any[]>('params', { default: [] });
const assertions = defineModel<any[]>('params', {
required: true,
});
const props = defineProps<{
isDefinition?: boolean; //
@ -170,75 +172,16 @@
const emit = defineEmits<{
(e: 'update:assertionConfig', params: ExecuteAssertionConfig): void;
// TODO
(e: 'update:params', params: any[]): void;
(e: 'change'): void;
}>();
const innerConfig = useVModel(props, 'assertionConfig', emit);
// Itemkey
const activeKey = ref<string>('');
// value
const valueKey = computed(() => {
return activeKey.value && assertions.value.find((item) => item.id === activeKey.value)?.assertionType;
});
const defaultResBodyItem = {
jsonPathAssertion: {
assertions: [],
},
xpathAssertion: { responseFormat: 'XML', assertions: [] },
assertionBodyType: '',
regexAssertion: {
assertions: [],
},
// TODO
// documentAssertion: {
// jsonAssertion: [
// {
// id: rootId,
// paramsName: 'root',
// mustInclude: false,
// typeChecking: false,
// paramType: 'object',
// matchCondition: '',
// matchValue: '',
// },
// ],
// responseFormat: 'JSON',
// followApi: false,
// },
};
//
const getCurrentItemState = computed({
get: () => {
const currentResItem =
assertions.value.find((item: any) => item.id === activeKey.value) || assertions.value[0] || {};
if (currentResItem && currentResItem?.assertionType === ResponseAssertionType.RESPONSE_BODY) {
const { jsonPathAssertion, xpathAssertion, regexAssertion } = currentResItem;
return {
...currentResItem,
jsonPathAssertion: jsonPathAssertion || defaultResBodyItem.jsonPathAssertion,
xpathAssertion: xpathAssertion || defaultResBodyItem.xpathAssertion,
assertionBodyType: '',
regexAssertion: regexAssertion || defaultResBodyItem.regexAssertion,
bodyAssertionDataByType: {},
};
}
if (currentResItem && currentResItem?.assertionType === ResponseAssertionType.SCRIPT) {
return {
...currentResItem,
processorType: ResponseAssertionType.SCRIPT,
};
}
return currentResItem;
},
set: (val: ExecuteAssertion) => {
const currentIndex = assertions.value.findIndex((item) => item.id === activeKey.value);
const tmpArr = assertions.value;
tmpArr[currentIndex] = cloneDeep(val);
assertions.value = tmpArr;
},
});
const getCurrentItemState = ref(assertions.value[0]);
const itemMoreActions: ActionsItem[] = [
{
@ -282,6 +225,7 @@
const showBody = computed(() => {
return assertions.value.length > 0;
});
// dropdown
const handleSelect = (value: string | number | Record<string, any> | undefined) => {
const id = new Date().getTime().toString();
@ -363,7 +307,9 @@
default:
break;
}
activeKey.value = id;
getCurrentItemState.value = assertions.value[assertions.value.length - 1];
activeKey.value = assertions.value[assertions.value.length - 1].id;
emit('change');
};
const handleMoreActionSelect = (event: ActionsItem, item: MsAssertionItem) => {
@ -373,10 +319,10 @@
activeKey.value = currentIndex > 0 ? assertions.value[currentIndex - 1].id : '';
} else {
// copy item
const tmpObj = { ...assertions.value[currentIndex], id: new Date().getTime().valueOf().toString() };
const tmpArr = assertions.value;
const tmpObj = { ...cloneDeep(assertions.value[currentIndex]), id: new Date().getTime().valueOf().toString() };
const tmpArr = cloneDeep(assertions.value);
tmpArr.splice(currentIndex, 0, tmpObj);
assertions.value = tmpArr;
assertions.value = cloneDeep(tmpArr);
activeKey.value = tmpObj.id;
}
};
@ -422,24 +368,30 @@
<style lang="less" scoped>
.ms-assertion {
width: 100%;
height: calc(100% - 22px);
&-body {
display: flex;
margin-top: 8px;
height: calc(100% - 42px);
flex-flow: row nowrap;
gap: 8px;
&-left {
display: flex;
overflow-y: auto;
padding: 12px;
width: 216px;
min-width: 216px;
height: 100%;
background-color: var(--color-text-n9);
flex-direction: column;
gap: 4px;
.ms-scroll-bar();
&-item {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
margin: 4px 0;
flex-flow: row nowrap;
padding: 4px 8px;
border-radius: 4px;
background-color: var(--color-text-fff);
@ -483,8 +435,6 @@
&-right {
display: flex;
flex-grow: 1;
padding: 0;
border: 1px solid var(--color-text-n8);
border-radius: 4px;
background: var(--color-text-fff);
}

View File

@ -44,7 +44,7 @@
<div :class="getFolderClass('all')" @click="setActiveFolder('all')">
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
<div class="folder-name">{{ t('caseManagement.featureCase.allCase') }}</div>
<div class="folder-count">({{ modulesCount.total || 0 }})</div>
<div class="folder-count">({{ modulesCount.total || modulesCount.all || 0 }})</div>
</div>
<div class="ml-auto flex items-center">
<a-tooltip

View File

@ -3,9 +3,11 @@
<div v-if="$slots.quickCreate" class="ms-base-table-quickCreate">
<slot name="quickCreate"></slot>
</div>
<!-- 表只做自适应不做可拖拽列 -->
<a-table
v-bind="{ ...$attrs, ...scrollObj }"
:row-class="getRowClass"
:column-resizable="false"
:span-method="spanMethod"
:columns="currentColumns"
:expanded-keys="props.expandedKeys"

View File

@ -31,12 +31,13 @@
<span class="mode-button-title">{{ t('msTable.columnSetting.drawer') }}</span>
</div>
</a-radio>
<a-radio value="new_window">
<!-- TODO 这版本不上新窗口 -->
<!-- <a-radio value="new_window">
<div class="mode-button">
<MsIcon :class="{ 'active-color': currentMode === 'new_window' }" type="icon-icon_into-item_outlined" />
<span class="mode-button-title">{{ t('msTable.columnSetting.newWindow') }}</span>
</div>
</a-radio>
</a-radio> -->
</a-radio-group>
</template>
<template v-if="props.showPagination">

View File

@ -249,6 +249,7 @@ export interface ExecuteConditionProcessorCommon {
associateScenarioResult?: boolean; // 是否关联场景结果
ignoreProtocols: string[]; // 忽略协议
beforeStepScript: boolean; // 是否是步骤内前置脚本前
assertionType?: RequestConditionProcessor;
}
// 执行请求-前后置条件-脚本处理器
export type ScriptProcessor = ScriptCommonConfig & ExecuteConditionProcessorCommon;

View File

@ -5,7 +5,8 @@
v-if="
condition.processorType === RequestConditionProcessor.SCRIPT ||
condition.processorType === RequestConditionProcessor.SCENARIO_SCRIPT ||
condition.processorType === RequestConditionProcessor.REQUEST_SCRIPT
condition.processorType === RequestConditionProcessor.REQUEST_SCRIPT ||
condition?.assertionType === RequestConditionProcessor.SCRIPT
"
>
<!-- 前后置请求开始 -->
@ -645,7 +646,8 @@ if (!result){
() => condition.value.commonScriptInfo,
(info) => {
propsRes.value.data = info?.params as any[]; //
}
},
{ deep: true, immediate: true }
);
const showQuoteDrawer = ref(false);

View File

@ -1,6 +1,12 @@
<template>
<div class="flex h-full flex-col gap-[16px]">
<a-spin class="max-h-[calc(100vh - 454px)] w-full" :loading="loading">
<a-spin class="w-full" :loading="loading">
<!-- 不做虚拟滚动 :virtual-list-props="{
height: `calc(100vh - 454px)`,
threshold: 20,
fixedSize: true,
buffer: 15,
}" -->
<MsTree
ref="treeRef"
v-model:selected-keys="selectedKeys"
@ -8,12 +14,6 @@
v-model:data="steps"
:expand-all="props.expandAll"
:field-names="{ title: 'name', key: 'stepId', children: 'children' }"
:virtual-list-props="{
height: `calc(100vh - 454px)`,
threshold: 20,
fixedSize: true,
buffer: 15,
}"
title-class="step-tree-node-title"
node-highlight-class="step-tree-node-focus"
action-on-node-click="expand"
@ -427,7 +427,4 @@
height: 1px;
background: var(--color-text-n8);
}
:deep(.foldContent .arco-scrollbar-track-direction-vertical) {
left: -12px !important;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<!-- class="tiled-wrap h-[calc(100vh - 374px)] p-4" -->
<div
class="tiled-wrap h-[calc(100vh - 374px)] p-4"
:class="{
'border border-solid border-[var(--color-text-n8)]': props.showType === 'API',
}"

View File

@ -205,7 +205,7 @@
:mouse-enter-delay="100"
mini
>
<div class="one-line-text">{{ getTableFields(record.customFields, item as MsTableColumn) }}</div>
<div class="one-line-text max-w-[300px]">{{ getTableFields(record.customFields, item as MsTableColumn) }}</div>
</a-tooltip>
</template>
<!-- 渲染自定义字段结束 -->
@ -584,6 +584,7 @@
dataIndex: 'tags',
showInTable: true,
isTag: true,
width: 456,
showDrag: true,
},
{

View File

@ -207,12 +207,24 @@
const confirmLoading = ref<boolean>(false);
async function getFetch() {
setLoadListParams({
keyword: keyword.value,
sourceId: props.caseId,
projectId: currentProjectId.value,
sourceType: currentSelectCase.value,
});
await loadList();
featureCaseStore.getCaseCounts(props.caseId);
}
async function saveHandler(params: TableQueryParams) {
try {
confirmLoading.value = true;
await associationPublicCase(params);
Message.success(t('caseManagement.featureCase.AssociatedSuccess'));
innerVisible.value = false;
getFetch();
} catch (error) {
console.log(error);
} finally {
@ -255,17 +267,6 @@
currentSelectCase.value = caseTypeOptions.value[0].value;
}
async function getFetch() {
setLoadListParams({
keyword: keyword.value,
sourceId: props.caseId,
projectId: currentProjectId.value,
sourceType: currentSelectCase.value,
});
await loadList();
featureCaseStore.getCaseCounts(props.caseId);
}
async function cancelLink(record: any) {
try {
await cancelAssociatedCase({

View File

@ -189,6 +189,7 @@
v-model:visible="caseAssociateVisible"
v-model:project="caseAssociateProject"
:reviewers="reviewForm.reviewers"
:associated-ids="selectedAssociateCasesParams.selectIds"
@success="writeAssociateCases"
/>
</template>
@ -424,7 +425,6 @@
loading.value = false;
}
}
onBeforeMount(() => {
initModules();
initReviewers();