fix(接口自动化): 允许引用用例新增步骤
--bug=1007648 --user=赵勇 引用的接口用例无法添加等待时间 https://www.tapd.cn/55049933/s/1062875
This commit is contained in:
parent
128a20245f
commit
70536148e0
|
@ -3,6 +3,9 @@ package io.metersphere.api.dto.definition.request;
|
|||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.metersphere.api.dto.definition.request.controller.MsLoopController;
|
||||
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
|
||||
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
|
||||
|
@ -330,6 +333,8 @@ public class ElementUtil {
|
|||
|
||||
public static void dataSetDomain(JSONArray hashTree, MsParameter msParameter) {
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
for (int i = 0; i < hashTree.size(); i++) {
|
||||
JSONObject element = hashTree.getJSONObject(i);
|
||||
boolean isScenarioEnv = false;
|
||||
|
@ -357,6 +362,13 @@ public class ElementUtil {
|
|||
MsHTTPSamplerProxy httpSamplerProxy = JSON.toJavaObject(element, MsHTTPSamplerProxy.class);
|
||||
if (httpSamplerProxy != null
|
||||
&& (!httpSamplerProxy.isCustomizeReq() || (httpSamplerProxy.isCustomizeReq() && httpSamplerProxy.getIsRefEnvironment()))) {
|
||||
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
||||
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
|
||||
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
|
||||
new TypeReference<LinkedList<MsTestElement>>() {
|
||||
});
|
||||
httpSamplerProxy.setHashTree(elements);
|
||||
}
|
||||
HashTree tmpHashTree = new HashTree();
|
||||
httpSamplerProxy.toHashTree(tmpHashTree, null, msParameter);
|
||||
if (tmpHashTree != null && tmpHashTree.getArray().length > 0) {
|
||||
|
@ -380,4 +392,46 @@ public class ElementUtil {
|
|||
LogUtil.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static void mergeHashTree(List<MsTestElement> sourceHashTree, List<MsTestElement> targetHashTree) {
|
||||
List<String> sourceIds = new ArrayList<>();
|
||||
List<String> delIds = new ArrayList<>();
|
||||
Map<String, MsTestElement> updateMap = new HashMap<>();
|
||||
if (CollectionUtils.isEmpty(sourceHashTree)) {
|
||||
sourceHashTree.addAll(targetHashTree);
|
||||
return;
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(targetHashTree)) {
|
||||
for (MsTestElement item : targetHashTree) {
|
||||
updateMap.put(item.getId(), item);
|
||||
}
|
||||
}
|
||||
// 找出待更新内容和源已经被删除的内容
|
||||
if (CollectionUtils.isNotEmpty(sourceHashTree)) {
|
||||
for (int i = 0; i < sourceHashTree.size(); i++) {
|
||||
MsTestElement source = sourceHashTree.get(i);
|
||||
if (source != null) {
|
||||
sourceIds.add(source.getId());
|
||||
if (!StringUtils.equals(source.getLabel(), "SCENARIO-REF-STEP")) {
|
||||
if (StringUtils.isNotEmpty(source.getId()) && updateMap.containsKey(source.getId())) {
|
||||
sourceHashTree.set(i, updateMap.get(source.getId()));
|
||||
} else {
|
||||
delIds.add(source.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除多余的步骤
|
||||
sourceHashTree.removeIf(item -> item != null && delIds.contains(item.getId()));
|
||||
// 补充新增的源引用步骤
|
||||
if (CollectionUtils.isNotEmpty(targetHashTree)) {
|
||||
for (MsTestElement item : targetHashTree) {
|
||||
if (!sourceIds.contains(item.getId())) {
|
||||
sourceHashTree.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,11 @@ public class MsDubboSampler extends MsTestElement {
|
|||
}
|
||||
}
|
||||
if (proxy != null) {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
if (StringUtils.equals(this.getRefType(), "CASE")) {
|
||||
ElementUtil.mergeHashTree(this.getHashTree(), proxy.getHashTree());
|
||||
} else {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
}
|
||||
this.setMethod(proxy.getMethod());
|
||||
this.set_interface(proxy.get_interface());
|
||||
this.setAttachmentArgs(proxy.getAttachmentArgs());
|
||||
|
|
|
@ -154,7 +154,11 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
}
|
||||
}
|
||||
if (proxy != null) {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
if (StringUtils.equals(this.getRefType(), "CASE")) {
|
||||
ElementUtil.mergeHashTree(this.getHashTree(), proxy.getHashTree());
|
||||
}else {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
}
|
||||
this.setMethod(proxy.getMethod());
|
||||
this.setBody(proxy.getBody());
|
||||
this.setRest(proxy.getRest());
|
||||
|
|
|
@ -230,7 +230,11 @@ public class MsJDBCSampler extends MsTestElement {
|
|||
}
|
||||
}
|
||||
if (proxy != null) {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
if (StringUtils.equals(this.getRefType(), "CASE")) {
|
||||
ElementUtil.mergeHashTree(this.getHashTree(), proxy.getHashTree());
|
||||
} else {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
}
|
||||
this.setDataSource(proxy.getDataSource());
|
||||
this.setDataSourceId(proxy.getDataSourceId());
|
||||
this.setQuery(proxy.getQuery());
|
||||
|
|
|
@ -182,7 +182,11 @@ public class MsTCPSampler extends MsTestElement {
|
|||
}
|
||||
}
|
||||
if (proxy != null) {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
if (StringUtils.equals(this.getRefType(), "CASE")) {
|
||||
ElementUtil.mergeHashTree(this.getHashTree(), proxy.getHashTree());
|
||||
}else {
|
||||
this.setHashTree(proxy.getHashTree());
|
||||
}
|
||||
this.setClassname(proxy.getClassname());
|
||||
this.setServer(proxy.getServer());
|
||||
this.setPort(proxy.getPort());
|
||||
|
|
|
@ -948,7 +948,7 @@ export default {
|
|||
setComponent(type, this, plugin);
|
||||
},
|
||||
nodeClick(data, node) {
|
||||
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled && this.stepFilter) {
|
||||
if ((data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled && this.stepFilter) || data.refType === 'CASE') {
|
||||
this.operatingElements = this.stepFilter.get(data.type);
|
||||
} else {
|
||||
this.operatingElements = [];
|
||||
|
|
|
@ -2,18 +2,16 @@
|
|||
<el-card :style="{'border-color':colorStyle}">
|
||||
<div class="header" @click="active(data)">
|
||||
<slot name="beforeHeaderLeft">
|
||||
<div v-if="data.index" class="el-step__icon is-text" style="margin-right: 10px;" :style="{'color': color, 'background-color': backgroundColor}">
|
||||
<div v-if="data.index" class="el-step__icon is-text enable-switch" :style="{'color': color, 'background-color': backgroundColor}">
|
||||
<div class="el-step__icon-inner">{{ data.index }}</div>
|
||||
</div>
|
||||
<el-tag class="ms-left-btn" size="small" :style="{'color': color, 'background-color': backgroundColor}">{{ title }}</el-tag>
|
||||
<el-tag size="mini" v-if="data.method && !data.pluginId">{{ getMethod() }}</el-tag>
|
||||
</slot>
|
||||
<slot name="behindHeaderLeft" v-if="!isMax"></slot>
|
||||
|
||||
<span>
|
||||
<slot name="headerLeft">
|
||||
<i class="icon el-icon-arrow-right" :class="{'is-active': data.active}"
|
||||
@click="active(data)" v-if="data.type!='scenario' && !isMax " @click.stop/>
|
||||
<i class="icon el-icon-arrow-right" :class="{'is-active': data.active}" @click="active(data)" v-if="data.type!='scenario' && !isMax " @click.stop/>
|
||||
<span @click.stop v-if="isShowInput && isShowNameInput">
|
||||
<el-input :draggable="draggable" size="mini" v-model="data.name" class="name-input" @focus="active(data)"
|
||||
@blur="isShowInput = false" :placeholder="$t('commons.input_name')" ref="nameEdit" :disabled="data.disabled"/>
|
||||
|
|
|
@ -32,10 +32,10 @@
|
|||
</template>
|
||||
<template v-slot:button>
|
||||
<el-tooltip :content="$t('api_test.run')" placement="top" v-if="!loading">
|
||||
<el-button :disabled="!request.enable" @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/>
|
||||
<el-button @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/>
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('report.stop_btn')" placement="top" :enterable="false" v-else>
|
||||
<el-button :disabled="!request.enable" @click.once="stop" size="mini" style="color:white;padding: 0 0.1px;width: 24px;height: 24px;" class="stop-btn" circle>
|
||||
<el-button @click.once="stop" size="mini" style="color:white;padding: 0 0.1px;width: 24px;height: 24px;" class="stop-btn" circle>
|
||||
<div style="transform: scale(0.66)">
|
||||
<span style="margin-left: -4.5px;font-weight: bold;">STOP</span>
|
||||
</div>
|
||||
|
@ -371,18 +371,15 @@ export default {
|
|||
getApiInfo() {
|
||||
if (this.request.id && this.request.referenced === 'REF') {
|
||||
let requestResult = this.request.requestResult;
|
||||
let url = this.request.refType && this.request.refType === 'CASE' ? "/api/testcase/get/" : "/api/definition/get/";
|
||||
let enable = this.request.enable;
|
||||
this.$get(url + this.request.id, response => {
|
||||
this.$get("/api/testcase/get/" + this.request.id, response => {
|
||||
if (response.data) {
|
||||
Object.assign(this.request, JSON.parse(response.data.request));
|
||||
this.request.name = response.data.name;
|
||||
this.request.referenced = "REF";
|
||||
this.request.enable = enable;
|
||||
if (response.data.path && response.data.path != null) {
|
||||
this.request.path = response.data.path;
|
||||
this.request.url = response.data.url;
|
||||
this.setUrl(this.request.path);
|
||||
}
|
||||
if (response.data.method && response.data.method != null) {
|
||||
this.request.method = response.data.method;
|
||||
|
@ -396,6 +393,10 @@ export default {
|
|||
this.request.disabled = true;
|
||||
this.request.root = true;
|
||||
this.request.projectId = response.data.projectId;
|
||||
let req = JSON.parse(response.data.request);
|
||||
if (req && this.request) {
|
||||
this.mergeHashTree(req.hashTree);
|
||||
}
|
||||
this.reload();
|
||||
this.sort();
|
||||
} else {
|
||||
|
@ -404,22 +405,67 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
sort(arr) {
|
||||
if (!arr) {
|
||||
arr = this.request.hashTree;
|
||||
}
|
||||
for (let i in arr) {
|
||||
arr[i].disabled = true;
|
||||
arr[i].index = Number(i) + 1;
|
||||
if (!arr[i].resourceId) {
|
||||
arr[i].resourceId = getUUID();
|
||||
mergeHashTree(targetHashTree) {
|
||||
let sourceHashTree = this.request.hashTree;
|
||||
let sourceIds = [];
|
||||
let delIds = [];
|
||||
let updateMap = new Map();
|
||||
if (!sourceHashTree || sourceHashTree.length == 0) {
|
||||
if (targetHashTree) {
|
||||
targetHashTree.forEach(item => {
|
||||
item.disabled = true;
|
||||
})
|
||||
this.request.hashTree = targetHashTree;
|
||||
}
|
||||
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
|
||||
this.sort(arr[i].hashTree);
|
||||
return;
|
||||
}
|
||||
if (targetHashTree) {
|
||||
for(let i in targetHashTree){
|
||||
targetHashTree[i].disabled = true;
|
||||
updateMap.set(targetHashTree[i].id, targetHashTree[i]);
|
||||
}
|
||||
}
|
||||
if (sourceHashTree && sourceHashTree.length > 0) {
|
||||
for (let index in sourceHashTree) {
|
||||
let source = sourceHashTree[index];
|
||||
sourceIds.push(source.id);
|
||||
if (source.label !== 'SCENARIO-REF-STEP') {
|
||||
if (source.id && updateMap.has(source.id)) {
|
||||
Object.assign(sourceHashTree[index] , updateMap.get(source.id));
|
||||
sourceHashTree[index].disabled = true;
|
||||
sourceHashTree[index].label = '';
|
||||
sourceHashTree[index].enable = updateMap.get(source.id).enable;
|
||||
} else {
|
||||
delIds.push(source.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 删除多余的步骤
|
||||
delIds.forEach(item => {
|
||||
const removeIndex = sourceHashTree.findIndex(d => d.id && d.id === item);
|
||||
sourceHashTree.splice(removeIndex, 1);
|
||||
})
|
||||
|
||||
// 补充新增的源引用步骤
|
||||
if (targetHashTree) {
|
||||
targetHashTree.forEach(item => {
|
||||
if (sourceIds.indexOf(item.id) === -1) {
|
||||
item.disabled = true;
|
||||
this.request.hashTree.push(item);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
sort() {
|
||||
for (let i in this.request.hashTree) {
|
||||
this.request.hashTree[i].index = Number(i) + 1;
|
||||
if (!this.request.hashTree[i].resourceId) {
|
||||
this.request.hashTree[i].resourceId = getUUID();
|
||||
}
|
||||
}
|
||||
},
|
||||
active(item) {
|
||||
active() {
|
||||
this.request.active = !this.request.active;
|
||||
if (this.node) {
|
||||
this.node.expanded = this.request.active;
|
||||
|
|
|
@ -152,35 +152,35 @@ export function setComponent(type, _this, plugin) {
|
|||
_this.scenarioDefinition.push(new IfController());
|
||||
break;
|
||||
case ELEMENT_TYPE.ConstantTimer:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new ConstantTimer()) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new ConstantTimer({label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new ConstantTimer());
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223Processor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor()) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor({label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new JSR223Processor());
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223PreProcessor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PreProcessor"})) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PreProcessor",label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PreProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.JSR223PostProcessor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PostProcessor"})) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PostProcessor",label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PostProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.JDBCPreProcessor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JDBCProcessor({type: "JDBCPreProcessor"})) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JDBCProcessor({type: "JDBCPreProcessor",label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new JDBCProcessor({type: "JDBCPreProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.JDBCPostProcessor:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JDBCProcessor({type: "JDBCPostProcessor"})) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new JDBCProcessor({type: "JDBCPostProcessor",label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new JDBCProcessor({type: "JDBCPostProcessor"}));
|
||||
break;
|
||||
case ELEMENT_TYPE.Assertions:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new Assertions()) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new Assertions({label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new Assertions());
|
||||
break;
|
||||
case ELEMENT_TYPE.Extract:
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new Extract()) :
|
||||
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new Extract({label: "SCENARIO-REF-STEP"})) :
|
||||
_this.scenarioDefinition.push(new Extract());
|
||||
break;
|
||||
case ELEMENT_TYPE.CustomizeReq:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<script>
|
||||
import {createComponent} from "../../jmeter/components";
|
||||
import {Assertions, Extract} from "../../../model/ApiTestModel";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "ApiDefinitionStepButton",
|
||||
|
@ -58,14 +59,14 @@
|
|||
this.request.hashTree.push(jdbcPostProcessor);
|
||||
},
|
||||
addAssertions() {
|
||||
let assertions = new Assertions();
|
||||
let assertions = new Assertions({id:getUUID()});
|
||||
if (!this.request.hashTree) {
|
||||
this.request.hashTree = [];
|
||||
}
|
||||
this.request.hashTree.push(assertions);
|
||||
},
|
||||
addExtract() {
|
||||
let jsonPostProcessor = new Extract();
|
||||
let jsonPostProcessor = new Extract({id:getUUID()});
|
||||
if (!this.request.hashTree) {
|
||||
this.request.hashTree = [];
|
||||
}
|
||||
|
|
|
@ -846,6 +846,7 @@ export class JSR223Processor extends BaseConfig {
|
|||
this.resourceId = uuid();
|
||||
this.active = false;
|
||||
this.type = "JSR223Processor";
|
||||
this.label="";
|
||||
this.script = undefined;
|
||||
this.scriptLanguage = "beanshell";
|
||||
this.enable = true;
|
||||
|
|
Loading…
Reference in New Issue