refactor(接口测试): 响应内容增加断言和提取

This commit is contained in:
wxg0103 2024-03-14 18:22:33 +08:00 committed by Craftsman
parent 0c49a5d4c1
commit 8464a2e39d
12 changed files with 63 additions and 63 deletions

View File

@ -14,15 +14,7 @@
<select id="list" resultType="io.metersphere.api.domain.ApiReport">
select
api_report.id,
api_report.name,
api_report.integrated,
api_report.status,
api_report.start_time,
api_report.update_time,
api_report.create_user,
api_report.update_user,
api_report.trigger_mode
api_report.*
from api_report where api_report.deleted = false
and api_report.test_plan_id = 'NONE'
<if test="request.keyword != null and request.keyword != ''">

View File

@ -14,15 +14,7 @@
<select id="list" resultType="io.metersphere.api.domain.ApiScenarioReport">
select
api_scenario_report.id,
api_scenario_report.name,
api_scenario_report.integrated,
api_scenario_report.status,
api_scenario_report.start_time,
api_scenario_report.update_time,
api_scenario_report.create_user,
api_scenario_report.update_user,
api_scenario_report.trigger_mode
api_scenario_report.*
from api_scenario_report where api_scenario_report.deleted = false
and api_scenario_report.test_plan_id = 'NONE'
<if test="request.keyword != null and request.keyword != ''">

View File

