Merge branch 'v1.8' into pr@master@fix_合并1.8
# Conflicts: # frontend/src/business/components/api/automation/report/ApiReportDetail.vue # frontend/src/business/components/api/automation/report/components/RequestResult.vue # frontend/src/business/components/api/definition/components/case/ApiCaseList.vue # frontend/src/business/components/api/definition/components/list/ApiCaseSimpleList.vue # frontend/src/business/components/common/components/MsModuleMinder.vue # frontend/src/business/components/track/review/view/components/TestReviewTestCaseList.vue
This commit is contained in:
commit
1578974237
|
@ -18,10 +18,7 @@ import io.metersphere.api.service.*;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.commons.constants.RoleConstants;
|
import io.metersphere.commons.constants.RoleConstants;
|
||||||
import io.metersphere.commons.constants.ScheduleGroup;
|
import io.metersphere.commons.constants.ScheduleGroup;
|
||||||
import io.metersphere.commons.utils.CronUtils;
|
import io.metersphere.commons.utils.*;
|
||||||
import io.metersphere.commons.utils.PageUtils;
|
|
||||||
import io.metersphere.commons.utils.Pager;
|
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
|
||||||
import io.metersphere.controller.request.QueryScheduleRequest;
|
import io.metersphere.controller.request.QueryScheduleRequest;
|
||||||
import io.metersphere.controller.request.ScheduleRequest;
|
import io.metersphere.controller.request.ScheduleRequest;
|
||||||
import io.metersphere.dto.ScheduleDao;
|
import io.metersphere.dto.ScheduleDao;
|
||||||
|
@ -398,6 +395,7 @@ public class APITestController {
|
||||||
|
|
||||||
@PostMapping(value = "/genPerformanceTestXml", consumes = {"multipart/form-data"})
|
@PostMapping(value = "/genPerformanceTestXml", consumes = {"multipart/form-data"})
|
||||||
public JmxInfoDTO genPerformanceTest(@RequestPart("request") RunDefinitionRequest runRequest, @RequestPart(value = "files") List<MultipartFile> bodyFiles) throws Exception {
|
public JmxInfoDTO genPerformanceTest(@RequestPart("request") RunDefinitionRequest runRequest, @RequestPart(value = "files") List<MultipartFile> bodyFiles) throws Exception {
|
||||||
|
|
||||||
ParameterConfig config = new ParameterConfig();
|
ParameterConfig config = new ParameterConfig();
|
||||||
config.setProjectId(runRequest.getProjectId());
|
config.setProjectId(runRequest.getProjectId());
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ import java.util.List;
|
||||||
public class ApiScenarioImportUtil {
|
public class ApiScenarioImportUtil {
|
||||||
|
|
||||||
public static ApiScenarioModule getSelectModule(String moduleId) {
|
public static ApiScenarioModule getSelectModule(String moduleId) {
|
||||||
ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
ApiScenarioModuleService apiScenarioModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
||||||
if (StringUtils.isNotBlank(moduleId) && !StringUtils.equals("root", moduleId)) {
|
if (StringUtils.isNotBlank(moduleId) && !StringUtils.equals("root", moduleId)) {
|
||||||
ApiScenarioModule module = new ApiScenarioModule();
|
ApiScenarioModule module = new ApiScenarioModule();
|
||||||
ApiScenarioModuleDTO moduleDTO = apiModuleService.getNode(moduleId);
|
ApiScenarioModuleDTO moduleDTO = apiScenarioModuleService.getNode(moduleId);
|
||||||
if (moduleDTO != null) {
|
if (moduleDTO != null) {
|
||||||
BeanUtils.copyBean(module, moduleDTO);
|
BeanUtils.copyBean(module, moduleDTO);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,17 @@ public class ApiScenarioImportUtil {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getSelectModulePath(String path, String pid) {
|
||||||
|
ApiScenarioModuleService apiScenarioModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
||||||
|
if (StringUtils.isNotBlank(pid)) {
|
||||||
|
ApiScenarioModuleDTO moduleDTO = apiScenarioModuleService.getNode(pid);
|
||||||
|
if (moduleDTO != null) {
|
||||||
|
return getSelectModulePath(moduleDTO.getName() + "/" + path, moduleDTO.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
public static ApiScenarioModule buildModule(ApiScenarioModule parentModule, String name, String projectId) {
|
public static ApiScenarioModule buildModule(ApiScenarioModule parentModule, String name, String projectId) {
|
||||||
ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
||||||
ApiScenarioModule module;
|
ApiScenarioModule module;
|
||||||
|
|
|
@ -18,6 +18,7 @@ import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -62,17 +63,21 @@ public class HarScenarioParser extends HarScenarioAbstractParser<ScenarioImport>
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) {
|
private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) {
|
||||||
ApiScenarioModule module = ApiScenarioImportUtil.getSelectModule(request.getModuleId());
|
ApiScenarioModule selectModule = null;
|
||||||
if (module == null) {
|
if (StringUtils.isNotBlank(request.getModuleId())) {
|
||||||
ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
|
selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId());
|
||||||
module = apiModuleService.getNewModule(msScenario.getName(), projectId, 1);
|
|
||||||
}
|
}
|
||||||
|
ApiScenarioModule module = ApiScenarioImportUtil.buildModule(selectModule, msScenario.getName(), this.projectId);
|
||||||
ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario);
|
ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario);
|
||||||
if (module != null) {
|
if (module != null) {
|
||||||
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
||||||
|
if (selectModule != null) {
|
||||||
|
String selectModulePath = ApiScenarioImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId());
|
||||||
|
scenarioWithBLOBs.setModulePath(selectModulePath + "/" + module.getName());
|
||||||
|
} else {
|
||||||
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,15 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
private List<ApiScenarioWithBLOBs> paseObj(MsScenario msScenario, ApiTestImportRequest request) {
|
private List<ApiScenarioWithBLOBs> paseObj(MsScenario msScenario, ApiTestImportRequest request) {
|
||||||
List<ApiScenarioWithBLOBs> scenarioWithBLOBsList = new ArrayList<>();
|
List<ApiScenarioWithBLOBs> scenarioWithBLOBsList = new ArrayList<>();
|
||||||
ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
|
ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
|
||||||
ApiScenarioModule module = ApiScenarioImportUtil.buildModule(ApiScenarioImportUtil.getSelectModule(request.getModuleId()), msScenario.getName(), this.projectId);
|
ApiScenarioModule selectModule = null;
|
||||||
|
String selectModulePath = null;
|
||||||
|
if (StringUtils.isNotBlank(request.getModuleId())) {
|
||||||
|
selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId());
|
||||||
|
if (selectModule != null) {
|
||||||
|
selectModulePath = ApiScenarioImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ApiScenarioModule module = ApiScenarioImportUtil.buildModule(selectModule, msScenario.getName(), this.projectId);
|
||||||
scenarioWithBLOBs.setName(msScenario.getName());
|
scenarioWithBLOBs.setName(msScenario.getName());
|
||||||
scenarioWithBLOBs.setProjectId(request.getProjectId());
|
scenarioWithBLOBs.setProjectId(request.getProjectId());
|
||||||
if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) {
|
if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) {
|
||||||
|
@ -120,8 +128,12 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
}
|
}
|
||||||
if (module != null) {
|
if (module != null) {
|
||||||
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
||||||
|
if (StringUtils.isNotBlank(selectModulePath)) {
|
||||||
|
scenarioWithBLOBs.setModulePath(selectModulePath + "/" + module.getName());
|
||||||
|
} else {
|
||||||
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
|
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
|
||||||
scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario));
|
scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario));
|
||||||
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
||||||
|
@ -198,6 +210,12 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
samplerProxy.setArguments(new ArrayList<KeyValue>() {{
|
samplerProxy.setArguments(new ArrayList<KeyValue>() {{
|
||||||
this.add(new KeyValue());
|
this.add(new KeyValue());
|
||||||
}});
|
}});
|
||||||
|
// 初始化body
|
||||||
|
Body body = new Body();
|
||||||
|
body.init();
|
||||||
|
body.initKvs();
|
||||||
|
body.initBinary();
|
||||||
|
samplerProxy.setBody(body);
|
||||||
if (source != null && source.getHTTPFiles().length > 0) {
|
if (source != null && source.getHTTPFiles().length > 0) {
|
||||||
samplerProxy.getBody().initBinary();
|
samplerProxy.getBody().initBinary();
|
||||||
samplerProxy.getBody().setType(Body.FORM_DATA);
|
samplerProxy.getBody().setType(Body.FORM_DATA);
|
||||||
|
|
|
@ -17,11 +17,23 @@ import java.util.*;
|
||||||
|
|
||||||
public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
|
public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
|
||||||
|
|
||||||
|
private ApiScenarioModule selectModule;
|
||||||
|
|
||||||
|
private String selectModulePath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScenarioImport parse(InputStream source, ApiTestImportRequest request) {
|
public ScenarioImport parse(InputStream source, ApiTestImportRequest request) {
|
||||||
String testStr = getApiTestStr(source);
|
String testStr = getApiTestStr(source);
|
||||||
this.projectId = request.getProjectId();
|
this.projectId = request.getProjectId();
|
||||||
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
|
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(request.getModuleId())) {
|
||||||
|
this.selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId());
|
||||||
|
if (this.selectModule != null) {
|
||||||
|
this.selectModulePath = ApiScenarioImportUtil.getSelectModulePath(this.selectModule.getName(), this.selectModule.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {
|
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {
|
||||||
return parseMsFormat(testStr, request);
|
return parseMsFormat(testStr, request);
|
||||||
} else {
|
} else {
|
||||||
|
@ -73,13 +85,19 @@ public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
|
||||||
modulePath = modulePath.substring(0, modulePath.length() - 1);
|
modulePath = modulePath.substring(0, modulePath.length() - 1);
|
||||||
}
|
}
|
||||||
List<String> modules = Arrays.asList(modulePath.split("/"));
|
List<String> modules = Arrays.asList(modulePath.split("/"));
|
||||||
ApiScenarioModule parent = ApiScenarioImportUtil.getSelectModule(importRequest.getModuleId());
|
ApiScenarioModule parent = this.selectModule;
|
||||||
Iterator<String> iterator = modules.iterator();
|
Iterator<String> iterator = modules.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
String item = iterator.next();
|
String item = iterator.next();
|
||||||
parent = ApiScenarioImportUtil.buildModule(parent, item, this.projectId);
|
parent = ApiScenarioImportUtil.buildModule(parent, item, this.projectId);
|
||||||
if (!iterator.hasNext()) {
|
if (!iterator.hasNext()) {
|
||||||
apiScenarioWithBLOBs.setApiScenarioModuleId(parent.getId());
|
apiScenarioWithBLOBs.setApiScenarioModuleId(parent.getId());
|
||||||
|
String path = apiScenarioWithBLOBs.getModulePath() == null ? "" : apiScenarioWithBLOBs.getModulePath();
|
||||||
|
if (StringUtils.isNotBlank(this.selectModulePath)) {
|
||||||
|
apiScenarioWithBLOBs.setModulePath(this.selectModulePath + path);
|
||||||
|
} else if (StringUtils.isBlank(importRequest.getModuleId())) {
|
||||||
|
apiScenarioWithBLOBs.setModulePath("/默认模块" + path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,12 +46,19 @@ public class PostmanScenarioParser extends PostmanAbstractParserParser<ScenarioI
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) {
|
private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) {
|
||||||
ApiScenarioModule module = ApiScenarioImportUtil.buildModule(ApiScenarioImportUtil.getSelectModule(request.getModuleId()), msScenario.getName(), this.projectId);
|
ApiScenarioModule selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId());
|
||||||
|
|
||||||
|
ApiScenarioModule module = ApiScenarioImportUtil.buildModule(selectModule, msScenario.getName(), this.projectId);
|
||||||
ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario);
|
ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario);
|
||||||
if (module != null) {
|
if (module != null) {
|
||||||
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
||||||
|
if (selectModule != null) {
|
||||||
|
String selectModulePath = ApiScenarioImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId());
|
||||||
|
scenarioWithBLOBs.setModulePath(selectModulePath + "/" + module.getName());
|
||||||
|
} else {
|
||||||
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
scenarioWithBLOBs.setModulePath("/" + module.getName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,24 @@ public class ApiDefinitionImportUtil {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getSelectModulePath(String path, String pid) {
|
||||||
|
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
|
||||||
|
if (StringUtils.isNotBlank(pid)) {
|
||||||
|
ApiModuleDTO moduleDTO = apiModuleService.getNode(pid);
|
||||||
|
if (moduleDTO != null) {
|
||||||
|
return getSelectModulePath(moduleDTO.getName() + "/" + path, moduleDTO.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiModule getNodeTree(String projectId) {
|
||||||
|
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
|
||||||
|
List<ApiModuleDTO> nodeTrees = apiModuleService.getNodeTreeByProjectId(projectId, RequestType.HTTP);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static ApiModule buildModule(ApiModule parentModule, String name, String projectId) {
|
public static ApiModule buildModule(ApiModule parentModule, String name, String projectId) {
|
||||||
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
|
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
|
||||||
ApiModule module;
|
ApiModule module;
|
||||||
|
|
|
@ -1,27 +1,10 @@
|
||||||
package io.metersphere.api.dto.definition.parse;
|
package io.metersphere.api.dto.definition.parse;
|
||||||
|
|
||||||
|
|
||||||
import io.metersphere.api.parse.ApiImportAbstractParser;
|
import io.metersphere.api.parse.ApiImportAbstractParser;
|
||||||
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
|
|
||||||
import io.metersphere.base.domain.ApiModule;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author song.tianyang
|
* @author song.tianyang
|
||||||
* @Date 2021/3/10 11:15 上午
|
* @Date 2021/3/10 11:15 上午
|
||||||
* @Description
|
* @Description
|
||||||
*/
|
*/
|
||||||
public abstract class HarAbstractParser extends ApiImportAbstractParser<ApiDefinitionImport> {
|
public abstract class HarAbstractParser extends ApiImportAbstractParser<ApiDefinitionImport> {
|
||||||
|
|
||||||
protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List<String> tags) {
|
|
||||||
if (tags != null) {
|
|
||||||
tags.forEach(tag -> {
|
|
||||||
ApiModule module = ApiDefinitionImportUtil.buildModule(parentModule, tag, this.projectId);
|
|
||||||
apiDefinition.setModuleId(module.getId());
|
|
||||||
});
|
|
||||||
}else {
|
|
||||||
apiDefinition.setModuleId(parentModule.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,15 @@ public class HarParser extends HarAbstractParser {
|
||||||
private List<ApiDefinitionWithBLOBs> parseRequests(Har har, ApiTestImportRequest importRequest) {
|
private List<ApiDefinitionWithBLOBs> parseRequests(Har har, ApiTestImportRequest importRequest) {
|
||||||
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
||||||
|
|
||||||
ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
|
ApiModule selectModule = null;
|
||||||
|
String selectModulePath = null;
|
||||||
|
if (StringUtils.isNotBlank(importRequest.getModuleId())) {
|
||||||
|
selectModule = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
|
||||||
|
if (selectModule != null) {
|
||||||
|
selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
List<HarEntry> harEntryList = new ArrayList<>();
|
List<HarEntry> harEntryList = new ArrayList<>();
|
||||||
if (har.log != null && har.log.entries != null) {
|
if (har.log != null && har.log.entries != null) {
|
||||||
|
@ -103,7 +111,17 @@ public class HarParser extends HarAbstractParser {
|
||||||
addBodyHeader(request);
|
addBodyHeader(request);
|
||||||
apiDefinition.setRequest(JSON.toJSONString(request));
|
apiDefinition.setRequest(JSON.toJSONString(request));
|
||||||
apiDefinition.setResponse(JSON.toJSONString(parseResponse(entry.response)));
|
apiDefinition.setResponse(JSON.toJSONString(parseResponse(entry.response)));
|
||||||
buildModule(parentNode, apiDefinition, null);
|
if (selectModule == null) {
|
||||||
|
apiDefinition.setModuleId("default-module");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
apiDefinition.setModuleId(selectModule.getId());
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(selectModulePath)) {
|
||||||
|
apiDefinition.setModulePath(selectModulePath);
|
||||||
|
} else {
|
||||||
|
apiDefinition.setModulePath("/默认模块");
|
||||||
|
}
|
||||||
results.add(apiDefinition);
|
results.add(apiDefinition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,22 @@ import java.util.*;
|
||||||
|
|
||||||
public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
|
public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
|
||||||
|
|
||||||
|
private ApiModule selectModule;
|
||||||
|
|
||||||
|
private String selectModulePath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
|
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
|
||||||
String testStr = getApiTestStr(source);
|
String testStr = getApiTestStr(source);
|
||||||
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
|
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
|
||||||
this.projectId = request.getProjectId();
|
this.projectId = request.getProjectId();
|
||||||
|
if (StringUtils.isNotBlank(request.getModuleId())) {
|
||||||
|
this.selectModule = ApiDefinitionImportUtil.getSelectModule(request.getModuleId());
|
||||||
|
if (this.selectModule != null) {
|
||||||
|
this.selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(this.selectModule.getName(), this.selectModule.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {// metersphere 格式导入
|
if (testObject.get("projectName") != null || testObject.get("projectId") != null ) {// metersphere 格式导入
|
||||||
return parseMsFormat(testStr, request);
|
return parseMsFormat(testStr, request);
|
||||||
} else { // chrome 插件录制格式导入
|
} else { // chrome 插件录制格式导入
|
||||||
|
@ -40,7 +51,7 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
|
||||||
testObject.keySet().forEach(tag -> {
|
testObject.keySet().forEach(tag -> {
|
||||||
String moduleId = null;
|
String moduleId = null;
|
||||||
if (isCreateModule) {
|
if (isCreateModule) {
|
||||||
moduleId = ApiDefinitionImportUtil.buildModule(ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()), tag, this.projectId).getId();
|
moduleId = ApiDefinitionImportUtil.buildModule(this.selectModule, tag, this.projectId).getId();
|
||||||
}
|
}
|
||||||
List<MsHTTPSamplerProxy> msHTTPSamplerProxies = parseMsHTTPSamplerProxy(testObject, tag);
|
List<MsHTTPSamplerProxy> msHTTPSamplerProxies = parseMsHTTPSamplerProxy(testObject, tag);
|
||||||
for (MsHTTPSamplerProxy msHTTPSamplerProxy : msHTTPSamplerProxies) {
|
for (MsHTTPSamplerProxy msHTTPSamplerProxy : msHTTPSamplerProxies) {
|
||||||
|
@ -113,13 +124,19 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
|
||||||
modulePath = modulePath.substring(0, modulePath.length() - 1);
|
modulePath = modulePath.substring(0, modulePath.length() - 1);
|
||||||
}
|
}
|
||||||
List<String> modules = Arrays.asList(modulePath.split("/"));
|
List<String> modules = Arrays.asList(modulePath.split("/"));
|
||||||
ApiModule parent = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
|
ApiModule parent = this.selectModule;
|
||||||
Iterator<String> iterator = modules.iterator();
|
Iterator<String> iterator = modules.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
String item = iterator.next();
|
String item = iterator.next();
|
||||||
parent = ApiDefinitionImportUtil.buildModule(parent, item, this.projectId);
|
parent = ApiDefinitionImportUtil.buildModule(parent, item, this.projectId);
|
||||||
if (!iterator.hasNext()) {
|
if (!iterator.hasNext()) {
|
||||||
apiDefinition.setModuleId(parent.getId());
|
apiDefinition.setModuleId(parent.getId());
|
||||||
|
String path = apiDefinition.getModulePath() == null ? "" : apiDefinition.getModulePath();
|
||||||
|
if (StringUtils.isNotBlank(this.selectModulePath)) {
|
||||||
|
apiDefinition.setModulePath(this.selectModulePath + path);
|
||||||
|
} else if (StringUtils.isBlank(importRequest.getModuleId())){
|
||||||
|
apiDefinition.setModulePath("/默认模块" + path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,22 @@ import io.metersphere.api.dto.parse.postman.PostmanKeyValue;
|
||||||
import io.metersphere.api.parse.PostmanAbstractParserParser;
|
import io.metersphere.api.parse.PostmanAbstractParserParser;
|
||||||
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
|
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
|
||||||
import io.metersphere.base.domain.ApiModule;
|
import io.metersphere.base.domain.ApiModule;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
||||||
|
import io.metersphere.base.domain.Project;
|
||||||
|
import io.metersphere.base.mapper.ProjectMapper;
|
||||||
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefinitionImport> {
|
public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefinitionImport> {
|
||||||
|
|
||||||
|
private ApiModule selectModule;
|
||||||
|
|
||||||
|
private String selectModulePath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
|
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
|
||||||
String testStr = getApiTestStr(source);
|
String testStr = getApiTestStr(source);
|
||||||
|
@ -24,33 +33,57 @@ public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefi
|
||||||
List<PostmanKeyValue> variables = postmanCollection.getVariable();
|
List<PostmanKeyValue> variables = postmanCollection.getVariable();
|
||||||
ApiDefinitionImport apiImport = new ApiDefinitionImport();
|
ApiDefinitionImport apiImport = new ApiDefinitionImport();
|
||||||
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
||||||
|
this.selectModule = ApiDefinitionImportUtil.getSelectModule(request.getModuleId());
|
||||||
|
if (this.selectModule != null) {
|
||||||
|
this.selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(this.selectModule.getName(), this.selectModule.getParentId());
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiModule apiModule = ApiDefinitionImportUtil.buildModule(this.selectModule, postmanCollection.getInfo().getName(), this.projectId);
|
||||||
|
List<ApiTestCaseWithBLOBs> cases = new ArrayList<>();
|
||||||
|
Map<String, String> repeatMap = new HashMap();
|
||||||
|
ProjectMapper projectMapper = CommonBeanFactory.getBean(ProjectMapper.class);
|
||||||
|
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
|
||||||
parseItem(postmanCollection.getItem(), variables, results,
|
parseItem(postmanCollection.getItem(), variables, results,
|
||||||
ApiDefinitionImportUtil.buildModule(ApiDefinitionImportUtil.getSelectModule(request.getModuleId()), postmanCollection.getInfo().getName(), this.projectId), true);
|
apiModule, apiModule.getName(), cases, repeatMap, project.getRepeatable());
|
||||||
apiImport.setData(results);
|
apiImport.setData(results);
|
||||||
|
apiImport.setCases(cases);
|
||||||
return apiImport;
|
return apiImport;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void parseItem(List<PostmanItem> items, List<PostmanKeyValue> variables, List<ApiDefinitionWithBLOBs> results, ApiModule parentModule, Boolean isCreateModule) {
|
protected void parseItem(List<PostmanItem> items, List<PostmanKeyValue> variables, List<ApiDefinitionWithBLOBs> results,
|
||||||
|
ApiModule parentModule, String path, List<ApiTestCaseWithBLOBs> cases, Map<String, String> repeatMap, Boolean repeatable) {
|
||||||
for (PostmanItem item : items) {
|
for (PostmanItem item : items) {
|
||||||
List<PostmanItem> childItems = item.getItem();
|
List<PostmanItem> childItems = item.getItem();
|
||||||
if (childItems != null) {
|
if (childItems != null) {
|
||||||
ApiModule module = null;
|
ApiModule module = null;
|
||||||
if (isCreateModule) {
|
|
||||||
module = ApiDefinitionImportUtil.buildModule(parentModule, item.getName(), this.projectId);
|
module = ApiDefinitionImportUtil.buildModule(parentModule, item.getName(), this.projectId);
|
||||||
}
|
parseItem(childItems, variables, results, module, path + "/" + module.getName(), cases, repeatMap, repeatable);
|
||||||
parseItem(childItems, variables, results, module, isCreateModule);
|
|
||||||
} else {
|
} else {
|
||||||
MsHTTPSamplerProxy msHTTPSamplerProxy = parsePostman(item);
|
MsHTTPSamplerProxy msHTTPSamplerProxy = parsePostman(item);
|
||||||
ApiDefinitionWithBLOBs request = buildApiDefinition(msHTTPSamplerProxy.getId(), msHTTPSamplerProxy.getName(),
|
ApiDefinitionWithBLOBs request = buildApiDefinition(msHTTPSamplerProxy.getId(), msHTTPSamplerProxy.getName(),
|
||||||
msHTTPSamplerProxy.getPath(), msHTTPSamplerProxy.getMethod(), new ApiTestImportRequest());
|
msHTTPSamplerProxy.getPath(), msHTTPSamplerProxy.getMethod(), new ApiTestImportRequest());
|
||||||
request.setPath(msHTTPSamplerProxy.getPath());
|
request.setPath(msHTTPSamplerProxy.getPath());
|
||||||
request.setRequest(JSON.toJSONString(msHTTPSamplerProxy));
|
request.setRequest(JSON.toJSONString(msHTTPSamplerProxy));
|
||||||
|
|
||||||
if (request != null) {
|
|
||||||
results.add(request);
|
|
||||||
}
|
|
||||||
if (parentModule != null) {
|
if (parentModule != null) {
|
||||||
request.setModuleId(parentModule.getId());
|
request.setModuleId(parentModule.getId());
|
||||||
|
if (StringUtils.isNotBlank(this.selectModulePath)) {
|
||||||
|
request.setModulePath(this.selectModulePath + "/" + path);
|
||||||
|
} else {
|
||||||
|
request.setModulePath("/" + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request != null) {
|
||||||
|
if (repeatMap.keySet().contains(request.getMethod() + request.getPath())
|
||||||
|
&& (repeatable == null || repeatable == false)) {
|
||||||
|
ApiTestCaseWithBLOBs apiTestCase = new ApiTestCaseWithBLOBs();
|
||||||
|
BeanUtils.copyBean(apiTestCase, request);
|
||||||
|
apiTestCase.setApiDefinitionId(repeatMap.get(request.getMethod() + request.getPath()));
|
||||||
|
apiTestCase.setPriority("P0");
|
||||||
|
cases.add(apiTestCase);
|
||||||
|
} else {
|
||||||
|
repeatMap.put(request.getMethod() + request.getPath(), request.getId());
|
||||||
|
results.add(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,14 @@ public class Swagger2Parser extends SwaggerAbstractParser {
|
||||||
|
|
||||||
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
||||||
|
|
||||||
ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
|
ApiModule selectModule = null;
|
||||||
|
String selectModulePath = null;
|
||||||
|
if (StringUtils.isNotBlank(importRequest.getModuleId())) {
|
||||||
|
selectModule = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
|
||||||
|
if (selectModule != null) {
|
||||||
|
selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String basePath = swagger.getBasePath();
|
String basePath = swagger.getBasePath();
|
||||||
for (String pathName : pathNames) {
|
for (String pathName : pathNames) {
|
||||||
|
@ -76,7 +83,7 @@ public class Swagger2Parser extends SwaggerAbstractParser {
|
||||||
}
|
}
|
||||||
apiDefinition.setRequest(JSON.toJSONString(request));
|
apiDefinition.setRequest(JSON.toJSONString(request));
|
||||||
apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation, operation.getResponses())));
|
apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation, operation.getResponses())));
|
||||||
buildModule(parentNode, apiDefinition, operation.getTags());
|
buildModule(selectModule, apiDefinition, operation.getTags(), selectModulePath);
|
||||||
results.add(apiDefinition);
|
results.add(apiDefinition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,12 @@ import io.swagger.v3.oas.models.parameters.*;
|
||||||
import io.swagger.v3.oas.models.responses.ApiResponse;
|
import io.swagger.v3.oas.models.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.models.responses.ApiResponses;
|
import io.swagger.v3.oas.models.responses.ApiResponses;
|
||||||
import io.swagger.v3.parser.core.models.SwaggerParseResult;
|
import io.swagger.v3.parser.core.models.SwaggerParseResult;
|
||||||
import net.sf.saxon.ma.json.XMLToJsonFn;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.fife.ui.rsyntaxtextarea.parser.XmlParser;
|
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,7 +81,14 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
||||||
|
|
||||||
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
|
||||||
|
|
||||||
ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
|
ApiModule selectModule = null;
|
||||||
|
String selectModulePath = null;
|
||||||
|
if (StringUtils.isNotBlank(importRequest.getModuleId())) {
|
||||||
|
selectModule = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId());
|
||||||
|
if (selectModule != null) {
|
||||||
|
selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (String pathName : pathNames) {
|
for (String pathName : pathNames) {
|
||||||
PathItem pathItem = paths.get(pathName);
|
PathItem pathItem = paths.get(pathName);
|
||||||
|
@ -112,7 +116,7 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
||||||
} // 有数据的话,去掉 Kvs 里初始化的第一个全 null 的数据,否则有空行
|
} // 有数据的话,去掉 Kvs 里初始化的第一个全 null 的数据,否则有空行
|
||||||
apiDefinition.setRequest(JSON.toJSONString(request));
|
apiDefinition.setRequest(JSON.toJSONString(request));
|
||||||
apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation.getResponses())));
|
apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation.getResponses())));
|
||||||
buildModule(parentNode, apiDefinition, operation.getTags());
|
buildModule(selectModule, apiDefinition, operation.getTags(), selectModulePath);
|
||||||
results.add(apiDefinition);
|
results.add(apiDefinition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,23 @@ package io.metersphere.api.dto.definition.parse;
|
||||||
import io.metersphere.api.parse.ApiImportAbstractParser;
|
import io.metersphere.api.parse.ApiImportAbstractParser;
|
||||||
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
|
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
|
||||||
import io.metersphere.base.domain.ApiModule;
|
import io.metersphere.base.domain.ApiModule;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class SwaggerAbstractParser extends ApiImportAbstractParser<ApiDefinitionImport> {
|
public abstract class SwaggerAbstractParser extends ApiImportAbstractParser<ApiDefinitionImport> {
|
||||||
|
|
||||||
protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List<String> tags) {
|
protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition,
|
||||||
|
List<String> tags, String selectModulePath) {
|
||||||
if (tags != null) {
|
if (tags != null) {
|
||||||
tags.forEach(tag -> {
|
tags.forEach(tag -> {
|
||||||
ApiModule module = ApiDefinitionImportUtil.buildModule(parentModule, tag, this.projectId);
|
ApiModule module = ApiDefinitionImportUtil.buildModule(parentModule, tag, this.projectId);
|
||||||
apiDefinition.setModuleId(module.getId());
|
apiDefinition.setModuleId(module.getId());
|
||||||
|
if (StringUtils.isNotBlank(selectModulePath)) {
|
||||||
|
apiDefinition.setModulePath(selectModulePath + "/" + tag);
|
||||||
|
} else {
|
||||||
|
apiDefinition.setModulePath("/" + tag);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ public abstract class MsTestElement {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addCsvDataSet(HashTree tree, List<ScenarioVariable> variables,ParameterConfig config) {
|
protected void addCsvDataSet(HashTree tree, List<ScenarioVariable> variables, ParameterConfig config) {
|
||||||
if (CollectionUtils.isNotEmpty(variables)) {
|
if (CollectionUtils.isNotEmpty(variables)) {
|
||||||
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList());
|
List<ScenarioVariable> list = variables.stream().filter(ScenarioVariable::isCSVValid).collect(Collectors.toList());
|
||||||
if (CollectionUtils.isNotEmpty(list)) {
|
if (CollectionUtils.isNotEmpty(list)) {
|
||||||
|
@ -276,10 +276,7 @@ public abstract class MsTestElement {
|
||||||
if (element.getParent() == null) {
|
if (element.getParent() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (MsTestElementConstants.LoopController.name().equals(element.getType())) {
|
path.append(StringUtils.isEmpty(element.getName()) ? element.getType() : element.getName()).append("^@~@^");
|
||||||
return;
|
|
||||||
}
|
|
||||||
path.append(element.getResourceId()).append("/");
|
|
||||||
getFullPath(element.getParent(), path);
|
getFullPath(element.getParent(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +297,6 @@ public abstract class MsTestElement {
|
||||||
// 获取全路径以备后面使用
|
// 获取全路径以备后面使用
|
||||||
StringBuilder fullPath = new StringBuilder();
|
StringBuilder fullPath = new StringBuilder();
|
||||||
getFullPath(parent, fullPath);
|
getFullPath(parent, fullPath);
|
||||||
|
|
||||||
return fullPath + "<->" + parent.getName();
|
return fullPath + "<->" + parent.getName();
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -369,8 +369,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
headerManager.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() + "HeaderManager" : "HeaderManager");
|
headerManager.setName(StringUtils.isNotEmpty(this.getName()) ? this.getName() + "HeaderManager" : "HeaderManager");
|
||||||
headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
|
headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
|
||||||
headerManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HeaderPanel"));
|
headerManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HeaderPanel"));
|
||||||
|
// header 也支持 mock 参数
|
||||||
headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
|
||||||
headerManager.add(new Header(keyValue.getName(), keyValue.getValue()))
|
headerManager.add(new Header(keyValue.getName(), ScriptEngineUtils.calculate(keyValue.getValue())))
|
||||||
);
|
);
|
||||||
if (headerManager.getHeaders().size() > 0) {
|
if (headerManager.getHeaders().size() > 0) {
|
||||||
tree.add(headerManager);
|
tree.add(headerManager);
|
||||||
|
|
|
@ -66,6 +66,8 @@ public class MsJmeterElement extends MsTestElement {
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||||
for (MsTestElement el : hashTree) {
|
for (MsTestElement el : hashTree) {
|
||||||
|
// 给所有孩子加一个父亲标志
|
||||||
|
el.setParent(this);
|
||||||
el.toHashTree(elementTree, el.getHashTree(), config);
|
el.toHashTree(elementTree, el.getHashTree(), config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package io.metersphere.api.dto.scenario;
|
package io.metersphere.api.dto.scenario;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
import io.metersphere.api.dto.scenario.request.BodyFile;
|
import io.metersphere.api.dto.scenario.request.BodyFile;
|
||||||
import io.metersphere.commons.json.JSONSchemaGenerator;
|
import io.metersphere.commons.json.JSONSchemaGenerator;
|
||||||
import io.metersphere.commons.utils.FileUtils;
|
import io.metersphere.commons.utils.FileUtils;
|
||||||
|
import io.metersphere.commons.utils.ScriptEngineUtils;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -66,8 +70,16 @@ public class Body {
|
||||||
sampler.setDoMultipart(true);
|
sampler.setDoMultipart(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (StringUtils.isNotEmpty(this.format) && "JSON-SCHEMA".equals(this.format) && this.getJsonSchema() != null) {
|
if (StringUtils.isNotEmpty(this.format) && this.getJsonSchema() != null) {
|
||||||
|
if("JSON-SCHEMA".equals(this.format)) {
|
||||||
this.raw = JSONSchemaGenerator.getJson(com.alibaba.fastjson.JSON.toJSONString(this.getJsonSchema()));
|
this.raw = JSONSchemaGenerator.getJson(com.alibaba.fastjson.JSON.toJSONString(this.getJsonSchema()));
|
||||||
|
} else { // json 文本也支持 mock 参数
|
||||||
|
JSONObject jsonObject = com.alibaba.fastjson.JSON.parseObject(this.getRaw());
|
||||||
|
jsonMockParse(jsonObject);
|
||||||
|
// 格式化 json
|
||||||
|
Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
|
||||||
|
this.raw = gson.toJson(jsonObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KeyValue keyValue = new KeyValue("", "JSON-SCHEMA", this.getRaw(), true, true);
|
KeyValue keyValue = new KeyValue("", "JSON-SCHEMA", this.getRaw(), true, true);
|
||||||
sampler.setPostBodyRaw(true);
|
sampler.setPostBodyRaw(true);
|
||||||
|
@ -78,6 +90,18 @@ public class Body {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void jsonMockParse(JSONObject jsonObject) {
|
||||||
|
for(String key : jsonObject.keySet()) {
|
||||||
|
Object value = jsonObject.get(key);
|
||||||
|
if(value instanceof JSONObject) {
|
||||||
|
jsonMockParse((JSONObject) value);
|
||||||
|
} else if(value instanceof String) {
|
||||||
|
value = ScriptEngineUtils.calculate((String) value);
|
||||||
|
jsonObject.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private HTTPFileArg[] httpFileArgs(String requestId) {
|
private HTTPFileArg[] httpFileArgs(String requestId) {
|
||||||
List<HTTPFileArg> list = new ArrayList<>();
|
List<HTTPFileArg> list = new ArrayList<>();
|
||||||
if (CollectionUtils.isNotEmpty(this.getKvs())) {
|
if (CollectionUtils.isNotEmpty(this.getKvs())) {
|
||||||
|
@ -116,6 +140,12 @@ public class Body {
|
||||||
return StringUtils.equals(type, XML);
|
return StringUtils.equals(type, XML);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
this.type = "";
|
||||||
|
this.raw = "";
|
||||||
|
this.format = "";
|
||||||
|
}
|
||||||
|
|
||||||
public void initKvs() {
|
public void initKvs() {
|
||||||
this.kvs = new ArrayList<>();
|
this.kvs = new ArrayList<>();
|
||||||
this.kvs.add(new KeyValue());
|
this.kvs.add(new KeyValue());
|
||||||
|
|
|
@ -43,50 +43,16 @@ public class TestResult {
|
||||||
private static final String SEPARATOR = "<->";
|
private static final String SEPARATOR = "<->";
|
||||||
|
|
||||||
public void addScenario(ScenarioResult result) {
|
public void addScenario(ScenarioResult result) {
|
||||||
Map<String, List<RequestResult>> requestResultMap = new LinkedHashMap<>();
|
|
||||||
if (result != null && CollectionUtils.isNotEmpty(result.getRequestResults())) {
|
if (result != null && CollectionUtils.isNotEmpty(result.getRequestResults())) {
|
||||||
result.getRequestResults().forEach(item -> {
|
result.getRequestResults().forEach(item -> {
|
||||||
if (StringUtils.isNotEmpty(item.getName()) && item.getName().indexOf(SEPARATOR) != -1) {
|
if (StringUtils.isNotEmpty(item.getName()) && item.getName().indexOf(SEPARATOR) != -1) {
|
||||||
String array[] = item.getName().split(SEPARATOR);
|
String array[] = item.getName().split(SEPARATOR);
|
||||||
String scenarioName = item.getName().replace(array[0] + SEPARATOR, "");
|
item.setName(array[1] + array[0]);
|
||||||
item.setName(array[0]);
|
|
||||||
if (requestResultMap.containsKey(scenarioName)) {
|
|
||||||
requestResultMap.get(scenarioName).add(item);
|
|
||||||
} else {
|
|
||||||
List<RequestResult> requestResults = new LinkedList<>();
|
|
||||||
requestResults.add(item);
|
|
||||||
requestResultMap.put(scenarioName, requestResults);
|
|
||||||
}
|
|
||||||
item.getSubRequestResults().forEach(subItem -> {
|
item.getSubRequestResults().forEach(subItem -> {
|
||||||
subItem.setName(item.getName());
|
subItem.setName(array[0]);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (requestResultMap.containsKey(result.getName())) {
|
|
||||||
requestResultMap.get(result.getName()).add(item);
|
|
||||||
} else {
|
|
||||||
List<RequestResult> requestResults = new LinkedList<>();
|
|
||||||
requestResults.add(item);
|
|
||||||
requestResultMap.put(result.getName(), requestResults);
|
|
||||||
}
|
|
||||||
item.getSubRequestResults().forEach(subItem -> {
|
|
||||||
subItem.setName(item.getName());
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!requestResultMap.isEmpty()) {
|
|
||||||
requestResultMap.forEach((k, v) -> {
|
|
||||||
ScenarioResult scenarioResult = new ScenarioResult();
|
|
||||||
BeanUtils.copyBean(scenarioResult, result);
|
|
||||||
scenarioResult.setName(k);
|
|
||||||
if (k.indexOf(SEPARATOR) != -1) {
|
|
||||||
scenarioResult.setName(k.split(SEPARATOR)[1]);
|
|
||||||
}
|
|
||||||
scenarioResult.setRequestResults(v);
|
|
||||||
scenarios.add(scenarioResult);
|
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
scenarios.add(result);
|
scenarios.add(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,20 +198,14 @@ public abstract class ApiImportAbstractParser<T> implements ApiImportParser<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ApiScenarioWithBLOBs parseScenario(MsScenario msScenario) {
|
protected ApiScenarioWithBLOBs parseScenario(MsScenario msScenario) {
|
||||||
// ApiScenarioModule module = ApiScenarioImportUtil.buildModule(ApiScenarioImportUtil.getSelectModule(request.getModuleId()), msScenario.getName(), this.projectId);
|
|
||||||
ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
|
ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
|
||||||
scenarioWithBLOBs.setName(msScenario.getName());
|
scenarioWithBLOBs.setName(msScenario.getName());
|
||||||
scenarioWithBLOBs.setProjectId(this.projectId);
|
scenarioWithBLOBs.setProjectId(this.projectId);
|
||||||
if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) {
|
if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) {
|
||||||
scenarioWithBLOBs.setStepTotal(msScenario.getHashTree().size());
|
scenarioWithBLOBs.setStepTotal(msScenario.getHashTree().size());
|
||||||
}
|
}
|
||||||
// if (module != null) {
|
|
||||||
// scenarioWithBLOBs.setApiScenarioModuleId(module.getId());
|
|
||||||
// scenarioWithBLOBs.setModulePath("/" + module.getName());
|
|
||||||
// }
|
|
||||||
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
|
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
|
||||||
scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario));
|
scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario));
|
||||||
return scenarioWithBLOBs;
|
return scenarioWithBLOBs;
|
||||||
// scenarioWithBLOBsList.add(scenarioWithBLOBs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,6 +240,19 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ApiDefinition> getSameRequestWithName(SaveApiDefinitionRequest request) {
|
||||||
|
ApiDefinitionExample example = new ApiDefinitionExample();
|
||||||
|
example.createCriteria()
|
||||||
|
.andMethodEqualTo(request.getMethod())
|
||||||
|
.andStatusNotEqualTo("Trash")
|
||||||
|
.andPathEqualTo(request.getPath())
|
||||||
|
.andNameEqualTo(request.getName())
|
||||||
|
.andProjectIdEqualTo(request.getProjectId())
|
||||||
|
.andIdNotEqualTo(request.getId());
|
||||||
|
return apiDefinitionMapper.selectByExample(example);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private ApiDefinition updateTest(SaveApiDefinitionRequest request) {
|
private ApiDefinition updateTest(SaveApiDefinitionRequest request) {
|
||||||
checkNameExist(request);
|
checkNameExist(request);
|
||||||
if (StringUtils.equals(request.getMethod(), "ESB")) {
|
if (StringUtils.equals(request.getMethod(), "ESB")) {
|
||||||
|
@ -322,7 +335,8 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApiDefinition importCreate(ApiDefinitionWithBLOBs apiDefinition, ApiDefinitionMapper batchMapper,
|
private ApiDefinition importCreate(ApiDefinitionWithBLOBs apiDefinition, ApiDefinitionMapper batchMapper,
|
||||||
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases) {
|
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases,
|
||||||
|
Boolean repeatable) {
|
||||||
SaveApiDefinitionRequest saveReq = new SaveApiDefinitionRequest();
|
SaveApiDefinitionRequest saveReq = new SaveApiDefinitionRequest();
|
||||||
BeanUtils.copyBean(saveReq, apiDefinition);
|
BeanUtils.copyBean(saveReq, apiDefinition);
|
||||||
apiDefinition.setCreateTime(System.currentTimeMillis());
|
apiDefinition.setCreateTime(System.currentTimeMillis());
|
||||||
|
@ -335,7 +349,13 @@ public class ApiDefinitionService {
|
||||||
}
|
}
|
||||||
apiDefinition.setDescription(apiDefinition.getDescription());
|
apiDefinition.setDescription(apiDefinition.getDescription());
|
||||||
|
|
||||||
List<ApiDefinition> sameRequest = getSameRequest(saveReq);
|
List<ApiDefinition> sameRequest;
|
||||||
|
if (repeatable == null || repeatable == false) {
|
||||||
|
sameRequest = getSameRequest(saveReq);
|
||||||
|
} else {
|
||||||
|
// 如果勾选了允许重复,则判断更新要加上name字段
|
||||||
|
sameRequest = getSameRequestWithName(saveReq);
|
||||||
|
}
|
||||||
if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) {
|
if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) {
|
||||||
_importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest, cases);
|
_importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, apiTestImportRequest, cases);
|
||||||
} else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) {
|
} else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) {
|
||||||
|
@ -373,6 +393,8 @@ public class ApiDefinitionService {
|
||||||
//如果存在则修改
|
//如果存在则修改
|
||||||
apiDefinition.setId(sameRequest.get(0).getId());
|
apiDefinition.setId(sameRequest.get(0).getId());
|
||||||
String request = setImportHashTree(apiDefinition);
|
String request = setImportHashTree(apiDefinition);
|
||||||
|
apiDefinition.setModuleId(sameRequest.get(0).getModuleId());
|
||||||
|
apiDefinition.setModulePath(sameRequest.get(0).getModulePath());
|
||||||
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
|
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
|
||||||
apiDefinition.setRequest(request);
|
apiDefinition.setRequest(request);
|
||||||
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, false);
|
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, false);
|
||||||
|
@ -415,15 +437,13 @@ public class ApiDefinitionService {
|
||||||
|
|
||||||
private void importMsCase(ApiDefinitionImport apiImport, SqlSession sqlSession, ApiTestCaseMapper apiTestCaseMapper) {
|
private void importMsCase(ApiDefinitionImport apiImport, SqlSession sqlSession, ApiTestCaseMapper apiTestCaseMapper) {
|
||||||
List<ApiTestCaseWithBLOBs> cases = apiImport.getCases();
|
List<ApiTestCaseWithBLOBs> cases = apiImport.getCases();
|
||||||
List<String> caseNames = apiTestCaseService.listPorjectAllCaseName(SessionUtils.getCurrentProjectId());
|
SaveApiTestCaseRequest checkRequest = new SaveApiTestCaseRequest();
|
||||||
Set<String> existCaseName = new HashSet<>();
|
|
||||||
caseNames.forEach(item -> {
|
|
||||||
existCaseName.add(item);
|
|
||||||
});
|
|
||||||
if (CollectionUtils.isNotEmpty(cases)) {
|
if (CollectionUtils.isNotEmpty(cases)) {
|
||||||
int batchCount = 0;
|
int batchCount = 0;
|
||||||
cases.forEach(item -> {
|
cases.forEach(item -> {
|
||||||
if (!existCaseName.contains(item.getName())) {
|
checkRequest.setName(item.getName());
|
||||||
|
checkRequest.setApiDefinitionId(item.getApiDefinitionId());
|
||||||
|
if (!apiTestCaseService.hasSameCase(checkRequest)) {
|
||||||
item.setId(UUID.randomUUID().toString());
|
item.setId(UUID.randomUUID().toString());
|
||||||
item.setCreateTime(System.currentTimeMillis());
|
item.setCreateTime(System.currentTimeMillis());
|
||||||
item.setUpdateTime(System.currentTimeMillis());
|
item.setUpdateTime(System.currentTimeMillis());
|
||||||
|
@ -613,6 +633,7 @@ public class ApiDefinitionService {
|
||||||
List<ApiDefinitionWithBLOBs> data = apiImport.getData();
|
List<ApiDefinitionWithBLOBs> data = apiImport.getData();
|
||||||
ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class);
|
ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class);
|
||||||
ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
|
ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
|
||||||
|
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
|
||||||
int num = 0;
|
int num = 0;
|
||||||
if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) {
|
if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) {
|
||||||
num = getNextNum(data.get(0).getProjectId());
|
num = getNextNum(data.get(0).getProjectId());
|
||||||
|
@ -628,14 +649,14 @@ public class ApiDefinitionService {
|
||||||
if (apiImport.getEsbApiParamsMap() != null) {
|
if (apiImport.getEsbApiParamsMap() != null) {
|
||||||
String apiId = item.getId();
|
String apiId = item.getId();
|
||||||
EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId);
|
EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId);
|
||||||
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
|
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases(), project.getRepeatable());
|
||||||
if (model != null) {
|
if (model != null) {
|
||||||
apiImport.getEsbApiParamsMap().remove(apiId);
|
apiImport.getEsbApiParamsMap().remove(apiId);
|
||||||
model.setResourceId(item.getId());
|
model.setResourceId(item.getId());
|
||||||
apiImport.getEsbApiParamsMap().put(item.getId(), model);
|
apiImport.getEsbApiParamsMap().put(item.getId(), model);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
|
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases(), project.getRepeatable());
|
||||||
}
|
}
|
||||||
if (i % 300 == 0) {
|
if (i % 300 == 0) {
|
||||||
sqlSession.flushStatements();
|
sqlSession.flushStatements();
|
||||||
|
|
|
@ -275,6 +275,9 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
|
||||||
@Override
|
@Override
|
||||||
public ApiModuleDTO getNode(String id) {
|
public ApiModuleDTO getNode(String id) {
|
||||||
ApiModule module = apiModuleMapper.selectByPrimaryKey(id);
|
ApiModule module = apiModuleMapper.selectByPrimaryKey(id);
|
||||||
|
if (module == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
ApiModuleDTO dto = JSON.parseObject(JSON.toJSONString(module), ApiModuleDTO.class);
|
ApiModuleDTO dto = JSON.parseObject(JSON.toJSONString(module), ApiModuleDTO.class);
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,6 @@ public class ApiTestCaseService {
|
||||||
|
|
||||||
private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR;
|
private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR;
|
||||||
|
|
||||||
public List<String> listPorjectAllCaseName(String projectId) {
|
|
||||||
return extApiTestCaseMapper.listPorjectAllCaseName(projectId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ApiTestCaseResult> list(ApiTestCaseRequest request) {
|
public List<ApiTestCaseResult> list(ApiTestCaseRequest request) {
|
||||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||||
List<ApiTestCaseResult> returnList = extApiTestCaseMapper.list(request);
|
List<ApiTestCaseResult> returnList = extApiTestCaseMapper.list(request);
|
||||||
|
@ -233,14 +229,24 @@ public class ApiTestCaseService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNameExist(SaveApiTestCaseRequest request) {
|
public void checkNameExist(SaveApiTestCaseRequest request) {
|
||||||
ApiTestCaseExample example = new ApiTestCaseExample();
|
if (hasSameCase(request)) {
|
||||||
example.createCriteria().andNameEqualTo(request.getName()).andApiDefinitionIdEqualTo(request.getApiDefinitionId()).andIdNotEqualTo(request.getId());
|
|
||||||
if (apiTestCaseMapper.countByExample(example) > 0) {
|
|
||||||
MSException.throwException(Translator.get("load_test_already_exists"));
|
MSException.throwException(Translator.get("load_test_already_exists"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean hasSameCase(SaveApiTestCaseRequest request) {
|
||||||
|
ApiTestCaseExample example = new ApiTestCaseExample();
|
||||||
|
ApiTestCaseExample.Criteria criteria = example.createCriteria();
|
||||||
|
criteria.andNameEqualTo(request.getName()).andApiDefinitionIdEqualTo(request.getApiDefinitionId());
|
||||||
|
if (StringUtils.isNotBlank(request.getId())) {
|
||||||
|
criteria.andIdNotEqualTo(request.getId());
|
||||||
|
}
|
||||||
|
if (apiTestCaseMapper.countByExample(example) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private ApiTestCase updateTest(SaveApiTestCaseRequest request) {
|
private ApiTestCase updateTest(SaveApiTestCaseRequest request) {
|
||||||
checkNameExist(request);
|
checkNameExist(request);
|
||||||
|
|
|
@ -12,8 +12,6 @@ import java.util.List;
|
||||||
|
|
||||||
public interface ExtApiTestCaseMapper {
|
public interface ExtApiTestCaseMapper {
|
||||||
|
|
||||||
List<String> listPorjectAllCaseName(@Param("projectId") String projectId);
|
|
||||||
|
|
||||||
List<ApiTestCaseResult> list(@Param("request") ApiTestCaseRequest request);
|
List<ApiTestCaseResult> list(@Param("request") ApiTestCaseRequest request);
|
||||||
|
|
||||||
List<ApiTestCaseDTO> listSimple(@Param("request") ApiTestCaseRequest request);
|
List<ApiTestCaseDTO> listSimple(@Param("request") ApiTestCaseRequest request);
|
||||||
|
|
|
@ -391,9 +391,6 @@
|
||||||
<select id="getNextNum" resultType="io.metersphere.base.domain.ApiTestCase">
|
<select id="getNextNum" resultType="io.metersphere.base.domain.ApiTestCase">
|
||||||
SELECT * FROM api_test_case WHERE api_test_case.api_definition_id = #{definitionId} ORDER BY num DESC LIMIT 1;
|
SELECT * FROM api_test_case WHERE api_test_case.api_definition_id = #{definitionId} ORDER BY num DESC LIMIT 1;
|
||||||
</select>
|
</select>
|
||||||
<select id="listPorjectAllCaseName" resultType="java.lang.String">
|
|
||||||
select name from api_test_case where project_id = #{projectId}
|
|
||||||
</select>
|
|
||||||
<select id="selectEffectiveTestCaseByProjectId" resultType="io.metersphere.base.domain.ApiTestCase">
|
<select id="selectEffectiveTestCaseByProjectId" resultType="io.metersphere.base.domain.ApiTestCase">
|
||||||
select id,api_definition_id from api_test_case where project_id = #{projectId}
|
select id,api_definition_id from api_test_case where project_id = #{projectId}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -79,7 +79,7 @@ public class EngineFactory {
|
||||||
}
|
}
|
||||||
if (type == ResourcePoolTypeEnum.K8S) {
|
if (type == ResourcePoolTypeEnum.K8S) {
|
||||||
try {
|
try {
|
||||||
return ConstructorUtils.invokeConstructor(kubernetesTestEngineClass, loadTest);
|
return (Engine) ConstructorUtils.invokeConstructor(kubernetesTestEngineClass, loadTest);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error(e);
|
LogUtil.error(e);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build",
|
"build": "export NODE_OPTIONS=--max_old_space_size=4096 && vue-cli-service build",
|
||||||
|
"build-win": "SET NODE_OPTIONS=--max_old_space_size=4096 && vue-cli-service build",
|
||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -49,7 +50,7 @@
|
||||||
"vue-float-action-button": "^0.6.6",
|
"vue-float-action-button": "^0.6.6",
|
||||||
"vue-i18n": "^8.15.3",
|
"vue-i18n": "^8.15.3",
|
||||||
"vue-jsonpath-picker": "^1.1.5",
|
"vue-jsonpath-picker": "^1.1.5",
|
||||||
"vue-minder-editor-plus": "^1.0.19",
|
"vue-minder-editor-plus": "^1.0.21",
|
||||||
"vue-papa-parse": "^2.0.0",
|
"vue-papa-parse": "^2.0.0",
|
||||||
"vue-pdf": "^4.2.0",
|
"vue-pdf": "^4.2.0",
|
||||||
"vue-router": "^3.1.3",
|
"vue-router": "^3.1.3",
|
||||||
|
|
|
@ -3,26 +3,21 @@
|
||||||
<ms-main-container>
|
<ms-main-container>
|
||||||
<el-card>
|
<el-card>
|
||||||
<section class="report-container" v-if="this.report.testId">
|
<section class="report-container" v-if="this.report.testId">
|
||||||
|
|
||||||
<ms-api-report-view-header :debug="debug" :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
|
<ms-api-report-view-header :debug="debug" :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
|
||||||
|
<main v-if="isNotRunning">
|
||||||
<main v-if="this.isNotRunning">
|
|
||||||
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
||||||
<div>
|
<div>
|
||||||
<!--<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>-->
|
|
||||||
|
|
||||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||||
<el-tab-pane :label="$t('api_report.total')" name="total">
|
<el-tab-pane :label="$t('api_report.total')" name="total">
|
||||||
<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>
|
<ms-scenario-results :treeData="fullTreeNodes" v-on:requestResult="requestResult"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane name="fail">
|
<el-tab-pane name="fail">
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<span class="fail">{{ $t('api_report.fail') }}</span>
|
<span class="fail">{{ $t('api_report.fail') }}</span>
|
||||||
</template>
|
</template>
|
||||||
<ms-scenario-results v-on:requestResult="requestResult" :scenarios="fails"/>
|
<ms-scenario-results v-on:requestResult="requestResult" :treeData="failsTreeNodes"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<ms-api-report-export v-if="reportExportVisible" id="apiTestReport" :title="report.testName"
|
<ms-api-report-export v-if="reportExportVisible" id="apiTestReport" :title="report.testName"
|
||||||
:content="content" :total-time="totalTime"/>
|
:content="content" :total-time="totalTime"/>
|
||||||
|
@ -62,6 +57,7 @@
|
||||||
report: {},
|
report: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
fails: [],
|
fails: [],
|
||||||
|
failsTreeNodes: [],
|
||||||
totalTime: 0,
|
totalTime: 0,
|
||||||
isRequestResult: false,
|
isRequestResult: false,
|
||||||
request: {},
|
request: {},
|
||||||
|
@ -69,6 +65,7 @@
|
||||||
scenarioName: null,
|
scenarioName: null,
|
||||||
reportExportVisible: false,
|
reportExportVisible: false,
|
||||||
requestType: undefined,
|
requestType: undefined,
|
||||||
|
fullTreeNodes: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
activated() {
|
activated() {
|
||||||
|
@ -92,6 +89,8 @@
|
||||||
this.content = {};
|
this.content = {};
|
||||||
this.fails = [];
|
this.fails = [];
|
||||||
this.report = {};
|
this.report = {};
|
||||||
|
this.fullTreeNodes = [];
|
||||||
|
this.failsTreeNodes = [];
|
||||||
this.isRequestResult = false;
|
this.isRequestResult = false;
|
||||||
},
|
},
|
||||||
handleClick(tab, event) {
|
handleClick(tab, event) {
|
||||||
|
@ -102,17 +101,88 @@
|
||||||
},
|
},
|
||||||
formatResult(res) {
|
formatResult(res) {
|
||||||
let resMap = new Map;
|
let resMap = new Map;
|
||||||
|
let array = [];
|
||||||
|
let i = 0;
|
||||||
if (res && res.scenarios) {
|
if (res && res.scenarios) {
|
||||||
res.scenarios.forEach(item => {
|
res.scenarios.forEach(item => {
|
||||||
if (item && item.requestResults) {
|
if (item && item.requestResults) {
|
||||||
item.requestResults.forEach(req => {
|
item.requestResults.forEach(req => {
|
||||||
resMap.set(req.id, req);
|
resMap.set(req.id, req);
|
||||||
|
req.index = i;
|
||||||
|
i++;
|
||||||
|
array.push(req);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
this.formatTree(array, this.fullTreeNodes);
|
||||||
|
this.sort(this.fullTreeNodes);
|
||||||
this.$emit('refresh', resMap);
|
this.$emit('refresh', resMap);
|
||||||
},
|
},
|
||||||
|
formatTree(array, tree) {
|
||||||
|
array.map((item) => {
|
||||||
|
let key = item.name;
|
||||||
|
let nodeArray = key.split('^@~@^');
|
||||||
|
let children = tree;
|
||||||
|
// 循环构建子节点
|
||||||
|
for (let i in nodeArray) {
|
||||||
|
if (!nodeArray[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let node = {
|
||||||
|
label: nodeArray[i],
|
||||||
|
value: item,
|
||||||
|
};
|
||||||
|
if (i !== nodeArray.length) {
|
||||||
|
node.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children.length === 0) {
|
||||||
|
children.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
let isExist = false;
|
||||||
|
for (let j in children) {
|
||||||
|
if (children[j].label === node.label) {
|
||||||
|
if (i !== nodeArray.length - 1 && !children[j].children) {
|
||||||
|
children[j].children = [];
|
||||||
|
}
|
||||||
|
children = (i === nodeArray.length - 1 ? children : children[j].children);
|
||||||
|
isExist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isExist) {
|
||||||
|
children.push(node);
|
||||||
|
if (i !== nodeArray.length - 1 && !children[children.length - 1].children) {
|
||||||
|
children[children.length - 1].children = [];
|
||||||
|
}
|
||||||
|
children = (i === nodeArray.length - 1 ? children : children[children.length - 1].children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
recursiveSorting(arr) {
|
||||||
|
for (let i in arr) {
|
||||||
|
if (arr[i]) {
|
||||||
|
arr[i].index = Number(i) + 1;
|
||||||
|
if (arr[i].children && arr[i].children.length > 0) {
|
||||||
|
this.recursiveSorting(arr[i].children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sort(scenarioDefinition) {
|
||||||
|
for (let i in scenarioDefinition) {
|
||||||
|
// 排序
|
||||||
|
if (scenarioDefinition[i]) {
|
||||||
|
scenarioDefinition[i].index = Number(i) + 1;
|
||||||
|
if (scenarioDefinition[i].children && scenarioDefinition[i].children.length > 0) {
|
||||||
|
this.recursiveSorting(scenarioDefinition[i].children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
getReport() {
|
getReport() {
|
||||||
this.init();
|
this.init();
|
||||||
if (this.reportId) {
|
if (this.reportId) {
|
||||||
|
@ -146,6 +216,7 @@
|
||||||
getFails() {
|
getFails() {
|
||||||
if (this.isNotRunning) {
|
if (this.isNotRunning) {
|
||||||
this.fails = [];
|
this.fails = [];
|
||||||
|
let array = [];
|
||||||
this.totalTime = 0
|
this.totalTime = 0
|
||||||
if (this.content.scenarios) {
|
if (this.content.scenarios) {
|
||||||
this.content.scenarios.forEach((scenario) => {
|
this.content.scenarios.forEach((scenario) => {
|
||||||
|
@ -158,11 +229,14 @@
|
||||||
if (!request.success) {
|
if (!request.success) {
|
||||||
let failRequest = Object.assign({}, request);
|
let failRequest = Object.assign({}, request);
|
||||||
failScenario.requestResults.push(failRequest);
|
failScenario.requestResults.push(failRequest);
|
||||||
|
array.push(request);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
this.formatTree(array, this.failsTreeNodes);
|
||||||
|
this.sort(this.failsTreeNodes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computeTotalTime() {
|
computeTotalTime() {
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
|
<el-card class="ms-cards">
|
||||||
<div class="request-result">
|
<div class="request-result">
|
||||||
<p class="el-divider--horizontal"></p>
|
|
||||||
<div @click="active">
|
<div @click="active">
|
||||||
<el-row :gutter="10" type="flex" align="middle" class="info">
|
<el-row :gutter="10" type="flex" align="middle" class="info">
|
||||||
<el-col :span="14" v-if="indexNumber!=undefined">
|
<el-col :span="10" v-if="indexNumber!=undefined">
|
||||||
<div class="method">
|
<div class="method">
|
||||||
<div class="el-step__icon is-text ms-api-col" v-if="indexNumber%2 ==0">
|
<div class="el-step__icon is-text ms-api-col-create">
|
||||||
<div class="el-step__icon-inner"> {{ indexNumber+1 }}</div>
|
<div class="el-step__icon-inner"> {{ indexNumber }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="el-step__icon is-text ms-api-col-create" v-else>
|
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}" @click="active" @click.stop/>
|
||||||
<div class="el-step__icon-inner"> {{ indexNumber+1 }}</div>
|
{{ getName(request.name) }}
|
||||||
</div>
|
|
||||||
{{ request.name }}
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="9">
|
||||||
<el-col :span="5">
|
|
||||||
<el-tooltip effect="dark" :content="request.responseResult.responseCode" placement="bottom" :open-delay="800">
|
<el-tooltip effect="dark" :content="request.responseResult.responseCode" placement="bottom" :open-delay="800">
|
||||||
<div style="color: #5daf34" v-if="request.success">{{ request.responseResult.responseCode }}</div>
|
<div style="color: #5daf34" v-if="request.success">
|
||||||
<div style="color: #FE6F71" v-else>{{ request.responseResult.responseCode }}</div>
|
{{ request.responseResult.responseCode }}
|
||||||
|
</div>
|
||||||
|
<div style="color: #FE6F71" v-else>
|
||||||
|
{{ request.responseResult.responseCode }}
|
||||||
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="3">
|
<el-col :span="3">
|
||||||
|
@ -29,7 +30,6 @@
|
||||||
{{request.responseResult.responseTime}} ms
|
{{request.responseResult.responseTime}} ms
|
||||||
</span>
|
</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="2">
|
<el-col :span="2">
|
||||||
<div>
|
<div>
|
||||||
<el-tag size="mini" type="success" v-if="request.success">
|
<el-tag size="mini" type="success" v-if="request.success">
|
||||||
|
@ -45,11 +45,14 @@
|
||||||
|
|
||||||
<el-collapse-transition>
|
<el-collapse-transition>
|
||||||
<div v-show="isActive" style="width: 99%">
|
<div v-show="isActive" style="width: 99%">
|
||||||
<ms-request-result-tail v-if="isActive" :request-type="requestType" :request="request"
|
<ms-request-result-tail :scenario-name="scenarioName"
|
||||||
:scenario-name="scenarioName"/>
|
:request-type="requestType"
|
||||||
|
:request="request"
|
||||||
|
v-if="isActive"/>
|
||||||
</div>
|
</div>
|
||||||
</el-collapse-transition>
|
</el-collapse-transition>
|
||||||
</div>
|
</div>
|
||||||
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -61,19 +64,46 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsRequestResult",
|
name: "MsRequestResult",
|
||||||
components: {MsResponseText, MsRequestText, MsAssertionResults, MsRequestMetric, MsRequestResultTail},
|
components: {
|
||||||
|
MsResponseText,
|
||||||
|
MsRequestText,
|
||||||
|
MsAssertionResults,
|
||||||
|
MsRequestMetric,
|
||||||
|
MsRequestResultTail
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
request: Object,
|
request: Object,
|
||||||
scenarioName: String,
|
scenarioName: String,
|
||||||
indexNumber: Number,
|
indexNumber: Number,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {isActive: false, requestType: undefined,}
|
return {
|
||||||
|
isActive: false,
|
||||||
|
requestType: "",
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return "#B8741A";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return "#F9F1EA";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
active() {
|
active() {
|
||||||
this.isActive = !this.isActive;
|
this.isActive = !this.isActive;
|
||||||
//this.$emit("requestResult", {request: this.request, scenarioName: this.scenarioName});
|
},
|
||||||
|
getName(name) {
|
||||||
|
if (name && name.indexOf("^@~@^") !== -1) {
|
||||||
|
let arr = name.split("^@~@^");
|
||||||
|
return arr[arr.length - 1];
|
||||||
|
}
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -81,8 +111,7 @@
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.request-result {
|
.request-result {
|
||||||
width: 100%;
|
min-height: 30px;
|
||||||
min-height: 40px;
|
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +124,7 @@
|
||||||
color: #1E90FF;
|
color: #1E90FF;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 40px;
|
line-height: 35px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +157,10 @@
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-cards >>> .el-card__body {
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.sub-result:last-child {
|
.sub-result:last-child {
|
||||||
border-bottom: 1px solid #EBEEF5;
|
border-bottom: 1px solid #EBEEF5;
|
||||||
}
|
}
|
||||||
|
@ -148,10 +181,20 @@
|
||||||
color: #008080;
|
color: #008080;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/deep/ .el-step__icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-divider--horizontal {
|
.el-divider--horizontal {
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
background: 0 0;
|
background: 0 0;
|
||||||
border-top: 1px solid #e8eaec;
|
border-top: 1px solid #e8eaec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon.is-active {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,24 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="scenario-result" v-if="scenario && scenario.requestResults && scenario.requestResults.length>0">
|
<div class="scenario-result">
|
||||||
|
<div v-if="node.children && node.children.length >0 ">
|
||||||
<div @click="active">
|
<el-card class="ms-card">
|
||||||
<el-row :gutter="10" type="flex" align="middle" class="info">
|
<div class="el-step__icon is-text ms-api-col">
|
||||||
<el-col :span="16">
|
<div class="el-step__icon-inner"> {{ node.index }}</div>
|
||||||
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
|
|
||||||
{{scenario.name}}
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
</div>
|
||||||
<el-collapse-transition>
|
{{node.label}}
|
||||||
<div v-show="isActive">
|
|
||||||
<div v-for="(request, index) in scenario.requestResults" :key="index">
|
</el-card>
|
||||||
<ms-request-result :key="index" :request="request" :indexNumber="index"
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<ms-request-result :request="node.value" :indexNumber="node.index"
|
||||||
v-on:requestResult="requestResult"
|
v-on:requestResult="requestResult"
|
||||||
:scenarioName="scenario.name"/>
|
:scenarioName="node.label"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</el-collapse-transition>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -27,11 +22,10 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsScenarioResult",
|
name: "MsScenarioResult",
|
||||||
|
|
||||||
components: {MsRequestResult},
|
components: {MsRequestResult},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
scenario: Object,
|
scenario: Object,
|
||||||
|
node: Object,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@ -69,6 +63,10 @@
|
||||||
border-top: 1px solid #DCDFE6;
|
border-top: 1px solid #DCDFE6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-card >>> .el-card__body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.scenario-result .info {
|
.scenario-result .info {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -82,4 +80,25 @@
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-api-col {
|
||||||
|
background-color: #EFF0F0;
|
||||||
|
border-color: #EFF0F0;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #64666A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-api-col-create {
|
||||||
|
background-color: #EBF2F2;
|
||||||
|
border-color: #008080;
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #008080;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-step__icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<el-card class="scenario-results">
|
<el-card class="scenario-results">
|
||||||
<ms-scenario-result v-for="(scenario, index) in scenarios" :key="index" :scenario="scenario" :indexNumber="index"
|
<el-tree :data="treeData"
|
||||||
v-on:requestResult="requestResult"/>
|
:expand-on-click-node="false"
|
||||||
|
highlight-current
|
||||||
|
class="ms-tree ms-report-tree">
|
||||||
|
<span slot-scope="{ node, data}" style="width: 99%" @click="nodeClick(node)">
|
||||||
|
<ms-scenario-result :node="data" v-on:requestResult="requestResult"/>
|
||||||
|
</span>
|
||||||
|
</el-tree>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -10,26 +16,61 @@
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsScenarioResults",
|
name: "MsScenarioResults",
|
||||||
|
|
||||||
components: {MsScenarioResult},
|
components: {MsScenarioResult},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
scenarios: Array
|
scenarios: Array,
|
||||||
|
treeData: Array,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
requestResult(requestResult) {
|
requestResult(requestResult) {
|
||||||
this.$emit("requestResult", requestResult);
|
this.$emit("requestResult", requestResult);
|
||||||
|
},
|
||||||
|
nodeClick(node) {
|
||||||
|
node.expanded = !node.expanded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.scenario-header {
|
.scenario-results {
|
||||||
border: 1px solid #EBEEF5;
|
height: 100%;
|
||||||
background-color: #F9FCFF;
|
|
||||||
border-left: 0;
|
|
||||||
border-right: 0;
|
|
||||||
padding: 5px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ms-report-tree >>> .el-tree-node__content {
|
||||||
|
height: 100%;
|
||||||
|
vertical-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-drawer__body {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-step__icon.is-text {
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-drawer__header {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-link {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-checkbox {
|
||||||
|
color: #303133;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .el-checkbox__label {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ms-sc-variable-header >>> .el-dialog__body {
|
||||||
|
padding: 0px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
<ms-table-header-select-popover v-show="total>0"
|
<ms-table-header-select-popover v-show="total>0"
|
||||||
:page-size="pageSize>total?total:pageSize"
|
:page-size="pageSize>total?total:pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
|
:select-data-counts="selectDataCounts"
|
||||||
@selectPageAll="isSelectDataAll(false)"
|
@selectPageAll="isSelectDataAll(false)"
|
||||||
@selectAll="isSelectDataAll(true)"/>
|
@selectAll="isSelectDataAll(true)"/>
|
||||||
|
|
||||||
|
@ -617,7 +618,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleSelectAll(selection) {
|
handleSelectAll(selection) {
|
||||||
_handleSelectAll(this, selection, this.tableData, this.selectRows);
|
_handleSelectAll(this, selection, this.tableData, this.selectRows, this.condition);
|
||||||
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
||||||
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
||||||
this.$emit('selection', selection);
|
this.$emit('selection', selection);
|
||||||
|
|
|
@ -1210,7 +1210,7 @@
|
||||||
|
|
||||||
/deep/ .el-tree-node__content {
|
/deep/ .el-tree-node__content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-top: 8px;
|
margin-top: 3px;
|
||||||
vertical-align: center;
|
vertical-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<i class="icon el-icon-arrow-right" :class="{'is-active': data.active}"
|
<i class="icon el-icon-arrow-right" :class="{'is-active': data.active}"
|
||||||
@click="active(data)" v-if="data.type!='scenario' && !isMax " @click.stop/>
|
@click="active(data)" v-if="data.type!='scenario' && !isMax " @click.stop/>
|
||||||
<span @click.stop v-if="isShowInput && isShowNameInput">
|
<span @click.stop v-if="isShowInput && isShowNameInput">
|
||||||
<el-input :draggable="draggable" size="mini" v-model="data.name" class="name-input"
|
<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"/>
|
@blur="isShowInput = false" :placeholder="$t('commons.input_name')" ref="nameEdit" :disabled="data.disabled"/>
|
||||||
</span>
|
</span>
|
||||||
<span :class="isMax?'ms-step-name':'scenario-name'" v-else>
|
<span :class="isMax?'ms-step-name':'scenario-name'" v-else>
|
||||||
|
|
|
@ -28,8 +28,24 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col class="item">
|
<el-col class="item">
|
||||||
<el-input :disabled="isReadOnly" v-model="item.value" size="small" @change="change"
|
<el-input v-if="!needMock" :disabled="isReadOnly" v-model="item.value" size="small" @change="change"
|
||||||
:placeholder="valueText" show-word-limit/>
|
:placeholder="valueText" show-word-limit/>
|
||||||
|
<div v-if="needMock">
|
||||||
|
<el-autocomplete
|
||||||
|
:disabled="isReadOnly"
|
||||||
|
@change="change"
|
||||||
|
:placeholder="valueText"
|
||||||
|
size="small"
|
||||||
|
style="width: 100%;"
|
||||||
|
v-model="item.value"
|
||||||
|
value-key="name"
|
||||||
|
:fetch-suggestions="funcSearch"
|
||||||
|
highlight-first-item
|
||||||
|
show-word-limit>
|
||||||
|
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced"></i>
|
||||||
|
</el-autocomplete>
|
||||||
|
<ms-api-variable-advance ref="variableAdvance"/>
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col class="item kv-delete">
|
<el-col class="item kv-delete">
|
||||||
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
|
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
|
||||||
|
@ -43,10 +59,13 @@
|
||||||
<script>
|
<script>
|
||||||
import {KeyValue} from "../model/ApiTestModel";
|
import {KeyValue} from "../model/ApiTestModel";
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import MsApiVariableAdvance from "./ApiVariableAdvance";
|
||||||
|
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiKeyValue",
|
name: "MsApiKeyValue",
|
||||||
|
components: {MsApiVariableAdvance},
|
||||||
props: {
|
props: {
|
||||||
keyPlaceholder: String,
|
keyPlaceholder: String,
|
||||||
valuePlaceholder: String,
|
valuePlaceholder: String,
|
||||||
|
@ -60,6 +79,10 @@
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
suggestions: Array,
|
suggestions: Array,
|
||||||
|
needMock: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -86,6 +109,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
advanced() {
|
||||||
|
this.$refs.variableAdvance.open();
|
||||||
|
},
|
||||||
|
funcFilter(queryString) {
|
||||||
|
return (func) => {
|
||||||
|
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
funcSearch(queryString, cb) {
|
||||||
|
let funcs = MOCKJS_FUNC.concat(JMETER_FUNC);
|
||||||
|
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
|
||||||
|
// 调用 callback 返回建议列表的数据
|
||||||
|
cb(results);
|
||||||
|
},
|
||||||
moveBottom(index) {
|
moveBottom(index) {
|
||||||
if (this.items.length < 2 || index === this.items.length - 2) {
|
if (this.items.length < 2 || index === this.items.length - 2) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col class="item" v-if="item.type !== 'file'">
|
<el-col class="item" v-if="isActive && item.type !== 'file'">
|
||||||
<el-autocomplete
|
<el-autocomplete
|
||||||
:disabled="isReadOnly"
|
:disabled="isReadOnly"
|
||||||
size="small"
|
size="small"
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
|
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col v-if="item.type === 'file'" class="item">
|
<el-col v-if="isActive && item.type === 'file'" class="item">
|
||||||
<ms-api-body-file-upload :parameter="item"/>
|
<ms-api-body-file-upload :parameter="item"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
@ -126,6 +126,7 @@
|
||||||
currentItem: null,
|
currentItem: null,
|
||||||
requireds: REQUIRED,
|
requireds: REQUIRED,
|
||||||
isSelectAll: true,
|
isSelectAll: true,
|
||||||
|
isActive: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -231,6 +232,7 @@
|
||||||
} else {
|
} else {
|
||||||
item.contentType = 'text/plain';
|
item.contentType = 'text/plain';
|
||||||
}
|
}
|
||||||
|
this.reload();
|
||||||
},
|
},
|
||||||
selectAll() {
|
selectAll() {
|
||||||
this.parameters.forEach(item => {
|
this.parameters.forEach(item => {
|
||||||
|
@ -242,6 +244,12 @@
|
||||||
item.enable = false;
|
item.enable = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
reload() {
|
||||||
|
this.isActive = false;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.isActive = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.parameters.length === 0 || this.parameters[this.parameters.length - 1].name) {
|
if (this.parameters.length === 0 || this.parameters[this.parameters.length - 1].name) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
<ms-table-header-select-popover v-show="total>0"
|
<ms-table-header-select-popover v-show="total>0"
|
||||||
:page-size="pageSize>total?total:pageSize"
|
:page-size="pageSize>total?total:pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
|
:select-data-counts="selectDataCounts"
|
||||||
@selectPageAll="isSelectDataAll(false)"
|
@selectPageAll="isSelectDataAll(false)"
|
||||||
@selectAll="isSelectDataAll(true)"/>
|
@selectAll="isSelectDataAll(true)"/>
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<ms-table-header-select-popover v-show="total>0"
|
<ms-table-header-select-popover v-show="total>0"
|
||||||
:page-size="pageSize>total?total:pageSize"
|
:page-size="pageSize>total?total:pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
|
:select-data-counts="selectDataCounts"
|
||||||
@selectPageAll="isSelectDataAll(false)"
|
@selectPageAll="isSelectDataAll(false)"
|
||||||
@selectAll="isSelectDataAll(true)"/>
|
@selectAll="isSelectDataAll(true)"/>
|
||||||
|
|
||||||
|
@ -547,7 +548,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleSelectAll(selection) {
|
handleSelectAll(selection) {
|
||||||
_handleSelectAll(this, selection, this.tableData, this.selectRows);
|
_handleSelectAll(this, selection, this.tableData, this.selectRows, this.condition);
|
||||||
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
||||||
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{$t("commons.batch_add")}}</el-link>
|
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{$t("commons.batch_add")}}</el-link>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<ms-api-key-value :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :suggestions="headerSuggestions" :items="headers"/>
|
<ms-api-key-value :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :suggestions="headerSuggestions" :items="headers" :need-mock="true"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<!--query 参数-->
|
<!--query 参数-->
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
:tags="tags"
|
:tags="tags"
|
||||||
:height="height"
|
:height="height"
|
||||||
:distinct-tags="distinctTags"
|
:distinct-tags="distinctTags"
|
||||||
|
@afterMount="$emit('afterMount')"
|
||||||
@save="save"
|
@save="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import MsFullScreenButton from "@/business/components/common/components/MsFullScreenButton";
|
import MsFullScreenButton from "@/business/components/common/components/MsFullScreenButton";
|
||||||
|
import {listenNodeSelected} from "@/business/components/track/common/minder/minderUtils";
|
||||||
export default {
|
export default {
|
||||||
name: "MsModuleMinder",
|
name: "MsModuleMinder",
|
||||||
components: {MsFullScreenButton},
|
components: {MsFullScreenButton},
|
||||||
|
@ -39,6 +41,12 @@ export default {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
tagEnable: {
|
||||||
|
type: Boolean,
|
||||||
|
default() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
distinctTags: {
|
distinctTags: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default() {
|
default() {
|
||||||
|
@ -56,7 +64,10 @@ export default {
|
||||||
data: {
|
data: {
|
||||||
text: this.$t('test_track.review_view.all_case'),
|
text: this.$t('test_track.review_view.all_case'),
|
||||||
disable: true,
|
disable: true,
|
||||||
id: 'root',
|
id: "root",
|
||||||
|
type: 'node',
|
||||||
|
path: "",
|
||||||
|
tagEnable: this.tagEnable
|
||||||
},
|
},
|
||||||
children: []
|
children: []
|
||||||
},
|
},
|
||||||
|
@ -115,9 +126,14 @@ export default {
|
||||||
text: item.name,
|
text: item.name,
|
||||||
id: item.id,
|
id: item.id,
|
||||||
disable: true,
|
disable: true,
|
||||||
|
type: 'node',
|
||||||
|
path: root.data.path + "/" + item.name,
|
||||||
expandState:"collapse"
|
expandState:"collapse"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if (this.tagEnable) {
|
||||||
|
node.data.tagEnable = this.tagEnable;
|
||||||
|
}
|
||||||
root.children.push(node);
|
root.children.push(node);
|
||||||
this.parse(node, item.children);
|
this.parse(node, item.children);
|
||||||
});
|
});
|
||||||
|
@ -127,6 +143,9 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.isActive = true;
|
this.isActive = true;
|
||||||
})
|
})
|
||||||
|
this.$nextTick(() => {
|
||||||
|
listenNodeSelected();
|
||||||
|
})
|
||||||
},
|
},
|
||||||
setJsonImport(data) {
|
setJsonImport(data) {
|
||||||
this.importJson = data;
|
this.importJson = data;
|
||||||
|
@ -147,6 +166,8 @@ export default {
|
||||||
text: nodeData.name,
|
text: nodeData.name,
|
||||||
id: nodeData.id,
|
id: nodeData.id,
|
||||||
disable: true,
|
disable: true,
|
||||||
|
tagEnable: this.tagEnable,
|
||||||
|
type: 'node'
|
||||||
},
|
},
|
||||||
children: []
|
children: []
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<el-table-column width="1" :resizable="false" align="center">
|
<el-table-column v-if="isShow" width="1" :resizable="false" align="center">
|
||||||
<el-popover slot="header" placement="right" trigger="click" style="margin-right: 0px;">
|
<el-popover slot="header" placement="right" trigger="click" style="margin-right: 0px;">
|
||||||
<el-link @click.native.stop="$emit('selectAll')">{{$t('api_test.batch_menus.select_all_data',[total])}}</el-link>
|
<el-link
|
||||||
|
:class="{'selected-link': selectDataCounts === this.total}"
|
||||||
|
@click.native.stop="click('selectAll')"
|
||||||
|
ref="selectAllLink">
|
||||||
|
{{$t('api_test.batch_menus.select_all_data',[total])}}
|
||||||
|
</el-link>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<el-link @click.native.stop="$emit('selectPageAll')">{{$t('api_test.batch_menus.select_show_data',[pageSize])}}</el-link>
|
<el-link
|
||||||
|
:class="{'selected-link': selectDataCounts === this.pageSize}"
|
||||||
|
@click.native.stop="click('selectPageAll')"
|
||||||
|
ref="selectPageAllLink">
|
||||||
|
{{$t('api_test.batch_menus.select_show_data',[pageSize])}}
|
||||||
|
</el-link>
|
||||||
|
|
||||||
<i class="el-icon-arrow-down" slot="reference"></i>
|
<i class="el-icon-arrow-down" slot="reference"></i>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -12,14 +24,35 @@
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "MsTableSelectAll",
|
name: "MsTableSelectAll",
|
||||||
props: ['total', 'pageSize'],
|
props: ['total', 'pageSize', 'selectDataCounts'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
isShow: true
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectDataCounts() {
|
||||||
|
this.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click(even) {
|
||||||
|
this.$emit(even);
|
||||||
|
},
|
||||||
|
reload() {
|
||||||
|
this.isShow = false;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.isShow = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
|
.selected-link{
|
||||||
|
color: #783887 !important;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-radio v-model='radioValue' :label="4">
|
<el-radio v-model='radioValue' :label="4">
|
||||||
{{$t('schedule.cron.from')}}
|
{{$t('schedule.cron.from')}}
|
||||||
<el-input-number v-model='average01' :min="0" :max="31" /> {{$t('schedule.cron.day_unit')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
<el-input-number v-model='average01' :min="1" :max="31" /> {{$t('schedule.cron.day_unit')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||||
<el-input-number v-model='average02' :min="0" :max="31" /> {{$t('schedule.cron.day')}}{{$t('schedule.cron.execute_once')}}
|
<el-input-number v-model='average02' :min="1" :max="31" /> {{$t('schedule.cron.day')}}{{$t('schedule.cron.execute_once')}}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-radio v-model='radioValue' :label="3">
|
<el-radio v-model='radioValue' :label="3">
|
||||||
{{$t('schedule.cron.from')}}
|
{{$t('schedule.cron.from')}}
|
||||||
<el-input-number v-model='average01' :min="0" :max="24" /> {{$t('schedule.cron.hours')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
<el-input-number v-model='average01' :min="1" :max="24" /> {{$t('schedule.cron.hours')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||||
<el-input-number v-model='average02' :min="0" :max="24" /> {{$t('schedule.cron.hours')}}{{$t('schedule.cron.execute_once')}}
|
<el-input-number v-model='average02' :min="1" :max="24" /> {{$t('schedule.cron.hours')}}{{$t('schedule.cron.execute_once')}}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-radio v-model='radioValue' :label="3">
|
<el-radio v-model='radioValue' :label="3">
|
||||||
{{$t('schedule.cron.from')}}
|
{{$t('schedule.cron.from')}}
|
||||||
<el-input-number v-model='average01' :min="0" :max="59" /> {{$t('schedule.cron.minutes')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
<el-input-number v-model='average01' :min="1" :max="59" /> {{$t('schedule.cron.minutes')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||||
<el-input-number v-model='average02' :min="0" :max="60" /> {{$t('schedule.cron.minutes')}}{{$t('schedule.cron.execute_once')}}
|
<el-input-number v-model='average02' :min="1" :max="60" /> {{$t('schedule.cron.minutes')}}{{$t('schedule.cron.execute_once')}}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-radio v-model='radioValue' :label="3">
|
<el-radio v-model='radioValue' :label="3">
|
||||||
{{$t('schedule.cron.from')}}
|
{{$t('schedule.cron.from')}}
|
||||||
<el-input-number v-model='average01' :min="0" :max="59" /> {{$t('schedule.cron.seconds')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
<el-input-number v-model='average01' :min="1" :max="59" /> {{$t('schedule.cron.seconds')}}{{$t('schedule.cron.start')}},{{$t('schedule.cron.every')}}
|
||||||
<el-input-number v-model='average02' :min="0" :max="60" /> {{$t('schedule.cron.seconds')}}{{$t('schedule.cron.execute_once')}}
|
<el-input-number v-model='average02' :min="1" :max="60" /> {{$t('schedule.cron.seconds')}}{{$t('schedule.cron.execute_once')}}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<ms-table-header-select-popover v-show="total>0"
|
<ms-table-header-select-popover v-show="total>0"
|
||||||
:page-size="pageSize>total?total:pageSize"
|
:page-size="pageSize>total?total:pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
|
:select-data-counts="selectDataCounts"
|
||||||
@selectPageAll="isSelectDataAll(false)"
|
@selectPageAll="isSelectDataAll(false)"
|
||||||
@selectAll="isSelectDataAll(true)"/>
|
@selectAll="isSelectDataAll(true)"/>
|
||||||
<el-table-column v-if="!referenced" width="30" min-width="30" :resizable="false" align="center">
|
<el-table-column v-if="!referenced" width="30" min-width="30" :resizable="false" align="center">
|
||||||
|
@ -365,7 +366,7 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleSelectAll(selection) {
|
handleSelectAll(selection) {
|
||||||
_handleSelectAll(this, selection, this.tableData, this.selectRows);
|
_handleSelectAll(this, selection, this.tableData, this.selectRows, this.condition);
|
||||||
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
||||||
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
||||||
this.$emit('selection', selection);
|
this.$emit('selection', selection);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<ms-table-header-select-popover v-show="total>0"
|
<ms-table-header-select-popover v-show="total>0"
|
||||||
:page-size="pageSize>total?total:pageSize"
|
:page-size="pageSize>total?total:pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
|
:select-data-counts="selectDataCounts"
|
||||||
@selectPageAll="isSelectDataAll(false)"
|
@selectPageAll="isSelectDataAll(false)"
|
||||||
@selectAll="isSelectDataAll(true)"/>
|
@selectAll="isSelectDataAll(true)"/>
|
||||||
<el-table-column v-if="!referenced" width="30" min-width="30" :resizable="false" align="center">
|
<el-table-column v-if="!referenced" width="30" min-width="30" :resizable="false" align="center">
|
||||||
|
@ -746,7 +747,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleSelectAll(selection) {
|
handleSelectAll(selection) {
|
||||||
_handleSelectAll(this, selection, this.tableData, this.selectRows);
|
_handleSelectAll(this, selection, this.tableData, this.selectRows, this.condition);
|
||||||
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
||||||
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
||||||
this.$emit('selection', selection);
|
this.$emit('selection', selection);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<ms-table-header-select-popover v-show="total>0"
|
<ms-table-header-select-popover v-show="total>0"
|
||||||
:page-size="pageSize>total?total:pageSize"
|
:page-size="pageSize>total?total:pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
|
:select-data-counts="selectDataCounts"
|
||||||
@selectPageAll="isSelectDataAll(false)"
|
@selectPageAll="isSelectDataAll(false)"
|
||||||
@selectAll="isSelectDataAll(true)"/>
|
@selectAll="isSelectDataAll(true)"/>
|
||||||
<el-table-column v-if="!referenced" width="30" min-width="30" :resizable="false" align="center">
|
<el-table-column v-if="!referenced" width="30" min-width="30" :resizable="false" align="center">
|
||||||
|
@ -361,7 +362,7 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleSelectAll(selection) {
|
handleSelectAll(selection) {
|
||||||
_handleSelectAll(this, selection, this.tableData, this.selectRows);
|
_handleSelectAll(this, selection, this.tableData, this.selectRows, this.condition);
|
||||||
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
||||||
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
||||||
this.$emit('selection', selection);
|
this.$emit('selection', selection);
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
<ms-table-header-select-popover v-show="total>0"
|
<ms-table-header-select-popover v-show="total>0"
|
||||||
:page-size="pageSize > total ? total : pageSize"
|
:page-size="pageSize > total ? total : pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
|
:select-data-counts="selectDataCounts"
|
||||||
@selectPageAll="isSelectDataAll(false)"
|
@selectPageAll="isSelectDataAll(false)"
|
||||||
@selectAll="isSelectDataAll(true)"/>
|
@selectAll="isSelectDataAll(true)"/>
|
||||||
|
|
||||||
|
@ -499,7 +500,7 @@ export default {
|
||||||
this.$emit('testCaseDetail', row);
|
this.$emit('testCaseDetail', row);
|
||||||
},
|
},
|
||||||
handleSelectAll(selection) {
|
handleSelectAll(selection) {
|
||||||
_handleSelectAll(this, selection, this.tableData, this.selectRows);
|
_handleSelectAll(this, selection, this.tableData, this.selectRows, this.condition);
|
||||||
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
setUnSelectIds(this.tableData, this.condition, this.selectRows);
|
||||||
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows);
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
:tree-nodes="treeNodes"
|
:tree-nodes="treeNodes"
|
||||||
:data-map="dataMap"
|
:data-map="dataMap"
|
||||||
:tags="tags"
|
:tags="tags"
|
||||||
:distinct-tags="[...tags, $t('test_track.plan.plan_status_prepare')]"
|
:tag-enable="true"
|
||||||
|
:select-node="selectNode"
|
||||||
|
:distinct-tags="[...tags, this.$t('test_track.plan.plan_status_prepare')]"
|
||||||
|
@afterMount="handleAfterMount"
|
||||||
@save="save"
|
@save="save"
|
||||||
ref="minder"
|
ref="minder"
|
||||||
/>
|
/>
|
||||||
|
@ -12,7 +15,10 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsModuleMinder from "@/business/components/common/components/MsModuleMinder";
|
import MsModuleMinder from "@/business/components/common/components/MsModuleMinder";
|
||||||
import {getTestCaseDataMap} from "@/business/components/track/common/minder/minderUtils";
|
import {
|
||||||
|
getTestCaseDataMap,
|
||||||
|
tagBatch,
|
||||||
|
} from "@/business/components/track/common/minder/minderUtils";
|
||||||
export default {
|
export default {
|
||||||
name: "TestPlanMinder",
|
name: "TestPlanMinder",
|
||||||
components: {MsModuleMinder},
|
components: {MsModuleMinder},
|
||||||
|
@ -63,6 +69,9 @@ name: "TestPlanMinder",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleAfterMount() {
|
||||||
|
tagBatch([...this.tags, this.$t('test_track.plan.plan_status_prepare')]);
|
||||||
|
},
|
||||||
getTestCases() {
|
getTestCases() {
|
||||||
if (this.projectId) {
|
if (this.projectId) {
|
||||||
this.result = this.$get('/test/plan/case/list/minder/' + this.planId, response => {
|
this.result = this.$get('/test/plan/case/list/minder/' + this.planId, response => {
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
:tree-nodes="treeNodes"
|
:tree-nodes="treeNodes"
|
||||||
:data-map="dataMap"
|
:data-map="dataMap"
|
||||||
:tags="tags"
|
:tags="tags"
|
||||||
|
:tag-enable="true"
|
||||||
|
:select-node="selectNode"
|
||||||
:distinct-tags="[...tags, $t('test_track.plan.plan_status_prepare')]"
|
:distinct-tags="[...tags, $t('test_track.plan.plan_status_prepare')]"
|
||||||
|
@afterMount="handleAfterMount"
|
||||||
@save="save"
|
@save="save"
|
||||||
ref="minder"
|
ref="minder"
|
||||||
/>
|
/>
|
||||||
|
@ -12,7 +15,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsModuleMinder from "@/business/components/common/components/MsModuleMinder";
|
import MsModuleMinder from "@/business/components/common/components/MsModuleMinder";
|
||||||
import {getTestCaseDataMap} from "@/business/components/track/common/minder/minderUtils";
|
import {getTestCaseDataMap, tagBatch} from "@/business/components/track/common/minder/minderUtils";
|
||||||
export default {
|
export default {
|
||||||
name: "TestReviewMinder",
|
name: "TestReviewMinder",
|
||||||
components: {MsModuleMinder},
|
components: {MsModuleMinder},
|
||||||
|
@ -63,6 +66,9 @@ name: "TestReviewMinder",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleAfterMount() {
|
||||||
|
tagBatch([...this.tags, this.$t('test_track.plan.plan_status_prepare')]);
|
||||||
|
},
|
||||||
getTestCases() {
|
getTestCases() {
|
||||||
if (this.projectId) {
|
if (this.projectId) {
|
||||||
let param = {
|
let param = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {getUUID} from "@/common/js/utils";
|
import i18n from "@/i18n/i18n";
|
||||||
|
|
||||||
export function getTestCaseDataMap(testCase, isDisable, setParamCallback) {
|
export function getTestCaseDataMap(testCase, isDisable, setParamCallback) {
|
||||||
let dataMap = new Map();
|
let dataMap = new Map();
|
||||||
|
@ -25,7 +25,7 @@ export function parseCase(item, dataMap, isDisable, setParamCallback) {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
text: item.name,
|
text: item.name,
|
||||||
priority: Number.parseInt(item.priority.substring(item.priority.length - 1 )) + 1,
|
priority: Number.parseInt(item.priority.substring(item.priority.length - 1 )) + 1,
|
||||||
resource: ["用例"],
|
resource: [i18n.t('api_test.definition.request.case')],
|
||||||
type: item.type,
|
type: item.type,
|
||||||
method: item.method,
|
method: item.method,
|
||||||
maintainer: item.maintainer
|
maintainer: item.maintainer
|
||||||
|
@ -53,7 +53,7 @@ export function parseCase(item, dataMap, isDisable, setParamCallback) {
|
||||||
function parseChildren(nodeItem, item, isDisable) {
|
function parseChildren(nodeItem, item, isDisable) {
|
||||||
nodeItem.children = [];
|
nodeItem.children = [];
|
||||||
let children = [];
|
let children = [];
|
||||||
_parseChildren(children, item.prerequisite, "前置条件", isDisable);
|
_parseChildren(children, item.prerequisite, i18n.t('test_track.case.prerequisite'), isDisable);
|
||||||
if (item.steps) {
|
if (item.steps) {
|
||||||
item.steps.forEach((step) => {
|
item.steps.forEach((step) => {
|
||||||
let descNode = _parseChildren(children, step.desc, undefined, isDisable);
|
let descNode = _parseChildren(children, step.desc, undefined, isDisable);
|
||||||
|
@ -64,7 +64,7 @@ function parseChildren(nodeItem, item, isDisable) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_parseChildren(children, item.remark, "备注", isDisable);
|
_parseChildren(children, item.remark, i18n.t('commons.remark'), isDisable);
|
||||||
nodeItem.children = children;
|
nodeItem.children = children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +85,33 @@ function _parseChildren(children, k, v, isDisable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function listenNodeSelected(callback) {
|
||||||
|
let minder = window.minder;
|
||||||
|
minder.on('selectionchange ', function (even) {
|
||||||
|
if (callback) {
|
||||||
|
callback(even);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listenNodeChange(callback) {
|
||||||
|
let minder = window.minder;
|
||||||
|
minder.on('contentchange ', function (even) {
|
||||||
|
if (callback) {
|
||||||
|
callback(even);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listenBeforeExecCommand(callback) {
|
||||||
|
let minder = window.minder;
|
||||||
|
minder.on('beforeExecCommand ', function (even) {
|
||||||
|
if (callback) {
|
||||||
|
callback(even);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function appendChild(appendPid, root, node) {
|
export function appendChild(appendPid, root, node) {
|
||||||
if (root.data.id === appendPid) {
|
if (root.data.id === appendPid) {
|
||||||
root.children.push(node);
|
root.children.push(node);
|
||||||
|
@ -121,3 +148,85 @@ export function updateNode(root, node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tagChildren(node, resourceName, distinctTags) {
|
||||||
|
let children = node.children;
|
||||||
|
if (!children) {
|
||||||
|
children = [];
|
||||||
|
}
|
||||||
|
if (!resourceName || !/\S/.test(resourceName)) {return;}
|
||||||
|
children.forEach((item) => {
|
||||||
|
let isCaseNode = item.data.resource && item.data.resource.indexOf(i18n.t('api_test.definition.request.case')) > -1;
|
||||||
|
if (item.data.type === 'node' || isCaseNode) {
|
||||||
|
let origin = item.data.resource;
|
||||||
|
if (!origin) {
|
||||||
|
origin = [];
|
||||||
|
}
|
||||||
|
let index = origin.indexOf(resourceName);
|
||||||
|
// 先删除排他的标签
|
||||||
|
if (distinctTags.indexOf(resourceName) > -1) {
|
||||||
|
for (let i = 0; i < origin.length; i++) {
|
||||||
|
if (distinctTags.indexOf(origin[i]) > -1) {
|
||||||
|
origin.splice(i, 1);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index !== -1) {
|
||||||
|
origin.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
origin.push(resourceName);
|
||||||
|
}
|
||||||
|
item.data.resource = origin;
|
||||||
|
if (isCaseNode) {
|
||||||
|
item.data.changed = true;
|
||||||
|
}
|
||||||
|
tagChildren(item, resourceName, distinctTags);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function modifyParentNodeTag(node, resourceName) {
|
||||||
|
let topNode = null;
|
||||||
|
while (node.parent) {
|
||||||
|
let pNode = node.parent;
|
||||||
|
let pResource = pNode.data.resource;
|
||||||
|
if (pResource && pResource.length > 0 && pResource.indexOf(resourceName) < 0) {
|
||||||
|
pNode.data.resource = [];
|
||||||
|
topNode = pNode;
|
||||||
|
}
|
||||||
|
node = pNode;
|
||||||
|
}
|
||||||
|
return topNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function tagBatch(distinctTags) {
|
||||||
|
listenBeforeExecCommand((even) => {
|
||||||
|
let minder = window.minder;
|
||||||
|
let selectNodes = window.minder.getSelectedNodes();
|
||||||
|
let args = even.commandArgs;
|
||||||
|
if (selectNodes) {
|
||||||
|
selectNodes.forEach((node) => {
|
||||||
|
if (node.data.type === 'node' && even.commandName === 'resource') {
|
||||||
|
// let origin = minder.queryCommandValue('resource');
|
||||||
|
if (args && args.length > 0) {
|
||||||
|
let origin = args[0];
|
||||||
|
if (origin && origin.length > 0) {
|
||||||
|
let resourceName = origin[0];
|
||||||
|
tagChildren(node, resourceName, distinctTags);
|
||||||
|
let modifyTopNode = modifyParentNodeTag(node, resourceName);
|
||||||
|
if (modifyTopNode) {
|
||||||
|
modifyTopNode.renderTree();
|
||||||
|
} else {
|
||||||
|
node.renderTree();
|
||||||
|
}
|
||||||
|
minder.layout(600);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
:icon="status == 'Completed' ? 'el-icon-check' : ''"
|
:icon="status == 'Completed' ? 'el-icon-check' : ''"
|
||||||
@click="setStatus('Completed')"> {{$t('test_track.plan.plan_status_completed')}}</el-button>
|
@click="setStatus('Completed')"> {{$t('test_track.plan.plan_status_completed')}}</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col>
|
||||||
|
<el-button type="warning" round size="mini"
|
||||||
|
:icon="status == 'Finished' ? 'el-icon-check' : ''"
|
||||||
|
@click="setStatus('Finished')"> {{$t('test_track.plan.plan_status_finished')}}</el-button>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<el-option
|
<el-option
|
||||||
v-for="(item) in principalOptions"
|
v-for="(item) in principalOptions"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:label="item.name"
|
:label="item.name + '(' + item.id + ')'"
|
||||||
:value="item.id">
|
:value="item.id">
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
@ -159,6 +159,12 @@ export default {
|
||||||
principalOptions: []
|
principalOptions: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
//设置“测试阶段”和“负责人”的默认值
|
||||||
|
this.form.stage = 'smoke';
|
||||||
|
const adminToken = JSON.parse(localStorage.getItem("Admin-Token"));
|
||||||
|
this.form.principal = adminToken.name + "(" + adminToken.id + ")";
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
reload() {
|
reload() {
|
||||||
this.isStepTableAlive = false;
|
this.isStepTableAlive = false;
|
||||||
|
@ -267,8 +273,9 @@ export default {
|
||||||
this.$refs['planFrom'].resetFields();
|
this.$refs['planFrom'].resetFields();
|
||||||
this.form.name = '';
|
this.form.name = '';
|
||||||
this.form.projectIds = [];
|
this.form.projectIds = [];
|
||||||
this.form.principal = '';
|
const adminToken = JSON.parse(localStorage.getItem("Admin-Token"));
|
||||||
this.form.stage = '';
|
this.form.principal = adminToken.name + "(" + adminToken.id + ")";
|
||||||
|
this.form.stage = 'smoke';
|
||||||
this.form.description = '';
|
this.form.description = '';
|
||||||
this.form.status = null;
|
this.form.status = null;
|
||||||
this.form.plannedStartTime = null;
|
this.form.plannedStartTime = null;
|
||||||
|
|
|
@ -343,11 +343,11 @@ export default {
|
||||||
handleEdit(testPlan) {
|
handleEdit(testPlan) {
|
||||||
this.$emit('testPlanEdit', testPlan);
|
this.$emit('testPlanEdit', testPlan);
|
||||||
},
|
},
|
||||||
statusChange(param) {
|
statusChange(data) {
|
||||||
console.log(this.tableData);
|
let oldStatus = data.item.status;
|
||||||
let oldStatus = param.item.status;
|
let newStatus = data.status;
|
||||||
let newStatus = param.status;
|
let param = {};
|
||||||
param = param.item;
|
param.id = data.item.id;
|
||||||
param.status = newStatus;
|
param.status = newStatus;
|
||||||
this.$post('/test/plan/edit', param, () => {
|
this.$post('/test/plan/edit', param, () => {
|
||||||
for (let i = 0; i < this.tableData.length; i++) {
|
for (let i = 0; i < this.tableData.length; i++) {
|
||||||
|
|
|
@ -509,7 +509,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
showDetail(row, event, column) {
|
showDetail(row, event, column) {
|
||||||
this.isReadOnly = true;
|
this.isReadOnly = !this.isTestManagerOrTestUser;
|
||||||
this.$refs.testPlanTestCaseEdit.openTestCaseEdit(row);
|
this.$refs.testPlanTestCaseEdit.openTestCaseEdit(row);
|
||||||
},
|
},
|
||||||
refresh() {
|
refresh() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {getCurrentProjectID, getCurrentUser, humpToLine} from "@/common/js/utils";
|
import {getCurrentProjectID, getCurrentUser, humpToLine} from "@/common/js/utils";
|
||||||
import {TEST_CASE_LIST} from "@/common/js/constants";
|
|
||||||
|
|
||||||
export function _handleSelectAll(component, selection, tableData, selectRows) {
|
export function _handleSelectAll(component, selection, tableData, selectRows, condition) {
|
||||||
if (selection.length > 0) {
|
if (selection.length > 0) {
|
||||||
if (selection.length === 1) {
|
if (selection.length === 1) {
|
||||||
selection.hashTree = [];
|
selection.hashTree = [];
|
||||||
|
@ -19,6 +18,9 @@ export function _handleSelectAll(component, selection, tableData, selectRows) {
|
||||||
component.$set(item, "showMore", false);
|
component.$set(item, "showMore", false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (selectRows.size < 1 && condition) {
|
||||||
|
condition.selectAll = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function _handleSelect(component, selection, row, selectRows) {
|
export function _handleSelect(component, selection, row, selectRows) {
|
||||||
|
|
Loading…
Reference in New Issue