refactor(接口测试): TCP请求的请求体改为json,xml,raw格式;场景增加批量创建性能测试按钮

TCP请求的请求体改为json,xml,raw格式;场景增加批量创建性能测试按钮
This commit is contained in:
song-tianyang 2021-06-23 15:44:40 +08:00 committed by 刘瑞斌
parent c79c753654
commit 929d3ae465
24 changed files with 1295 additions and 37 deletions

View File

@ -298,9 +298,7 @@ public class APITestController {
long taskCountInThisWeek = scheduleService.countTaskByProjectIdInThisWeek(projectId);
apiCountResult.setThisWeekAddedCount(taskCountInThisWeek);
// long api_executedInThisWeekCountNumber = apiReportService.countByProjectIdAndCreateInThisWeek(projectId);
long executedInThisWeekCountNumber = apiScenarioReportService.countByProjectIdAndCreateAndByScheduleInThisWeek(projectId);
// long executedInThisWeekCountNumber = api_executedInThisWeekCountNumber+scene_executedInThisWeekCountNumber;
apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber);
//统计 失败 成功 以及总数

View File

@ -242,6 +242,11 @@ public class ApiAutomationController {
return apiAutomationService.genPerformanceTestJmx(runRequest);
}
@PostMapping("/batchGenPerformanceTestJmx")
public List<JmxInfoDTO> batchGenPerformanceTestJmx(@RequestBody ApiScenarioBatchRequest request) {
return apiAutomationService.batchGenPerformanceTestJmx(request);
}
@PostMapping("/file/download")
public ResponseEntity<byte[]> download(@RequestBody FileOperationRequest fileOperationRequest) {
byte[] bytes = apiAutomationService.loadFileAsBytes(fileOperationRequest);

View File

@ -13,9 +13,15 @@ import java.util.Map;
*/
@Getter
@Setter
@AllArgsConstructor
public class JmxInfoDTO {
private String name;
private String xml;
private String id;
private Map<String, String> attachFiles;
public JmxInfoDTO(String name,String xml,Map<String, String> attachFiles){
this.name = name;
this.xml = xml;
this.attachFiles = attachFiles;
}
}

View File

@ -0,0 +1,180 @@
package io.metersphere.api.dto.automation;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* //ESB数据格式
*
* @author song.tianyang
* @Date 2021/3/15 4:37 下午
* @Description
*/
@Getter
@Setter
public class TcpTreeTableDataStruct {
private String uuid;
private String name;
private String value;
private String type;
private String systemName;
private String contentType;
private boolean required;
private String description;
private List<TcpTreeTableDataStruct> children;
private String status = "";
public void init(){
this.uuid = UUID.randomUUID().toString();
this.systemName = "";
this.description = "";
this.value="";
this.required = true;
this.contentType = "";
this.type = "";
this.children = new ArrayList<>();
}
public boolean initDefaultData(String name, String typeLength,String chineseName,String desc){
this.init();
if(StringUtils.isEmpty(name)){return false; }
if(typeLength == null){
typeLength = "";
}else{
typeLength = typeLength.trim();
typeLength = typeLength.toLowerCase();
}
this.name = name;
if(typeLength.startsWith("string")){
this.type = "string";
String lengthStr = typeLength.substring(6);
if(lengthStr.startsWith("(") && lengthStr.endsWith(")")){
try {
int length = Integer.parseInt(lengthStr.substring(1,lengthStr.length()-1));
this.contentType = String.valueOf(length);
}catch (Exception e){ }
}
}else if(typeLength.startsWith("array")){
this.type = "array";
}else{
this.type = "object";
}
if(StringUtils.isEmpty(desc)){desc = "";}
if(StringUtils.isNotEmpty(chineseName)){
this.description = chineseName+":"+desc;
}else{
this.description =desc;
}
if(this.description.endsWith(":")){
this.description = this.description.substring(0,this.description.length()-1);
}
return true;
}
public TcpTreeTableDataStruct copy(boolean copyChildren) {
TcpTreeTableDataStruct returnObj = new TcpTreeTableDataStruct();
returnObj.name = this.name;
returnObj.value = this.value;
returnObj.type = this.type;
returnObj.systemName = this.systemName;
returnObj.contentType = this.contentType;
returnObj.required = this.required;
returnObj.description = this.description;
if (copyChildren) {
returnObj.children = this.children;
} else {
returnObj.children = new ArrayList<>();
}
return returnObj;
}
public Element genXmlElementByChildren(Element document) {
this.name = this.name.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
.replace("\"", "&quot;").replace("©", "&apos;");
if (StringUtils.isEmpty(this.name)) {
return null;
}
Element element = null;
try {
element = document.addElement(this.name);
if (StringUtils.equalsAnyIgnoreCase(type, "string", "array")) {
long lengthNum = Long.parseLong(this.contentType);
String attrString = "";
if (StringUtils.equalsIgnoreCase(this.type, "string")) {
attrString = "s," + contentType;
} else if (StringUtils.equalsIgnoreCase(this.type, "array")) {
attrString = "a," + contentType;
}
element.addAttribute("attr", attrString);
}
} catch (Exception e) {
System.out.println(this.name);
e.printStackTrace();
}
if (element != null) {
if (this.children == null || this.children.isEmpty()) {
if(this.value == null ){
this.value = "";
}
element.addText(this.value);
} else {
for (TcpTreeTableDataStruct child : children) {
child.genXmlElementByChildren(element);
}
}
}
return element;
}
public Element genXmlElementByDocument(Document document) {
this.name = this.name.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
.replace("\"", "&quot;").replace("©", "&apos;");
if (StringUtils.isEmpty(this.name)) {
return null;
}
Element element = null;
try {
element = document.addElement(this.name);
if (StringUtils.equalsAnyIgnoreCase(type, "string", "array")) {
long lengthNum = Long.parseLong(this.contentType);
String attrString = "";
if (StringUtils.equalsIgnoreCase(this.type, "string")) {
attrString = "s," + contentType;
} else if (StringUtils.equalsIgnoreCase(this.type, "array")) {
attrString = "a," + contentType;
}
element.addAttribute("attr", attrString);
}
} catch (Exception e) {
System.out.println(this.name);
e.printStackTrace();
}
if (element != null) {
if (this.children == null || this.children.isEmpty()) {
element.addText(this.value);
} else {
for (TcpTreeTableDataStruct child : children) {
child.genXmlElementByChildren(element);
}
}
}
return element;
}
}

View File

@ -0,0 +1,79 @@
package io.metersphere.api.dto.automation.parse;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
/**
* @author song.tianyang
* @Date 2021/3/15 5:00 下午
* @Description
*/
public class TcpTreeTableDataParser {
public static String treeTableData2Xml(List<TcpTreeTableDataStruct> treeDataList) {
String xmlString = "";
try {
if (treeDataList == null || treeDataList.isEmpty()) {
return xmlString;
}
// 创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = factory.newDocumentBuilder();
Document document = DocumentHelper.createDocument();
TcpTreeTableDataStruct dataStruct = null;
if(treeDataList.size()>1){
dataStruct = new TcpTreeTableDataStruct();
dataStruct.setName("ROOT");
dataStruct.setChildren(treeDataList);
}else {
dataStruct = treeDataList.get(0);
}
dataStruct.genXmlElementByDocument(document);
xmlString = document.getRootElement().asXML();
// 设置XML文档格式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
// 设置XML编码方式,即是用指定的编码方式保存XML文档到字符串(String),这里也可以指定为GBK或是ISO8859-1
outputFormat.setEncoding("UTF-8");
//outputFormat.setSuppressDeclaration(true); //是否生产xml头
outputFormat.setIndent(true); //设置是否缩进
outputFormat.setNewlines(true); //设置是否换行
try {
// stringWriter字符串是用来保存XML文档的
StringWriter stringWriter = new StringWriter();
// xmlWriter是用来把XML文档写入字符串的(工具)
XMLWriter xmlWriter = new XMLWriter(stringWriter, outputFormat);
// 把创建好的XML文档写入字符串
xmlWriter.write(document);
// 打印字符串,即是XML文档
xmlString = stringWriter.toString();
xmlWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
if (StringUtils.isEmpty(xmlString)) {
xmlString = "";
} else {
xmlString = xmlString.replaceAll(" ", "");
}
return xmlString;
}
}

View File

@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
@ -88,6 +89,14 @@ public class MsTCPSampler extends MsTestElement {
private String projectId;
@JSONField(ordinal = 40)
private String connectEncoding;
@JSONField(ordinal = 41)
private String reportType;
@JSONField(ordinal = 42)
private List<TcpTreeTableDataStruct> xmlDataStruct;
@JSONField(ordinal = 43)
private String jsonDataStruct;
@JSONField(ordinal = 44)
private String rawDataStruct;
/**

View File

@ -466,7 +466,6 @@ public class APITestService {
/**
* 更新jmx数据处理jmx里的各种参数
* <p>
* 与1.7分支合并时如果该方法产生冲突请以master为准
*
* @param jmxString 原JMX文件
* @param testNameParam 某些节点要替换的testName
@ -475,7 +474,6 @@ public class APITestService {
* @author song tianyang
*/
public JmxInfoDTO updateJmxString(String jmxString, String testNameParam, boolean isFromScenario) {
// 与1.7分支合并时如果该方法产生冲突请以master为准
String attribute_testName = "testname";
String[] requestElementNameArr = new String[]{"HTTPSamplerProxy", "TCPSampler", "JDBCSampler", "DubboSample"};

View File

@ -125,6 +125,8 @@ public class ApiAutomationService {
private ProjectMapper projectMapper;
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private TcpApiParamService tcpApiParamService;
public ApiScenarioWithBLOBs getDto(String id) {
return apiScenarioMapper.selectByPrimaryKey(id);
@ -320,6 +322,8 @@ public class ApiAutomationService {
//检查场景的请求步骤如果含有ESB请求步骤的话要做参数计算处理
esbApiParamService.checkScenarioRequests(request);
//如果场景有TCP步骤的话也要做参数计算处理
tcpApiParamService.checkTestElement(request.getScenarioDefinition());
final ApiScenarioWithBLOBs scenario = buildSaveScenario(request);
@ -1346,21 +1350,9 @@ public class ApiAutomationService {
return request.getId();
}
private void preduceTestElement(RunDefinitionRequest request) throws Exception {
public void preduceTestElement(RunDefinitionRequest request) throws Exception {
if (request.getTestElement() != null) {
for (MsTestElement threadGroup : request.getTestElement().getHashTree()) {
if (threadGroup instanceof MsThreadGroup && threadGroup.getHashTree() != null) {
for (MsTestElement scenario : threadGroup.getHashTree()) {
if (scenario instanceof MsScenario && scenario.getHashTree() != null) {
for (MsTestElement itemElement : scenario.getHashTree()) {
if (itemElement instanceof MsScenario) {
itemElement.setId(UUID.randomUUID().toString());
}
}
}
}
}
}
tcpApiParamService.checkTestElement(request.getTestElement());
}
}
@ -1548,8 +1540,10 @@ public class ApiAutomationService {
List<String> ids = request.getIds();
apiScenarios = extApiScenarioMapper.selectIds(ids);
String testName = "";
String id = "";
if (!apiScenarios.isEmpty()) {
testName = apiScenarios.get(0).getName();
id = apiScenarios.get(0).getId();
}
if (CollectionUtils.isEmpty(apiScenarios)) {
return null;
@ -1560,6 +1554,7 @@ public class ApiAutomationService {
String name = request.getName() + ".jmx";
dto.setName(name);
dto.setId(id);
return dto;
}
@ -2117,4 +2112,28 @@ public class ApiAutomationService {
}
}
public List<JmxInfoDTO> batchGenPerformanceTestJmx(ApiScenarioBatchRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query));
List<JmxInfoDTO> returnList = new ArrayList<>();
List<String> ids = request.getIds();
List<ApiScenarioWithBLOBs> apiScenarioList = extApiScenarioMapper.selectIds(ids);
if (CollectionUtils.isEmpty(apiScenarioList)) {
return returnList;
}else {
apiScenarioList.forEach(item ->{
String testName = item.getName();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
JmxInfoDTO dto = apiTestService.updateJmxString(generateJmx(item), testName, true);
String name = item.getName() + ".jmx";
dto.setId(item.getId());
dto.setName(name);
returnList.add(dto);
});
return returnList;
}
}
}

View File

@ -100,6 +100,8 @@ public class ApiDefinitionService {
@Resource
private EsbApiParamService esbApiParamService;
@Resource
private TcpApiParamService tcpApiParamService;
@Resource
private ApiModuleMapper apiModuleMapper;
@Resource
private SystemParameterService systemParameterService;
@ -277,6 +279,8 @@ public class ApiDefinitionService {
if (StringUtils.equals(request.getMethod(), "ESB")) {
//ESB的接口类型数据采用TCP方式去发送并将方法类型改为TCP 并修改发送数据
request = esbApiParamService.handleEsbRequest(request);
}else if(StringUtils.equals(request.getMethod(), "TCP")) {
request = tcpApiParamService.handleTcpRequest(request);
}
final ApiDefinitionWithBLOBs test = new ApiDefinitionWithBLOBs();
test.setId(request.getId());
@ -581,6 +585,13 @@ public class ApiDefinitionService {
});
}
try{
//检查TCP数据结构等其他进行处理
tcpApiParamService.checkTestElement(request.getTestElement());
}catch (Exception e){
}
HashTree hashTree = request.getTestElement().generateHashTree(config);
String runMode = ApiRunMode.DEFINITION.name();
if (StringUtils.isNotBlank(request.getType()) && StringUtils.equals(request.getType(), ApiRunMode.API_PLAN.name())) {

View File

@ -0,0 +1,80 @@
package io.metersphere.api.service;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.automation.parse.TcpTreeTableDataParser;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.UUID;
/**
* @author song.tianyang
* @Date 2021/3/16 4:57 下午
* @Description
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class TcpApiParamService {
public SaveApiDefinitionRequest handleTcpRequest(SaveApiDefinitionRequest request) {
MsTCPSampler tcpSampler = this.handleTcpRequest(request.getRequest());
if(tcpSampler != null){
request.setRequest(tcpSampler);
}
return request;
}
public MsTCPSampler handleTcpRequest(MsTestElement testElement){
MsTCPSampler tcpSampler = null;
try {
if(testElement instanceof MsTCPSampler){
tcpSampler = (MsTCPSampler)testElement;
String reportType = tcpSampler.getReportType();
if (StringUtils.isNotEmpty(reportType)) {
switch (reportType) {
case "raw":
tcpSampler.setRequest(tcpSampler.getRawDataStruct());
break;
case "xml":
String xmlDataStruct = this.genValueFromEsbDataStructByParam(tcpSampler.getXmlDataStruct());
tcpSampler.setRequest(xmlDataStruct);
break;
case "json":
tcpSampler.setRequest(tcpSampler.getJsonDataStruct());
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return tcpSampler;
}
//通过报文模版中的变量参数解析报文数据结构生成对应的xml数据
private String genValueFromEsbDataStructByParam(List<TcpTreeTableDataStruct> dataStructRequestList) {
String returnValue = TcpTreeTableDataParser.treeTableData2Xml(dataStructRequestList);
return returnValue;
}
public void checkTestElement(MsTestElement testElement) {
if(testElement != null){
if(testElement instanceof MsTCPSampler){
this.handleTcpRequest(testElement);
}else if (testElement instanceof MsScenario) {
testElement.setId(UUID.randomUUID().toString());
}
if(testElement.getHashTree() != null){
for (MsTestElement itemElement : testElement.getHashTree()) {
this.checkTestElement(itemElement);
}
}
}
}
}

View File

@ -709,6 +709,11 @@
"name": "创建性能测试",
"resourceId": "PROJECT_API_SCENARIO"
},
{
"id": "PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH",
"name": "批量创建性能测试",
"resourceId": "PROJECT_API_SCENARIO"
},
{
"id": "PROJECT_API_REPORT:READ",
"name": "查询报告",

View File

@ -368,6 +368,11 @@ export default {
handleClick: this.handleBatchEdit,
permissions: ['PROJECT_API_SCENARIO:READ+EDIT']
},
{
name: this.$t('api_test.create_performance_test_batch'),
handleClick: this.batchCreatePerformance,
permissions: ['PROJECT_API_SCENARIO:READ+CREATE_PERFORMANCE_BATCH']
},
{
name: this.$t('test_track.case.batch_move_case'),
handleClick: this.handleBatchMove,
@ -821,7 +826,39 @@ export default {
},
callBackSelect(selection){
this.$emit('selection', selection);
}
},
batchCreatePerformance() {
this.$alert(this.$t('api_test.definition.request.batch_to_performance_confirm') + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.infoDb = false;
let param = {};
this.buildBatchParam(param);
this.$post('/api/automation/batchGenPerformanceTestJmx/', param, response => {
let returnDataList = response.data;
let jmxObjList = [];
returnDataList.forEach(item => {
let jmxObj = {};
jmxObj.name = item.name;
jmxObj.xml = item.xml;
jmxObj.attachFiles = item.attachFiles;
jmxObj.attachByteFiles = item.attachByteFiles;
jmxObj.scenarioId = item.id;
jmxObjList.push(jmxObj);
});
this.$store.commit('setScenarioJmxs', {
name: 'Scenarios',
jmxs: jmxObjList
});
this.$router.push({
path: "/performance/test/create"
});
});
}
}
});
},
}
};
</script>

View File

@ -44,10 +44,13 @@
:showScript="false"
:is-read-only="this.isCompReadOnly"
ref="esbDefinition"/>
<ms-tcp-basis-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "
:request="request"
:is-read-only="isCompReadOnly"
:showScript="false"/>
<!-- <ms-tcp-basis-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "-->
<!-- :request="request"-->
<!-- :is-read-only="isCompReadOnly"-->
<!-- :showScript="false"/>-->
<ms-tcp-format-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "
:is-read-only="isCompReadOnly"
:show-script="false" :request="request"/>
<ms-sql-basis-parameters v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"
:request="request"
:is-read-only="isCompReadOnly"
@ -91,7 +94,8 @@
<script>
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
// import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
import MsTcpFormatParameters from "../../../definition/components/request/tcp/TcpFormatParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
import MsRequestResultTail from "../../../definition/components/response/RequestResultTail";
@ -131,7 +135,7 @@ export default {
components: {
CustomizeReqInfo,
ApiBaseComponent, ApiResponseComponent,
MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun,
MsSqlBasisParameters, MsTcpFormatParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun,
"esbDefinition": esbDefinition.default,
"esbDefinitionResponse": esbDefinitionResponse.default
},

View File

@ -25,7 +25,8 @@
<!-- 请求参数 -->
<div v-if="apiProtocol=='TCP'">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-basis-parameters :show-script="false" :request="request"/>
<!-- <ms-basis-parameters :show-script="false" :request="request"/>-->
<ms-tcp-format-parameters :show-script="false" :request="request"/>
</div>
<div v-else-if="apiProtocol=='ESB'">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
@ -43,7 +44,7 @@
<script>
import MsTcpBasicApi from "./TCPBasicApi";
import MsBasisParameters from "../request/tcp/TcpBasisParameters";
import MsTcpFormatParameters from "../request/tcp/TcpFormatParameters";
import MsChangeHistory from "../../../../history/ChangeHistory";
import {hasLicense} from "@/common/js/utils";
@ -52,7 +53,7 @@ const esbDefinition = (requireComponent!=null&&requireComponent.keys().length) >
const esbDefinitionResponse = (requireComponent!=null&&requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinitionResponse.vue") : {};
export default {
name: "MsAddCompleteTcpApi",
components: {MsTcpBasicApi, MsBasisParameters,MsChangeHistory,
components: {MsTcpBasicApi, MsTcpFormatParameters,MsChangeHistory,
"esbDefinition": esbDefinition.default,
"esbDefinitionResponse": esbDefinitionResponse.default},
props: {

View File

@ -0,0 +1,292 @@
<template>
<div class="ms-border">
<el-table
:data="tableData" @cell-dblclick="editRow"
row-key="uuid" :expand-row-keys="tableExpandRowKayArray"
default-expand-all
v-loading="loading"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column prop="name" :label="$t('api_test.definition.request.esb_table.name')" width="230">
<template slot-scope="scope">
<el-input v-if="scope.row.status" v-model="scope.row.name" style="width: 140px"></el-input>
<span v-else>{{scope.row.name}}</span>
</template>
</el-table-column>
<el-table-column prop="type" :label="$t('api_test.definition.request.esb_table.type')" width="120">
<template slot-scope="scope">
<el-select v-if="scope.row.status" v-model="scope.row.type" :placeholder="$t('commons.please_select')">
<el-option v-for="item in typeSelectOptions " :key="item.value" :label="item.value" :value="item.value">
</el-option>
</el-select>
<span v-else>{{scope.row.type}}</span>
</template>
</el-table-column>
<el-table-column prop="length" :label="$t('api_test.definition.request.esb_table.length')" width="80">
<template slot-scope="scope">
<el-input v-if="scope.row.status" v-model="scope.row.contentType"></el-input>
<span v-else>{{scope.row.contentType}}</span>
</template>
</el-table-column>
<el-table-column prop="description" :label="$t('api_test.definition.request.esb_table.desc')" min-width="200">
<template slot-scope="scope">
<el-input v-if="scope.row.status" v-model="scope.row.description"></el-input>
<span v-else>{{scope.row.description}}</span>
</template>
</el-table-column>
<el-table-column prop="value" :label="$t('api_test.definition.request.esb_table.value')" width="180">
<template slot-scope="scope">
<el-input v-if="scope.row.status" v-model="scope.row.value"></el-input>
<span v-else>{{scope.row.value}}</span>
</template>
</el-table-column>
<el-table-column v-if="showOptionsButton" :label="$t('commons.operating')" width="140" fixed="right">
<template v-slot:default="scope">
<span>
<el-button size="mini" p="$t('commons.next_level')" icon="el-icon-plus" type="primary" circle @click="nextRow(scope.row)"
class="ht-btn-confirm"/>
<el-button size="mini" p="$t('commons.copy')" icon="el-icon-copy-document" type="primary" circle @click="copyDataStructConfirm(scope.row)"
class="ht-btn-confirm"/>
<el-button size="mini" p="$t('commons.remove')" icon="el-icon-close" circle @click="remove(scope.row)"
class="ht-btn-remove"/>
</span>
</template>
</el-table-column>
</el-table>
<div v-if="showOptionsButton">
<el-button class="ht-btn-add" size="mini" p="$t('commons.add')" icon="el-icon-circle-plus-outline" @click="add">{{$t("commons.add")}}</el-button>
<el-button class="ht-btn-add" size="mini" p="$t('commons.add')" icon="el-icon-circle-plus-outline" @click="saveTableData">{{$t("commons.save")}}</el-button>
</div>
</div>
</template>
<script>
export default {
name: "MsTcpXmlTable",
components: {},
props: {
tableData: Array,
showOptionsButton:Boolean,
},
data() {
return {
loading:false,
typeSelectOptions:[
{ value: 'object', label: '[object]' },
{ value: 'string', label: '[string]' },
{ value: 'array', label: '[array]' },
],
requiredSelectOptions:[
{ value: true, label: '必填' },
{ value: false, label: '非必填' },
],
tableExpandRowKayArray:["name","systemName"],
}
},
created() {
if(this.tableData && this.tableData.length>0){
this.tableData.forEach(row => {
if(row.name == null || row.name === ""){
this.remove(row);
}
})
}
},
methods: {
saveTableData:function(){
this.$emit('saveTableData',this.tableData);
},
remove: function (row) {
this.removeTableRow(row);
},
add: function (r) {
let row = this.getNewRow(null);
this.pushTableData(row);
},
nextRow:function (row) {
//
let confirmRowFlag = this.confirm(row);
if(confirmRowFlag){
let nextRow = this.getNewRow(null);
this.pushTableData(nextRow,row.uuid);
}
},
//
copyDataStructConfirm:function (row){
this.$alert(this.$t('api_test.definition.request.esb_copy_confirm') + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.copyDataStruct(row);
}
}
});
},
copyDataStruct:function (row){
let parentRow = this.selectParentRow(this.tableData,row.uuid);
let newRow = this.createNewId(row);
if(parentRow!=null){
if(parentRow.children == null){
parentRow.children = [];
}
parentRow.children.push(newRow);
}else{
this.$emit('xmlTableDataPushRow',newRow);
}
},
createNewId(row){
let newRow = this.getNewRow(row);
if(row.children!=null && row.children.length > 0){
row.children.forEach(child => {
let newChild = this.createNewId(child);
newRow.children.push(newChild);
});
}
return newRow;
},
selectParentRow(dataStruct,rowId){
let returnRow = null;
if(dataStruct == null || dataStruct.length === 0){
return returnRow;
}
dataStruct.forEach( itemData => {
if(itemData.children != null && itemData.children.length > 0){
itemData.children.forEach( child => {
if(child.uuid === rowId){
returnRow = itemData;
return returnRow;
}
});
}
if(returnRow == null ){
if(itemData.children != null && itemData.children.length > 0){
returnRow = this.selectParentRow(itemData.children,rowId);
if(returnRow!=null){
return returnRow;
}
}
}
});
return returnRow;
},
confirm: function (row) {
this.validateRowData(row) ? row.status = '' : row.status;
if (row.status === "") {
return true;
}
return false;
},
getNewRow(param){
if(param == null ){
let row = {
name: '',systemName: '',status: 'edit',type: '[object]',contentType: '',required: false,description: '',uuid: this.uuid(),children: []
}
return row;
}else{
let row = {
name: param.name,
systemName: param.systemName,
status: '',
type: param.type,
contentType: param.contentType,
required: param.required,
description: param.description,
uuid: this.uuid(),
children: []
}
return row;
}
},
validateRowData(row) {
if(row.name == null || row.name === ''){
// this.$warning(this.$t('load_test.input_ip'));
this.$warning("参数名"+"不能为空,且不能包含英文小数点[.]");
return false;
}else if(row.name.indexOf(".")>0){
this.$warning("参数名["+row.name+"]不合法,不能包含英文小数点\".\"!");
return false;
}else if(row.type == null || row.type === ''){
this.$warning("类型"+"不能为空!");
return false;
}
return true;
},
editRow: function (row) {
row.status = 'edit';
},
uuid: function () {
return (((1 + Math.random()) * 0x100000) | 0).toString(16).substring(1);
},
pushTableData: function(dataRow,rowId){
if(rowId === "" || rowId == null){
if(this.tableData){
this.$emit("initXmlTableData");
}
this.tableData.push(dataRow);
}else {
this.appendDataWithDeepForeach(this.tableData,rowId,dataRow);
}
},
appendDataWithDeepForeach(datas,rowId,appendData){
datas.forEach( row => {
if(row.uuid === rowId){
if(row.children == null){
row.children = [];
}
row.children.push(appendData);
}else if(row.children.length>0){
let appendResult = this.appendDataWithDeepForeach(row.children,rowId,appendData);
if(appendResult){
return appendResult;
}
}
});
return false;
},
removeTableRow: function (row){
this.removeFromDataStruct(this.tableData,row);
},
removeFromDataStruct(dataStruct,row){
if(dataStruct == null || dataStruct.length === 0){
return;
}
let rowIndex = dataStruct.indexOf(row);
if(rowIndex >= 0){
dataStruct.splice(rowIndex,1);
}else {
dataStruct.forEach( itemData => {
if(itemData.children != null && itemData.children.length > 0){
this.removeFromDataStruct(itemData.children,row);
}
});
}
},
}
}
</script>
<style scoped>
.ht-btn-remove {
color: white;
background-color: #DCDFE6;
}
.ht-btn-confirm {
color: white;
/*background-color: #1483F6;*/
}
.ht-btn-add {
border: 0px;
margin-top: 10px;
color: #783887;
background-color: white;
}
.ht-tb {
background-color: white;
border: 0px;
}
</style>

View File

@ -27,8 +27,8 @@
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<!-- TCP 请求参数 -->
<tcp-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/>
<!-- <tcp-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/>-->
<ms-tcp-format-parameters :request="request" @callback="runDebug" ref="requestForm"/>
<!-- TCP 请求返回数据 -->
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
<ms-request-result-tail :response="responseData" :currentProtocol="currentProtocol" ref="debugResult"/>
@ -58,7 +58,7 @@
import {createComponent} from "../jmeter/components";
import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail";
import TcpBasisParameters from "../request/tcp/TcpBasisParameters";
import MsTcpFormatParameters from "@/business/components/api/definition/components/request/tcp/TcpFormatParameters";
import MsJmxStep from "../step/JmxStep";
import MsApiCaseList from "../case/ApiCaseList";
@ -66,7 +66,7 @@
name: "ApiConfig",
components: {
MsJmxStep,
TcpBasisParameters,
MsTcpFormatParameters,
MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsApiCaseList
},
props: {

View File

@ -0,0 +1,497 @@
<template>
<div>
<el-row>
<el-col :span="21" style="padding-bottom: 20px">
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin: 10px">
<el-form class="tcp" :model="request" :rules="rules" ref="request" :disabled="isReadOnly" style="margin: 20px">
<el-tabs v-model="activeName" class="request-tabs">
<!--query 参数-->
<el-tab-pane :label="$t('api_test.definition.document.request_body')" name="request">
<el-radio-group v-model="reportType" size="mini" style="margin: 10px 0px;">
<el-radio :disabled="isReadOnly" label="json" @change="changeReportType">
json
</el-radio>
<el-radio :disabled="isReadOnly" label="xml" @change="changeReportType">
xml
</el-radio>
<el-radio :disabled="isReadOnly" label="raw" @change="changeReportType">
raw
</el-radio>
</el-radio-group>
<div style="min-width: 1200px;" v-if="request.reportType === 'xml'">
<tcp-xml-table :table-data="request.xmlDataStruct" :show-options-button="true"
@initXmlTableData="initXmlTableData"
@saveTableData="saveXmlTableData" ref="treeTable"></tcp-xml-table>
</div>
<div style="min-width: 1200px;" v-if="request.reportType === 'json'">
<div class="send-request">
<ms-code-edit mode="json" :read-only="isReadOnly" :data.sync="request.jsonDataStruct" :modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
</div>
</div>
<div style="min-width: 1200px;" v-if="request.reportType === 'raw'">
<div class="send-request">
<ms-code-edit mode="text" :read-only="isReadOnly" :data.sync="request.rawDataStruct" :modes="['text', 'json', 'xml', 'html']" theme="eclipse"/>
</div>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.definition.request.pre_script')" name="script">
<jsr233-processor-content
:jsr223-processor="request.tcpPreProcessor"
:is-pre-processor="true"
:is-read-only="isReadOnly"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.definition.request.other_config')" name="other" class="other-config">
<el-row>
<el-col :span="8">
<el-form-item label="TCPClient" prop="classname">
<el-select v-model="request.classname" style="width: 100%" size="small">
<el-option v-for="c in classes" :key="c" :label="c" :value="c"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('api_test.request.tcp.connect')" prop="ctimeout">
<el-input-number v-model="request.ctimeout" controls-position="right" :min="0" size="small"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="$t('api_test.request.tcp.response')" prop="timeout">
<el-input-number v-model="request.timeout" controls-position="right" :min="0" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.so_linger')" prop="soLinger">
<el-input v-model="request.soLinger" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.eol_byte')" prop="eolByte">
<el-input v-model="request.eolByte" size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.username')" prop="username">
<el-input v-model="request.username" maxlength="100" show-word-limit size="small"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.password')" prop="password">
<el-input v-model="request.password" maxlength="30" show-word-limit show-password
autocomplete="new-password" size="small"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10" style="margin-left: 30px">
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.re_use_connection')">
<el-checkbox v-model="request.reUseConnection"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.close_connection')">
<el-checkbox v-model="request.closeConnection"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('api_test.request.tcp.no_delay')">
<el-checkbox v-model="request.nodelay"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="Connect encoding">
<el-select v-model="request.connectEncoding" style="width: 100px" size="small">
<el-option v-for="item in connectEncodingArr" :key="item.key" :label="item.value" :value="item.key"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</el-form>
</div>
</el-col>
<!--操作按钮-->
<api-definition-step-button :request="request" v-if="!referenced && showScript"/>
</el-row>
</div>
</template>
<script>
import MsApiKeyValue from "../../ApiKeyValue";
import MsApiAssertions from "../../assertion/ApiAssertions";
import MsApiExtract from "../../extract/ApiExtract";
import ApiRequestMethodSelect from "../../collapse/ApiRequestMethodSelect";
import MsCodeEdit from "../../../../../common/components/MsCodeEdit";
import MsApiScenarioVariables from "../../ApiScenarioVariables";
import {createComponent} from "../../jmeter/components";
import {Assertions, Extract} from "../../../model/ApiTestModel";
import {parseEnvironment} from "../../../model/EnvironmentModel";
import ApiEnvironmentConfig from "../../environment/ApiEnvironmentConfig";
import {API_STATUS} from "../../../model/JsonData";
import TCPSampler from "../../jmeter/components/sampler/tcp-sampler";
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import MsApiVariable from "../../ApiVariable";
import MsInstructionsIcon from "../../../../../common/components/MsInstructionsIcon";
import Jsr233ProcessorContent from "../../../../automation/scenario/common/Jsr233ProcessorContent";
import JSR223PreProcessor from "../../jmeter/components/pre-processors/jsr223-pre-processor";
import ApiDefinitionStepButton from "../components/ApiDefinitionStepButton";
import TcpXmlTable from "@/business/components/api/definition/components/complete/table/TcpXmlTable";
export default {
name: "MsTcpFormatParameters",
components: {
TcpXmlTable,
ApiDefinitionStepButton,
Jsr233ProcessorContent,
MsInstructionsIcon,
MsApiVariable,
MsApiScenarioVariables,
MsCodeEdit,
ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiKeyValue, ApiEnvironmentConfig
},
props: {
request: {},
basisData: {},
moduleOptions: Array,
isReadOnly: {
type: Boolean,
default: false
},
showScript: {
type: Boolean,
default: true,
},
referenced: {
type: Boolean,
default: false,
},
},
data() {
return {
activeName: "request",
classes: TCPSampler.CLASSES,
reportType:"xml",
isReloadData: false,
refreshedXmlTable:true,
options: API_STATUS,
currentProjectId: "",
connectEncodingArr:[
{
'key':'UTF-8',
'value':'UTF-8',
},
{
'key':'GBK',
'value':'GBK',
},
],
rules: {
classname: [{required: true, message: "请选择TCPClient", trigger: 'change'}],
server: [{required: true, message: this.$t('api_test.request.tcp.server_cannot_be_empty'), trigger: 'blur'}],
port: [{required: true, message: this.$t('commons.port_cannot_be_empty'), trigger: 'change'}],
},
}
},
watch:{
reportType(){
this.request.reportType = this.reportType;
}
},
created() {
this.currentProjectId = getCurrentProjectID();
if (!this.request.parameters) {
this.$set(this.request, 'parameters', []);
this.request.parameters = [];
}
if (!this.request.tcpPreProcessor) {
this.$set(this.request, 'tcpPreProcessor', new JSR223PreProcessor())
}
if(!this.request.connectEncoding){
this.request.connectEncoding = "UTF-8";
}
this.getEnvironments();
if(this.request){
if(!this.request.reportType){
this.request.reportType = "raw";
}else {
if(this.request.reportType !== "json" && this.request.reportType !== "xml"&&this.request.reportType !== "raw"){
this.request.reportType = "raw";
}
}
this.reportType = this.request.reportType;
if(!this.request.xmlDataStruct){
this.initXmlTableData();
}
}
},
methods: {
addPre() {
let jsr223PreProcessor = createComponent("JSR223PreProcessor");
this.request.hashTree.push(jsr223PreProcessor);
this.reload();
},
addPost() {
let jsr223PostProcessor = createComponent("JSR223PostProcessor");
this.request.hashTree.push(jsr223PostProcessor);
this.reload();
},
addAssertions() {
let assertions = new Assertions();
this.request.hashTree.push(assertions);
this.reload();
},
addExtract() {
let jsonPostProcessor = new Extract();
this.request.hashTree.push(jsonPostProcessor);
this.reload();
},
remove(row) {
let index = this.request.hashTree.indexOf(row);
this.request.hashTree.splice(index, 1);
this.reload();
},
copyRow(row) {
let obj =JSON.parse(JSON.stringify(row));
obj.id = getUUID();
this.request.hashTree.push(obj);
this.reload();
},
reload() {
this.isReloadData = true
this.$nextTick(() => {
this.isReloadData = false
})
},
validateApi() {
if (this.currentProjectId === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['basicForm'].validate();
},
saveApi() {
this.basisData.method = this.basisData.protocol;
this.$emit('saveApi', this.basisData);
},
runTest() {
},
validate() {
if (this.currentProjectId === null) {
this.$error(this.$t('api_test.select_project'), 2000);
return;
}
this.$refs['request'].validate((valid) => {
if (valid) {
this.$emit('callback');
}
})
},
getEnvironments() {
if (this.currentProjectId) {
this.environments = [];
this.$get('/api/environment/list/' + this.currentProjectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
this.initDataSource();
});
}
},
openEnvironmentConfig() {
if (!this.currentProjectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.currentProjectId);
},
initDataSource() {
for (let i in this.environments) {
if (this.environments[i].id === this.request.environmentId) {
this.databaseConfigsOptions = [];
this.environments[i].config.databaseConfigs.forEach(item => {
this.databaseConfigsOptions.push(item);
})
break;
}
}
},
environmentChange(value) {
this.request.dataSource = undefined;
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.databaseConfigsOptions = [];
this.environments[i].config.databaseConfigs.forEach(item => {
this.databaseConfigsOptions.push(item);
})
break;
}
}
},
environmentConfigClose() {
this.getEnvironments();
},
changeReportType(){
},
//xml
updateXmlTableData(dataStruct){
this.request.xmlDataStruct = dataStruct;
},
saveXmlTableData(dataStruct){
let valedataResult = this.validateXmlDataStruct(dataStruct);
if(valedataResult){
this.request.xmlDataStruct = dataStruct;
this.refreshXmlTable();
}
},
validateXmlDataStruct(dataStruct){
this.refreshXmlTableDataStruct(dataStruct);
let result = this.checkXmlTableDataStructData(dataStruct);
return result;
},
refreshXmlTableDataStruct(dataStruct){
if(dataStruct && dataStruct.length > 0){
dataStruct.forEach( row => {
row.status = "";
if(row.children == null || row.children.length === 0){
row.children = [];
}else if(row.children.length>0){
this.refreshXmlTableDataStruct(row.children);
}
});
}
},
checkXmlTableDataStructData(dataStruct){
let allCheckResult = true;
if(dataStruct && dataStruct.length > 0){
for(let i = 0;i<dataStruct.length;i++){
let row = dataStruct[i];
allCheckResult = this.$refs.treeTable.validateRowData(row);
if(allCheckResult){
if(row.children != null && row.children.length > 0){
allCheckResult = this.checkXmlTableDataStructData(row.children);
if(!allCheckResult){
return false;
}
}
}else{
return false;
}
}
}
return allCheckResult;
},
initXmlTableData(){
if(this.request){
this.request.xmlDataStruct = [];
this.refreshXmlTable();
}
},
xmlTableDataPushRow(newRow){
if(this.request){
if(!this.request.xmlDataStruct){
this.request.xmlDataStruct = [];
}
this.request.xmlDataStruct.push(newRow);
this.refreshXmlTable();
}
},
xmlTableDataRemoveRow(row){
if(this.request){
if(this.request.xmlDataStruct){
this.removeFromDataStruct(this.request.xmlDataStruct,row);
this.refreshXmlTable();
}
}
},
removeFromDataStruct(dataStruct,row){
if(!dataStruct || dataStruct.length === 0){
return;
}
let rowIndex = dataStruct.indexOf(row);
if(rowIndex >= 0){
dataStruct.splice(rowIndex,1);
}else {
dataStruct.forEach( itemData => {
if(!itemData.children && itemData.children.length > 0){
this.removeFromDataStruct(itemData.children,row);
}
});
}
},
refreshXmlTable(){
this.refreshedXmlTable = true
this.$nextTick(() => {
this.refreshedXmlTable = false
})
}
}
}
</script>
<style scoped>
.tcp >>> .el-input-number {
width: 100%;
}
.send-request {
padding: 0px 0;
height: 300px;
border: 1px #DCDFE6 solid;
border-radius: 4px;
width: 100%;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
.ms-left-cell {
margin-top: 40px;
}
.ms-left-buttion {
margin: 6px 0px 8px 30px;
}
/deep/ .el-form-item {
margin-bottom: 15px;
}
/deep/ .instructions-icon {
font-size: 14px !important;
}
.request-tabs {
margin: 20px;
min-height: 200px;
}
.other-config {
padding: 15px;
}
</style>

View File

@ -33,7 +33,8 @@
<div v-if="api.method=='TCP'">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>
<!-- <ms-basis-parameters :request="api.request" @callback="runTest" ref="requestForm"/>-->
<ms-tcp-format-parameters :request="api.request" @callback="runTest" ref="requestForm"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
@ -74,7 +75,7 @@ import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer";
import MsRequestResultTail from "../response/RequestResultTail";
import MsRun from "../Run";
import MsBasisParameters from "../request/tcp/TcpBasisParameters";
import MsTcpFormatParameters from "@/business/components/api/definition/components/request/tcp/TcpFormatParameters";
import {REQ_METHOD} from "../../model/JsonData";
import EnvironmentSelect from "../environment/EnvironmentSelect";
import MsJmxStep from "../step/JmxStep";
@ -92,7 +93,7 @@ export default {
MsBottomContainer,
MsRequestResultTail,
MsRun,
MsBasisParameters,
MsTcpFormatParameters,
"esbDefinition": esbDefinition.default,
"esbDefinitionResponse": esbDefinitionResponse.default
},

View File

@ -160,7 +160,7 @@ export default {
if (apiTest.jmx.caseId) {
this.$refs.basicConfig.importCase(apiTest.jmx);
}
if (JSON.stringify(apiTest.jmx.attachFiles) != "{}") {
if (JSON.stringify(apiTest.jmx.attachFiles) !== "{}") {
let attachFiles = [];
for (let fileID in apiTest.jmx.attachFiles) {
attachFiles.push(fileID);
@ -171,6 +171,33 @@ export default {
}
this.active = '1';
this.$store.commit("clearTest");
}else {
let scenarioJmxs = this.$store.state.scenarioJmxs;
if(scenarioJmxs && scenarioJmxs.name){
this.$set(this.test, "name", scenarioJmxs.name);
if(scenarioJmxs.jmxs){
scenarioJmxs.jmxs.forEach(item => {
if (item.scenarioId) {
this.$refs.basicConfig.importScenario(item.scenarioId);
this.$refs.basicConfig.handleUpload();
}
if (item.caseId) {
this.$refs.basicConfig.importCase(item);
}
if (JSON.stringify(item.attachFiles) !== "{}") {
let attachFiles = [];
for (let fileID in item.attachFiles) {
attachFiles.push(fileID);
}
if (attachFiles.length > 0) {
this.$refs.basicConfig.selectAttachFileById(attachFiles);
}
}
});
this.active = '1';
this.$store.commit("clearScenarioJmxs");
}
}
}
},
getTest(testId) {

View File

@ -669,6 +669,7 @@ export default {
key: "Key",
value: "Value",
create_performance_test: "Create Performance Test",
create_performance_test_batch: "Batch Create Performance Test",
export_config: "Export",
enable_validate_tip: "No request available",
copy: "Copy Test",
@ -760,6 +761,7 @@ export default {
res_param: "Response content",
batch_delete: "Batch deletion",
delete_confirm: "Confirm deletion",
batch_to_performance_confirm: "Confirm Batch Create Performance Test",
delete_case_confirm: "Confirm case deletion",
delete_confirm_step: "Confirm deletion step",
assertions_rule: "Assertion rule",

View File

@ -668,6 +668,7 @@ export default {
key: "键",
value: "值",
create_performance_test: "创建性能测试",
create_performance_test_batch: "批量创建性能测试",
export_config: "导出",
enable_validate_tip: "没有可用请求",
copy: "复制测试",
@ -760,6 +761,7 @@ export default {
res_param: "响应内容",
batch_delete: "批量删除",
delete_confirm: "确认删除接口",
batch_to_performance_confirm: "确认批量创建性能测试",
delete_case_confirm: "确认删除用例",
delete_confirm_step: "确认删除步骤",
assertions_rule: "断言规则",

View File

@ -668,6 +668,7 @@ export default {
key: "鍵",
value: "值",
create_performance_test: "創建性能測試",
create_performance_test_batch: "批量創建性能測試",
export_config: "導出",
enable_validate_tip: "沒有可用請求",
copy: "復制測試",
@ -760,6 +761,7 @@ export default {
res_param: "響應內容",
batch_delete: "批量刪除",
delete_confirm: "確認刪除接口",
batch_to_performance_confirm: "確認批量創建性能測試",
delete_case_confirm: "確認刪除用例",
delete_confirm_step: "確認刪除步驟",
assertions_rule: "斷言規則",

View File

@ -9,6 +9,7 @@ Vue.use(Vuex)
const state = {
projectId: "",
test: {},
scenarioJmxs:{},
versionSwitch: "new",
isReadOnly: true,
theme: undefined,

View File

@ -1,7 +1,9 @@
const mutations = {
setProjectId: (state, projectId) => state.projectId = projectId,
setTest: (state, test) => state.test = test,
setScenarioJmxs: (state, scenarioJmxs) => state.scenarioJmxs = scenarioJmxs,
clearTest: state => state.test = {},
clearScenarioJmxs:state => state.scenarioJmxs = {},
setVersionSwitch: (state, value) => state.versionSwitch = value,
setTheme: (state, value) => state.theme = value,