@ -757,15 +757,15 @@ public class ApiScenarioControllerTests extends BaseTest {
private ScenarioVariable getScenarioVariable() {
ScenarioVariable scenarioVariable = new ScenarioVariable();
CommonVariables commonVariables1 = new CommonVariables();
commonVariables1.setType(VariableTypeConstants.CONSTANT.name());
commonVariables1.setParamType(VariableTypeConstants.CONSTANT.name());
commonVariables1.setKey("a");
commonVariables1.setValue("b");
CommonVariables commonVariables2 = new CommonVariables();
commonVariables2.setType(VariableTypeConstants.CONSTANT.name());
commonVariables2.setParamType(VariableTypeConstants.CONSTANT.name());
commonVariables2.setKey("b");
commonVariables2.setValue("c");
CommonVariables commonVariables3 = new CommonVariables();
commonVariables3.setType(VariableTypeConstants.LIST.name());
commonVariables3.setParamType(VariableTypeConstants.LIST.name());
commonVariables3.setKey("list1");
commonVariables3.setValue("1,2,3");
scenarioVariable.setCommonVariables(List.of(commonVariables1, commonVariables2, commonVariables3));

View File

@ -66,15 +66,15 @@ public class BaseEnvTestService {
environmentConfig.setDataSources(List.of(dataSource));
CommonVariables commonVariables1 = new CommonVariables();
commonVariables1.setType(VariableTypeConstants.CONSTANT.name());
commonVariables1.setParamType(VariableTypeConstants.CONSTANT.name());
commonVariables1.setKey("a");
commonVariables1.setValue("c");
CommonVariables commonVariables2 = new CommonVariables();
commonVariables2.setType(VariableTypeConstants.CONSTANT.name());
commonVariables2.setParamType(VariableTypeConstants.CONSTANT.name());
commonVariables2.setKey("q");
commonVariables2.setValue("qq");
CommonVariables commonVariables3 = new CommonVariables();
commonVariables3.setType(VariableTypeConstants.LIST.name());
commonVariables3.setParamType(VariableTypeConstants.LIST.name());
commonVariables3.setKey("list1");
commonVariables3.setValue("1,2,3,5");
environmentConfig.setCommonVariables(List.of(commonVariables1, commonVariables2, commonVariables3));

View File

@ -19,7 +19,7 @@ public class CommonVariables implements Serializable {
@Schema(description = "变量名")
private String key;
@Schema(description = "变量类型 CONSTANT LIST JSON")
private String type = VariableTypeConstants.CONSTANT.name();
private String paramType = VariableTypeConstants.CONSTANT.name();
@Schema(description = "变量值")
private String value;
@Schema(description = "状态")
@ -32,17 +32,17 @@ public class CommonVariables implements Serializable {
@JsonIgnore
public boolean isConstantValid() {
return StringUtils.equals(this.type, VariableTypeConstants.CONSTANT.name()) && StringUtils.isNotEmpty(key);
return StringUtils.equals(this.paramType, VariableTypeConstants.CONSTANT.name()) && StringUtils.isNotEmpty(key);
}
@JsonIgnore
public boolean isListValid() {
return StringUtils.equals(this.type, VariableTypeConstants.LIST.name()) && StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value) && value.indexOf(",") != -1;
return StringUtils.equals(this.paramType, VariableTypeConstants.LIST.name()) && StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value) && value.indexOf(",") != -1;
}
@JsonIgnore
public boolean isJsonValid() {
return StringUtils.equals(this.type, VariableTypeConstants.JSON.name()) && StringUtils.isNotEmpty(key);
return StringUtils.equals(this.paramType, VariableTypeConstants.JSON.name()) && StringUtils.isNotEmpty(key);
}
}

View File

@ -130,7 +130,7 @@ public class GlobalParamsControllerTests extends BaseTest {
envVariable.setValue("value" + i);
envVariable.setDescription("desc" + i);
envVariable.setTags(List.of("tag" + i));
envVariable.setType(VariableTypeConstants.CONSTANT.name());
envVariable.setParamType(VariableTypeConstants.CONSTANT.name());
commonVariables.add(envVariable);
}
return commonVariables;

View File

@ -396,6 +396,8 @@ export interface ResponseResult {
sslHandshakeTime: number;
tcpHandshakeTime: number;
transferStartTime: number;
vars: string;
assertions: any;
}
export interface RequestResult {
body: string;

View File

@ -126,6 +126,8 @@ export const defaultResponse: RequestTaskResult = {
tcpHandshakeTime: 0,
transferStartTime: 0,
sslHandshakeTime: 0,
vars: '',
assertions: [],
},
},
],

View File

@ -51,8 +51,8 @@
</div>
<MsBaseTable v-else-if="activeTab === 'ASSERTION'" v-bind="propsRes" v-on="propsEvent">
<template #status="{ record }">
<MsTag :type="record.status === 1 ? 'success' : 'danger'" theme="light">
{{ record.status === 1 ? t('common.success') : t('common.fail') }}
<MsTag :type="record.pass === true ? 'success' : 'danger'" theme="light">
{{ record.pass === true ? t('common.success') : t('common.fail') }}
</MsTag>
</template>
</MsBaseTable>
@ -127,14 +127,14 @@
label: t('apiTestDebug.console'),
value: ResponseComposition.CONSOLE,
},
// {
// label: t('apiTestDebug.extract'),
// value: ResponseComposition.EXTRACT,
// },
// {
// label: t('apiTestDebug.assertion'),
// value: ResponseComposition.ASSERTION,
// }, // TODO:
{
label: t('apiTestDebug.extract'),
value: ResponseComposition.EXTRACT,
},
{
label: t('apiTestDebug.assertion'),
value: ResponseComposition.ASSERTION,
},
];
const activeTab = defineModel<ResponseComposition>('activeTab', {
required: true,
@ -179,10 +179,8 @@
props.requestResult.headers
}\nBody:\n${props.requestResult.body.trim()}`
: '';
// case ResponseComposition.EXTRACT:
// return Object.keys(props.request.response.extract)
// .map((e) => `${e}: ${props.request.response.extract[e]}`)
// .join('\n'); // TODO:
case ResponseComposition.EXTRACT:
return props.requestResult?.responseResult?.vars?.trim();
default:
return '';
}
@ -196,34 +194,32 @@
},
{
title: 'apiTestDebug.status',
dataIndex: 'status',
dataIndex: 'pass',
slotName: 'status',
width: 80,
},
{
title: '',
dataIndex: 'desc',
title: 'apiTestDebug.reason',
dataIndex: 'message',
showTooltip: true,
},
];
const { propsRes, propsEvent } = useTable(() => Promise.resolve([]), {
const { propsRes, propsEvent } = useTable(undefined, {
scroll: { x: '100%' },
columns,
});
propsRes.value.data = [
{
id: new Date().getTime(),
content: 'Response Code equals: 200',
status: 1,
desc: '',
watch(
() => props.requestResult?.responseResult.assertions,
(val) => {
if (val) {
propsRes.value.data = props.requestResult?.responseResult.assertions || [];
}
},
{
id: new Date().getTime(),
content: '$.users[1].age REGEX: 31',
status: 0,
desc: `Value expected to match regexp '31', but it did not match: '30' match: '30'`,
},
] as any;
immediate: true,
}
);
</script>
<style lang="less" scoped>
@ -231,7 +227,7 @@
margin-top: 8px;
height: calc(100% - 48px);
.response-header-pre {
@apply h-full overflow-auto bg-white;
@apply h-full overflow-auto bg-white;
.ms-scroll-bar();
padding: 8px 12px;

View File

@ -34,7 +34,7 @@
:all-names="rootModulesName"
parent-id="NONE"
:add-module-api="addDebugModule"
@add-finish="initModules"
@add-finish="handleAddFinish"
>
<MsButton type="icon" class="!mr-0 p-[2px]">
<MsIcon
@ -119,7 +119,7 @@
:parent-id="nodeData.id"
:add-module-api="addDebugModule"
@close="resetFocusNodeKey"
@add-finish="() => initModules()"
@add-finish="handleAddFinish"
>
<MsButton type="icon" size="mini" class="ms-tree-node-extra__btn !mr-0" @click="setFocusNodeKey(nodeData)">
<MsIcon type="icon-icon_add_outlined" size="14" class="text-[var(--color-text-4)]" />
@ -167,7 +167,15 @@
isExpandAll?: boolean; //
activeNodeId?: string | number; // id
}>();
const emit = defineEmits(['init', 'clickApiNode', 'newApi', 'import', 'renameFinish', 'deleteFinish']);
const emit = defineEmits([
'init',
'clickApiNode',
'newApi',
'import',
'renameFinish',
'deleteFinish',
'updateApiNode',
]);
const appStore = useAppStore();
const { t } = useI18n();
@ -422,6 +430,7 @@
targetId: dropNode.type === 'MODULE' ? dragNode.id : dropNode.id,
moduleId: dropNode.type === 'API' ? dropNode.parentId : dropNode.id, // APIidid
});
emit('updateApiNode', { ...dragNode, moduleId: dropNode.type === 'API' ? dropNode.parentId : dropNode.id });
}
Message.success(t('apiTestDebug.moduleMoveSuccess'));
} catch (error) {
@ -434,6 +443,11 @@
}
}
async function handleAddFinish() {
await initModules();
initModuleCount();
}
function moreActionsClose() {
if (!renamePopVisible.value) {
// key

View File

@ -180,6 +180,7 @@ export default {
'apiTestDebug.resourcePool': 'Resource pool',
'apiTestDebug.content': 'Content',
'apiTestDebug.status': 'Status',
'apiTestDebug.reason': 'Reason',
'apiTestDebug.requestName': 'Request name',
'apiTestDebug.requestNameRequired': 'Request name cannot be empty',
'apiTestDebug.requestNamePlaceholder': 'Please enter a request name',

View File

@ -169,6 +169,7 @@ export default {
'apiTestDebug.resourcePool': '资源池',
'apiTestDebug.content': '内容',
'apiTestDebug.status': '状态',
'apiTestDebug.reason': '原因',
'apiTestDebug.requestName': '请求名称',
'apiTestDebug.requestNameRequired': '请求名称不能为空',
'apiTestDebug.requestNamePlaceholder': '请输入请求名称',