Merge remote-tracking branch 'origin/master'

This commit is contained in:
wenyann 2021-02-19 18:27:44 +08:00
commit 9b2e1e5a52
29 changed files with 644 additions and 467 deletions

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.dto.definition.request.MsScenario; import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs; import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import lombok.Data; import lombok.Data;
@ -15,6 +16,7 @@ public class ApiDefinitionImport {
//导入场景 //导入场景
private MsScenario scenarioDefinition; private MsScenario scenarioDefinition;
private List<ApiScenarioWithBLOBs> scenarioDefinitionData;
// 新版本带用例导出 // 新版本带用例导出
private List<ApiTestCaseWithBLOBs> cases; private List<ApiTestCaseWithBLOBs> cases;

View File

@ -20,6 +20,8 @@ import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments; import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.save.SaveService; import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
@ -100,6 +102,9 @@ public class MsScenario extends MsTestElement {
el.toHashTree(tree, el.getHashTree(), config); el.toHashTree(tree, el.getHashTree(), config);
} }
} }
if (CollectionUtils.isNotEmpty(this.headers)) {
setHeader(tree, this.headers);
}
} }
public void setOldVariables(List<KeyValue> oldVariables) { public void setOldVariables(List<KeyValue> oldVariables) {
@ -109,6 +114,20 @@ public class MsScenario extends MsTestElement {
} }
} }
public void setHeader(HashTree tree, List<KeyValue> headers) {
if (CollectionUtils.isNotEmpty(headers)) {
HeaderManager headerManager = new HeaderManager();
headerManager.setEnabled(true);
headerManager.setName(this.getName() + "场景Headers");
headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName());
headerManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HeaderPanel"));
headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
headerManager.add(new Header(keyValue.getName(), keyValue.getValue()))
);
tree.add(headerManager);
}
}
private Arguments arguments(ParameterConfig config) { private Arguments arguments(ParameterConfig config) {
Arguments arguments = new Arguments(); Arguments arguments = new Arguments();
arguments.setEnabled(true); arguments.setEnabled(true);
@ -134,11 +153,6 @@ public class MsScenario extends MsTestElement {
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
); );
} }
if (CollectionUtils.isNotEmpty(this.headers)) {
this.headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
);
}
return arguments; return arguments;
} }

View File

@ -102,7 +102,7 @@ public class MsLoopController extends MsTestElement {
return counterConfig; return counterConfig;
} }
private LoopController loopController() { private LoopController initLoopController() {
LoopController loopController = new LoopController(); LoopController loopController = new LoopController();
loopController.setEnabled(true); loopController.setEnabled(true);
loopController.setName("LoopController"); loopController.setName("LoopController");
@ -113,7 +113,7 @@ public class MsLoopController extends MsTestElement {
return loopController; return loopController;
} }
public String getCondition() { private String getCondition() {
String variable = "\"" + this.whileController.getVariable() + "\""; String variable = "\"" + this.whileController.getVariable() + "\"";
String operator = this.whileController.getOperator(); String operator = this.whileController.getOperator();
String value = "\"" + this.whileController.getValue() + "\""; String value = "\"" + this.whileController.getValue() + "\"";
@ -136,7 +136,7 @@ public class MsLoopController extends MsTestElement {
return "${__jexl3(" + variable + operator + value + ")}"; return "${__jexl3(" + variable + operator + value + ")}";
} }
private WhileController whileController() { private WhileController initWhileController() {
String condition = getCondition(); String condition = getCondition();
if (StringUtils.isEmpty(condition)) { if (StringUtils.isEmpty(condition)) {
return null; return null;
@ -150,7 +150,7 @@ public class MsLoopController extends MsTestElement {
return controller; return controller;
} }
private ForeachController foreachController() { private ForeachController initForeachController() {
ForeachController controller = new ForeachController(); ForeachController controller = new ForeachController();
controller.setEnabled(true); controller.setEnabled(true);
controller.setName("ForeachController"); controller.setName("ForeachController");
@ -175,13 +175,13 @@ public class MsLoopController extends MsTestElement {
runTime.setRuntime(timeout); runTime.setRuntime(timeout);
// 添加超时处理防止死循环 // 添加超时处理防止死循环
HashTree hashTree = tree.add(runTime); HashTree hashTree = tree.add(runTime);
return hashTree.add(whileController()); return hashTree.add(initWhileController());
} }
if (StringUtils.equals(this.loopType, LoopConstants.FOREACH.name()) && this.forEachController != null) { if (StringUtils.equals(this.loopType, LoopConstants.FOREACH.name()) && this.forEachController != null) {
return tree.add(foreachController()); return tree.add(initForeachController());
} }
if (StringUtils.equals(this.loopType, LoopConstants.LOOP_COUNT.name()) && this.countController != null) { if (StringUtils.equals(this.loopType, LoopConstants.LOOP_COUNT.name()) && this.countController != null) {
return tree.add(loopController()); return tree.add(initLoopController());
} }
return null; return null;
} }

View File

@ -39,7 +39,7 @@ public class MsParser extends ApiImportAbstractParser {
return parseMsFormat(testStr, request); return parseMsFormat(testStr, request);
} else { } else {
request.setPlatform(ApiImportPlatform.Plugin.name()); request.setPlatform(ApiImportPlatform.Plugin.name());
return parsePluginFormat(testObject, request); return parsePluginFormat(testObject, request, true);
} }
} }
@ -65,17 +65,20 @@ public class MsParser extends ApiImportAbstractParser {
apiDefinition.setRequest(JSONObject.toJSONString(requestObj)); apiDefinition.setRequest(JSONObject.toJSONString(requestObj));
} }
private ApiDefinitionImport parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest) { protected ApiDefinitionImport parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest, Boolean isCreateModule) {
List<ApiDefinitionWithBLOBs> results = new ArrayList<>(); List<ApiDefinitionWithBLOBs> results = new ArrayList<>();
ApiDefinitionImport apiImport = new ApiDefinitionImport(); ApiDefinitionImport apiImport = new ApiDefinitionImport();
apiImport.setProtocol(RequestType.HTTP); apiImport.setProtocol(RequestType.HTTP);
apiImport.setData(results); apiImport.setData(results);
testObject.keySet().forEach(tag -> { testObject.keySet().forEach(tag -> {
ApiModule parentModule = getSelectModule(importRequest.getModuleId()); ApiModule module = null;
ApiModule module = buildModule(parentModule, tag); if (isCreateModule) {
module = buildModule(getSelectModule(importRequest.getModuleId()), tag);
}
JSONObject requests = testObject.getJSONObject(tag); JSONObject requests = testObject.getJSONObject(tag);
String moduleId = module.getId();
requests.keySet().forEach(requestName -> { requests.keySet().forEach(requestName -> {
JSONObject requestObject = requests.getJSONObject(requestName); JSONObject requestObject = requests.getJSONObject(requestName);
@ -84,7 +87,7 @@ public class MsParser extends ApiImportAbstractParser {
MsHTTPSamplerProxy request = buildRequest(requestName, path, method); MsHTTPSamplerProxy request = buildRequest(requestName, path, method);
ApiDefinitionWithBLOBs apiDefinition = buildApiDefinition(request.getId(), requestName, path, method,importRequest); ApiDefinitionWithBLOBs apiDefinition = buildApiDefinition(request.getId(), requestName, path, method,importRequest);
apiDefinition.setModuleId(module.getId()); apiDefinition.setModuleId(moduleId);
apiDefinition.setProjectId(this.projectId); apiDefinition.setProjectId(this.projectId);
parseBody(requestObject, request.getBody()); parseBody(requestObject, request.getBody());
parseHeader(requestObject, request.getHeaders()); parseHeader(requestObject, request.getHeaders());

View File

@ -0,0 +1,71 @@
package io.metersphere.api.parse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ApiScenrioExportResult;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.service.ApiModuleService;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.commons.constants.ApiImportPlatform;
import io.metersphere.commons.utils.CommonBeanFactory;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.UUID;
public class ScenarioMsParser extends MsParser {
@Override
public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) {
String testStr = getApiTestStr(source);
JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField);
apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
this.projectId = request.getProjectId();
if (testObject.get("projectId") != null) {
return parseMsFormat(testStr, request);
} else {
request.setPlatform(ApiImportPlatform.Plugin.name());
ApiDefinitionImport apiDefinitionImport = parsePluginFormat(testObject, request, false);
MsScenario msScenario = new MsScenario();
LinkedList<MsTestElement> msHTTPSamplerProxies = new LinkedList<>();
apiDefinitionImport.getData().forEach(res -> {
msHTTPSamplerProxies.add(JSONObject.parseObject(res.getRequest(), MsHTTPSamplerProxy.class));
});
msScenario.setHashTree(msHTTPSamplerProxies);
msScenario.setType("scenario");
msScenario.setName("test");
apiDefinitionImport.setScenarioDefinition(msScenario);
return apiDefinitionImport;
}
}
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
ApiScenrioExportResult apiScenrioExportResult = JSON.parseObject(testStr, ApiScenrioExportResult.class);
apiScenrioExportResult.getData().forEach(scenario -> {
parseApiDefinition(scenario, importRequest);
});
ApiDefinitionImport apiDefinitionImport = new ApiDefinitionImport();
apiDefinitionImport.setScenarioDefinitionData(apiScenrioExportResult.getData());
return apiDefinitionImport;
}
private void parseApiDefinition(ApiScenarioWithBLOBs scenario, ApiTestImportRequest importRequest) {
String id = UUID.randomUUID().toString();
if (StringUtils.isBlank(scenario.getModulePath())) {
scenario.setApiScenarioModuleId(null);
}
// parseModule(scenario, importRequest);
scenario.setId(id);
scenario.setProjectId(this.projectId);
String scenarioDefinition = scenario.getScenarioDefinition();
JSONObject scenarioDefinitionObj = JSONObject.parseObject(scenarioDefinition);
scenarioDefinitionObj.put("id", id);
scenario.setScenarioDefinition(JSONObject.toJSONString(scenarioDefinitionObj));
}
}

View File

@ -10,7 +10,6 @@ import io.metersphere.api.dto.DeleteAPIReportRequest;
import io.metersphere.api.dto.JmxInfoDTO; import io.metersphere.api.dto.JmxInfoDTO;
import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.definition.ApiExportResult;
import io.metersphere.api.dto.definition.RunDefinitionRequest; import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.*; import io.metersphere.api.dto.definition.request.*;

View File

@ -44,7 +44,7 @@ import org.springframework.web.multipart.MultipartFile;
import sun.security.util.Cache; import sun.security.util.Cache;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.*; import java.io.File;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;

View File

@ -29,6 +29,7 @@ import io.metersphere.service.FileService;
import io.metersphere.service.QuotaService; import io.metersphere.service.QuotaService;
import io.metersphere.service.UserService; import io.metersphere.service.UserService;
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest; import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
@ -38,11 +39,10 @@ import org.apache.jorphan.collections.ListedHashTree;
import org.aspectj.util.FileUtil; import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.*; import java.io.File;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;

View File

@ -407,6 +407,10 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
TestCaseNodeDTO nodeTree = request.getNodeTree(); TestCaseNodeDTO nodeTree = request.getNodeTree();
if (nodeTree == null) {
return;
}
List<TestCaseNode> updateNodes = new ArrayList<>(); List<TestCaseNode> updateNodes = new ArrayList<>();
buildUpdateTestCase(nodeTree, testCases, updateNodes, "/", "0", 1); buildUpdateTestCase(nodeTree, testCases, updateNodes, "/", "0", 1);

View File

@ -276,22 +276,19 @@ public class XmindCaseParser {
testCase.setType("functional"); testCase.setType("functional");
String tc = title.replace("", ":"); String tc = title.replace("", ":");
String[] tcArr = tc.split(":"); String[] tcArrs = tc.split(":");
if (tcArr.length < 1) { if (tcArrs.length < 1) {
process.add(Translator.get("test_case_name") + Translator.get("incorrect_format"), title); process.add(Translator.get("test_case_name") + Translator.get("incorrect_format"), title);
return; return;
} }
// 用例名称 // 用例名称
StringBuffer name = new StringBuffer(); String name = title.replace(tcArrs[0] + "", "").replace(tcArrs[0] + ":", "");
for (int i = 1; i < tcArr.length; i++) { testCase.setName(name);
name.append(tcArr[i]);
}
testCase.setName(name.toString());
testCase.setNodePath(nodePath); testCase.setNodePath(nodePath);
// 用例等级和用例性质处理 // 用例等级和用例性质处理
if (tcArr[0].indexOf("-") != -1) { if (tcArrs[0].indexOf("-") != -1) {
for (String item : tcArr[0].split("-")) { for (String item : tcArrs[0].split("-")) {
if (isAvailable(item, TC_REGEX)) { if (isAvailable(item, TC_REGEX)) {
continue; continue;
} else if (item.toUpperCase().startsWith("P")) { } else if (item.toUpperCase().startsWith("P")) {

View File

@ -1,4 +1,4 @@
ALTER TABLE schedule ALTER TABLE schedule
MODIFY COLUMN id VARCHAR(255); MODIFY COLUMN id VARCHAR (255);
ALTER TABLE message_task ALTER TABLE message_task
MODIFY COLUMN id VARCHAR(255); MODIFY COLUMN id VARCHAR (255);

View File

@ -1,4 +1,4 @@
ALTER TABLE schedule ALTER TABLE schedule
MODIFY COLUMN resource_id VARCHAR(255); MODIFY COLUMN resource_id VARCHAR (255);
ALTER TABLE message_task ALTER TABLE message_task
MODIFY COLUMN test_id VARCHAR(255); MODIFY COLUMN test_id VARCHAR (255);

View File

@ -106,7 +106,7 @@
</el-col> </el-col>
<el-col :span="3" class="ms-col-one ms-font"> <el-col :span="3" class="ms-col-one ms-font">
<el-link class="head" @click="showScenarioParameters">{{$t('api_test.automation.scenario_total')}}</el-link> <el-link class="head" @click="showScenarioParameters">{{$t('api_test.automation.scenario_total')}}</el-link>
{{getVariableSize()}} {{ getVariableSize() }}
</el-col> </el-col>
<el-col :span="3" class="ms-col-one ms-font"> <el-col :span="3" class="ms-col-one ms-font">
<el-checkbox v-model="enableCookieShare">共享cookie</el-checkbox> <el-checkbox v-model="enableCookieShare">共享cookie</el-checkbox>
@ -204,37 +204,44 @@
</template> </template>
<script> <script>
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData"; import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {WORKSPACE_ID} from '@/common/js/constants'; import {WORKSPACE_ID} from '@/common/js/constants';
import {Assertions, Extract, IfController, JSR223Processor, ConstantTimer, LoopController} from "../../definition/model/ApiTestModel"; import {
import {parseEnvironment} from "../../definition/model/EnvironmentModel"; Assertions,
import {ELEMENTS, ELEMENT_TYPE} from "./Setting"; ConstantTimer,
import MsApiCustomize from "./ApiCustomize"; Extract,
import {getUUID, getCurrentProjectID} from "@/common/js/utils"; IfController,
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig"; JSR223Processor,
import MsInputTag from "./MsInputTag"; LoopController
import MsRun from "./DebugRun"; } from "../../definition/model/ApiTestModel";
import MsApiReportDetail from "../report/ApiReportDetail"; import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import MsVariableList from "./variable/VariableList"; import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
import ApiImport from "../../definition/components/import/ApiImport"; import MsApiCustomize from "./ApiCustomize";
import "@/common/css/material-icons.css" import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import OutsideClick from "@/common/js/outside-click"; import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import ScenarioApiRelevance from "./api/ApiRelevance"; import MsInputTag from "./MsInputTag";
import ScenarioRelevance from "./api/ScenarioRelevance"; import MsRun from "./DebugRun";
import MsComponentConfig from "./component/ComponentConfig"; import MsApiReportDetail from "../report/ApiReportDetail";
import {handleCtrlSEvent} from "../../../../../common/js/utils"; import MsVariableList from "./variable/VariableList";
import ApiImport from "../../definition/components/import/ApiImport";
import "@/common/css/material-icons.css"
import OutsideClick from "@/common/js/outside-click";
import ScenarioApiRelevance from "./api/ApiRelevance";
import ScenarioRelevance from "./api/ScenarioRelevance";
import MsComponentConfig from "./component/ComponentConfig";
import {handleCtrlSEvent} from "../../../../../common/js/utils";
export default { export default {
name: "EditApiScenario", name: "EditApiScenario",
props: { props: {
moduleOptions: Array, moduleOptions: Array,
currentScenario: {}, currentScenario: {},
}, },
components: { components: {
MsVariableList, MsVariableList,
ScenarioRelevance, ScenarioRelevance,
ScenarioApiRelevance, ScenarioApiRelevance,
ApiEnvironmentConfig, ApiEnvironmentConfig,
MsApiReportDetail, MsApiReportDetail,
MsInputTag, MsRun, MsInputTag, MsRun,
MsApiCustomize, MsApiCustomize,
@ -679,9 +686,15 @@
if (valid) { if (valid) {
this.editScenario(); this.editScenario();
this.debugData = { this.debugData = {
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", id: this.currentScenario.id,
variables: this.currentScenario.variables, referenced: 'Created', enableCookieShare: this.enableCookieShare, headers: this.currentScenario.headers, name: this.currentScenario.name,
environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition type: "scenario",
variables: this.currentScenario.variables,
referenced: 'Created',
enableCookieShare: this.enableCookieShare,
headers: this.currentScenario.headers,
environmentId: this.currentEnvironmentId,
hashTree: this.scenarioDefinition
}; };
this.reportId = getUUID().substring(0, 8); this.reportId = getUUID().substring(0, 8);
} }
@ -912,9 +925,15 @@
this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId); this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId);
// 便 // 便
let scenario = { let scenario = {
id: this.currentScenario.id, enableCookieShare: this.enableCookieShare, name: this.currentScenario.name, type: "scenario", id: this.currentScenario.id,
variables: this.currentScenario.variables, headers: this.currentScenario.headers, enableCookieShare: this.enableCookieShare,
referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition name: this.currentScenario.name,
type: "scenario",
variables: this.currentScenario.variables,
headers: this.currentScenario.headers,
referenced: 'Created',
environmentId: this.currentEnvironmentId,
hashTree: this.scenarioDefinition
}; };
this.currentScenario.scenarioDefinition = scenario; this.currentScenario.scenarioDefinition = scenario;
if (this.currentScenario.tags instanceof Array) { if (this.currentScenario.tags instanceof Array) {
@ -1084,6 +1103,7 @@
content: "\e722"; content: "\e722";
font-size: 20px; font-size: 20px;
} }
.ms-sc-variable-header >>> .el-dialog__body { .ms-sc-variable-header >>> .el-dialog__body {
padding: 0px 20px; padding: 0px 20px;
} }

View File

@ -1,12 +1,14 @@
<template> <template>
<div> <div>
<div v-if="request.protocol === 'HTTP'"> <div v-if="request.protocol === 'HTTP'">
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-if="request.url" v-model="request.url" style="width: 85%;margin-top: 10px" size="small" @blur="urlChange"> <el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-if="request.url" v-model="request.url"
style="width: 85%;margin-top: 10px" size="small" @blur="urlChange">
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small"> <el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/> <el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
</el-select> </el-select>
</el-input> </el-input>
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-else v-model="request.path" style="width: 85%;margin-top: 10px" size="small" @blur="pathChange"> <el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-else v-model="request.path"
style="width: 85%;margin-top: 10px" size="small" @blur="pathChange">
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small"> <el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/> <el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
</el-select> </el-select>
@ -33,55 +35,55 @@
</template> </template>
<script> <script>
import {REQ_METHOD} from "@/business/components/api/definition/model/JsonData"; import {REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import {KeyValue} from "../../../definition/model/ApiTestModel"; import {KeyValue} from "../../../definition/model/ApiTestModel";
export default { export default {
name: "CustomizeReqInfo", name: "CustomizeReqInfo",
props: ['request', 'isCustomizeReq'], props: ['request', 'isCustomizeReq'],
data() { data() {
return { return {
reqOptions: REQ_METHOD, reqOptions: REQ_METHOD,
}
},
methods: {
pathChange() {
if (!this.request.path || this.request.path.indexOf('?') === -1) return;
let url = this.getURL(this.addProtocol(this.request.path));
if (url) {
this.request.path = decodeURIComponent(this.request.path.substr(0, this.request.path.indexOf("?")));
} }
}, },
methods: { urlChange() {
pathChange() { if (!this.request.url || this.request.url.indexOf('?') === -1) return;
if (!this.request.path || this.request.path.indexOf('?') === -1) return; let url = this.getURL(this.addProtocol(this.request.url));
let url = this.getURL(this.addProtocol(this.request.path)); if (url) {
if (url) { this.request.url = decodeURIComponent(this.request.url.substr(0, this.request.url.indexOf("?")));
this.request.path = decodeURIComponent(this.request.path.substr(0, this.request.path.indexOf("?"))); }
},
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
} }
}, }
urlChange() { return url;
if (!this.request.url || this.request.url.indexOf('?') === -1) return; },
let url = this.getURL(this.addProtocol(this.request.url)); getURL(urlStr) {
if (url) { try {
this.request.url = decodeURIComponent(this.request.url.substr(0, this.request.url.indexOf("?"))); let url = new URL(urlStr);
} url.searchParams.forEach((value, key) => {
}, if (key && value) {
addProtocol(url) { this.request.arguments.splice(0, 0, new KeyValue({name: key, required: false, value: value}));
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
} }
} });
return url; return url;
}, } catch (e) {
getURL(urlStr) { this.$error(this.$t('api_test.request.url_invalid'), 2000);
try { }
let url = new URL(urlStr); },
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.arguments.splice(0, 0, new KeyValue({name: key, required: false, value: value}));
}
});
return url;
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
}
} }
}
</script> </script>
<style scoped> <style scoped>

View File

@ -28,13 +28,17 @@
<customize-req-info :is-customize-req="isCustomizeReq" :request="request"/> <customize-req-info :is-customize-req="isCustomizeReq" :request="request"/>
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p> <p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-api-request-form :isShowEnable="true" :referenced="true" :headers="request.headers " :request="request" v-if="request.protocol==='HTTP' || request.type==='HTTPSamplerProxy'"/> <ms-api-request-form :isShowEnable="true" :referenced="true" :headers="request.headers " :request="request"
v-if="request.protocol==='HTTP' || request.type==='HTTPSamplerProxy'"/>
<ms-tcp-basis-parameters :request="request" v-if="request.protocol==='TCP'|| request.type==='TCPSampler'"/> <ms-tcp-basis-parameters :request="request" v-if="request.protocol==='TCP'|| request.type==='TCPSampler'"/>
<ms-sql-basis-parameters :request="request" v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'" :showScript="false"/> <ms-sql-basis-parameters :request="request" v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"
<ms-dubbo-basis-parameters :request="request" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'" :showScript="false"/> :showScript="false"/>
<ms-dubbo-basis-parameters :request="request"
v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"
:showScript="false"/>
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p> <p class="tip">{{ $t('api_test.definition.request.res_param') }} </p>
<div v-if="request.result"> <div v-if="request.result">
<el-tabs v-model="request.activeName" closable class="ms-tabs"> <el-tabs v-model="request.activeName" closable class="ms-tabs">
<el-tab-pane :label="item.name" :name="item.name" v-for="(item,index) in request.result.scenarios" :key="index"> <el-tab-pane :label="item.name" :name="item.name" v-for="(item,index) in request.result.scenarios" :key="index">
@ -47,37 +51,37 @@
<api-response-component :currentProtocol="request.protocol" :result="request.requestResult" v-else/> <api-response-component :currentProtocol="request.protocol" :result="request.requestResult" v-else/>
<!-- 保存操作 --> <!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)" v-if="!request.referenced"> <el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)"
{{$t('commons.save')}} v-if="!request.referenced">
{{ $t('commons.save') }}
</el-button> </el-button>
</api-base-component> </api-base-component>
</template> </template>
<script> <script>
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters"; import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters"; import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters"; import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm"; import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
import {REQ_METHOD} from "../../../definition/model/JsonData"; import MsRequestResultTail from "../../../definition/components/response/RequestResultTail";
import MsRequestResultTail from "../../../definition/components/response/RequestResultTail"; import MsRun from "../../../definition/components/Run";
import MsRun from "../../../definition/components/Run"; import {getUUID} from "@/common/js/utils";
import {getUUID} from "@/common/js/utils"; import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiBaseComponent from "../common/ApiBaseComponent"; import ApiResponseComponent from "./ApiResponseComponent";
import ApiResponseComponent from "./ApiResponseComponent"; import CustomizeReqInfo from "@/business/components/api/automation/scenario/common/CustomizeReqInfo";
import CustomizeReqInfo from "@/business/components/api/automation/scenario/common/CustomizeReqInfo";
export default { export default {
name: "MsApiComponent", name: "MsApiComponent",
props: { props: {
request: {}, request: {},
currentScenario: {}, currentScenario: {},
node: {}, node: {},
draggable: { draggable: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
currentEnvironmentId: String, currentEnvironmentId: String,
}, },
components: { components: {
CustomizeReqInfo, CustomizeReqInfo,

View File

@ -22,23 +22,23 @@
</template> </template>
<script> <script>
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters"; import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters"; import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters"; import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm"; import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
import ApiBaseComponent from "../common/ApiBaseComponent"; import ApiBaseComponent from "../common/ApiBaseComponent";
export default { export default {
name: "ApiScenarioComponent", name: "ApiScenarioComponent",
props: { props: {
scenario: {}, scenario: {},
node: {}, node: {},
draggable: { draggable: {
type: Boolean, type: Boolean,
default: false, default: false,
},
}, },
watch: {}, },
watch: {},
created() { created() {
if (this.scenario.id && this.scenario.referenced === 'REF' && !this.scenario.loaded) { if (this.scenario.id && this.scenario.referenced === 'REF' && !this.scenario.loaded) {
this.result = this.$get("/api/automation/getApiScenario/" + this.scenario.id, response => { this.result = this.$get("/api/automation/getApiScenario/" + this.scenario.id, response => {

View File

@ -19,59 +19,59 @@
</template> </template>
<script> <script>
import MsCodeEdit from "../../../../common/components/MsCodeEdit"; import MsCodeEdit from "../../../../common/components/MsCodeEdit";
import MsInstructionsIcon from "../../../../common/components/MsInstructionsIcon"; import MsInstructionsIcon from "../../../../common/components/MsInstructionsIcon";
import MsDropdown from "../../../../common/components/MsDropdown"; import MsDropdown from "../../../../common/components/MsDropdown";
import ApiBaseComponent from "../common/ApiBaseComponent"; import ApiBaseComponent from "../common/ApiBaseComponent";
import Jsr233ProcessorContent from "../common/Jsr233ProcessorContent"; import Jsr233ProcessorContent from "../common/Jsr233ProcessorContent";
export default { export default {
name: "MsJsr233Processor", name: "MsJsr233Processor",
components: {Jsr233ProcessorContent, ApiBaseComponent, MsDropdown, MsInstructionsIcon, MsCodeEdit}, components: {Jsr233ProcessorContent, ApiBaseComponent, MsDropdown, MsInstructionsIcon, MsCodeEdit},
props: { props: {
draggable: { draggable: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
isReadOnly: { isReadOnly: {
type: Boolean, type: Boolean,
default: default:
false false
}, },
jsr223Processor: { jsr223Processor: {
type: Object, type: Object,
}, },
isPreProcessor: { isPreProcessor: {
type: Boolean, type: Boolean,
default: default:
false false
},
title: String,
color: String,
backgroundColor: String,
node: {},
}, },
data() { title: String,
return {loading: false} color: String,
backgroundColor: String,
node: {},
},
data() {
return {loading: false}
},
methods: {
remove() {
this.$emit('remove', this.jsr223Processor, this.node);
}, },
methods: { copyRow() {
remove() { this.$emit('copyRow', this.jsr223Processor, this.node);
this.$emit('remove', this.jsr223Processor, this.node); },
}, reload() {
copyRow() { this.loading = true
this.$emit('copyRow', this.jsr223Processor, this.node); this.$nextTick(() => {
}, this.loading = false
reload() { })
this.loading = true },
this.$nextTick(() => { active() {
this.loading = false this.jsr223Processor.active = !this.jsr223Processor.active;
}) this.reload();
}, },
active() { }
this.jsr223Processor.active = !this.jsr223Processor.active;
this.reload();
},
}
} }
</script> </script>

View File

@ -97,22 +97,22 @@
</template> </template>
<script> <script>
import ApiBaseComponent from "../common/ApiBaseComponent"; import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent"; import ApiResponseComponent from "./ApiResponseComponent";
import MsRun from "../DebugRun"; import MsRun from "../DebugRun";
import {getUUID, getCurrentProjectID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
export default { export default {
name: "MsLoopController", name: "MsLoopController",
components: {ApiBaseComponent, ApiResponseComponent, MsRun}, components: {ApiBaseComponent, ApiResponseComponent, MsRun},
props: { props: {
controller: {}, controller: {},
currentEnvironmentId: String, currentEnvironmentId: String,
currentScenario: {}, currentScenario: {},
node: {}, node: {},
index: Object, index: Object,
draggable: { draggable: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}, },
@ -204,9 +204,15 @@
} }
this.loading = true; this.loading = true;
this.debugData = { this.debugData = {
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", id: this.currentScenario.id,
variables: this.currentScenario.variables, headers: this.currentScenario.headers, name: this.currentScenario.name,
referenced: 'Created', enableCookieShare: this.enableCookieShare, environmentId: this.currentEnvironmentId, hashTree: [this.controller] type: "scenario",
variables: this.currentScenario.variables,
headers: this.currentScenario.headers,
referenced: 'Created',
enableCookieShare: this.enableCookieShare,
environmentId: this.currentEnvironmentId,
hashTree: [this.controller]
}; };
this.reportId = getUUID().substring(0, 8); this.reportId = getUUID().substring(0, 8);
}, },

View File

@ -7,7 +7,8 @@
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<el-row style="margin-bottom: 10px"> <el-row style="margin-bottom: 10px">
<el-col :span="8"> <el-col :span="8">
<el-input placeholder="变量名称搜索" v-model="selectVariable" size="small" @change="filter" @keyup.enter="filter"> <el-input placeholder="变量名称搜索" v-model="selectVariable" size="small" @change="filter"
@keyup.enter="filter">
<el-select v-model="searchType" slot="prepend" placeholder="类型" style="width: 90px" @change="filter"> <el-select v-model="searchType" slot="prepend" placeholder="类型" style="width: 90px" @change="filter">
<el-option value="CONSTANT" label="常量"></el-option> <el-option value="CONSTANT" label="常量"></el-option>
<el-option value="LIST" label="列表"></el-option> <el-option value="LIST" label="列表"></el-option>
@ -19,8 +20,9 @@
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-dropdown split-button type="primary" @command="handleClick" @click="handleClick('CONSTANT')" size="small" style="margin-left: 10px"> <el-dropdown split-button type="primary" @command="handleClick" @click="handleClick('CONSTANT')"
{{$t('commons.add')}} size="small" style="margin-left: 10px">
{{ $t('commons.add') }}
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="CONSTANT">常量</el-dropdown-item> <el-dropdown-item command="CONSTANT">常量</el-dropdown-item>
<el-dropdown-item command="LIST">列表</el-dropdown-item> <el-dropdown-item command="LIST">列表</el-dropdown-item>
@ -29,21 +31,23 @@
<el-dropdown-item command="RANDOM">随机数</el-dropdown-item> <el-dropdown-item command="RANDOM">随机数</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
<el-button size="small" style="margin-left: 10px" @click="deleteVariable">{{$t('commons.delete')}}</el-button> <el-button size="small" style="margin-left: 10px" @click="deleteVariable">{{ $t('commons.delete') }}
</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<div style="border:1px #DCDFE6 solid; min-height: 400px;border-radius: 4px ;width: 100% ;"> <div style="border:1px #DCDFE6 solid; min-height: 400px;border-radius: 4px ;width: 100% ;">
<el-table ref="table" border :data="variables" class="adjust-table" @select-all="select" @select="select" <el-table ref="table" border :data="variables" class="adjust-table" @select-all="select"
@select="select"
v-loading="loading" @row-click="edit" height="400px" :row-class-name="tableRowClassName"> v-loading="loading" @row-click="edit" height="400px" :row-class-name="tableRowClassName">
<el-table-column type="selection" width="38"/> <el-table-column type="selection" width="38"/>
<el-table-column prop="num" label="ID" sortable/> <el-table-column prop="num" label="ID" sortable/>
<el-table-column prop="name" :label="$t('api_test.variable_name')" sortable show-overflow-tooltip/> <el-table-column prop="name" :label="$t('api_test.variable_name')" sortable show-overflow-tooltip/>
<el-table-column prop="type" :label="$t('test_track.case.type')"> <el-table-column prop="type" :label="$t('test_track.case.type')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{types.get(scope.row.type)}}</span> <span>{{ types.get(scope.row.type) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="value" :label="$t('api_test.value')" show-overflow-tooltip/> <el-table-column prop="value" :label="$t('api_test.value')" show-overflow-tooltip/>
@ -64,15 +68,17 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_test.scenario.headers')" name="headers"> <el-tab-pane :label="$t('api_test.scenario.headers')" name="headers">
<!-- 请求头--> <!-- 请求头-->
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.request.headers')" placement="top-start" slot="label"> <el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.request.headers')" placement="top-start"
<span>{{$t('api_test.request.headers')}} slot="label">
<span>{{ $t('api_test.request.headers') }}
<div class="el-step__icon is-text ms-api-col ms-variable-header" v-if="headers.length>1"> <div class="el-step__icon is-text ms-api-col ms-variable-header" v-if="headers.length>1">
<div class="el-step__icon-inner">{{headers.length-1}}</div> <div class="el-step__icon-inner">{{ headers.length - 1 }}</div>
</div> </div>
</span> </span>
</el-tooltip> </el-tooltip>
<el-row> <el-row>
<el-link class="ms-variable-link" @click="batchAdd" style="color: #783887"> {{$t("commons.batch_add")}}</el-link> <el-link class="ms-variable-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}
</el-link>
</el-row> </el-row>
<div style="min-height: 400px"> <div style="min-height: 400px">
<ms-api-key-value :items="headers"/> <ms-api-key-value :items="headers"/>
@ -82,40 +88,40 @@
</el-tabs> </el-tabs>
<template v-slot:footer> <template v-slot:footer>
<div> <div>
<el-button type="primary" @click="save">{{$t('commons.confirm')}}</el-button> <el-button type="primary" @click="save">{{ $t('commons.confirm') }}</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import MsEditConstant from "./EditConstant"; import MsEditConstant from "./EditConstant";
import MsDialogFooter from "../../../../common/components/MsDialogFooter"; import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import MsTableHeader from "@/business/components/common/components/MsTableHeader"; import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination"; import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import MsEditCounter from "./EditCounter"; import MsEditCounter from "./EditCounter";
import MsEditRandom from "./EditRandom"; import MsEditRandom from "./EditRandom";
import MsEditListValue from "./EditListValue"; import MsEditListValue from "./EditListValue";
import MsEditCsv from "./EditCsv"; import MsEditCsv from "./EditCsv";
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsApiKeyValue from "../../../definition/components/ApiKeyValue"; import MsApiKeyValue from "../../../definition/components/ApiKeyValue";
import BatchAddParameter from "../../../definition/components/basis/BatchAddParameter"; import BatchAddParameter from "../../../definition/components/basis/BatchAddParameter";
import {KeyValue} from "../../../definition/model/ApiTestModel"; import {KeyValue} from "../../../definition/model/ApiTestModel";
export default { export default {
name: "MsVariableList", name: "MsVariableList",
components: { components: {
MsEditConstant, MsEditConstant,
MsDialogFooter, MsDialogFooter,
MsTableHeader, MsTableHeader,
MsTablePagination, MsTablePagination,
MsEditCounter, MsEditCounter,
MsEditRandom, MsEditRandom,
MsEditListValue, MsEditListValue,
MsEditCsv, MsEditCsv,
MsApiKeyValue, MsApiKeyValue,
BatchAddParameter BatchAddParameter
}, },
data() { data() {
return { return {
variables: [], variables: [],
@ -154,7 +160,18 @@
if (line[1] === '必填' || line[1] === 'true') { if (line[1] === '必填' || line[1] === 'true') {
required = true; required = true;
} }
keyValues.push(new KeyValue({name: line[0], required: required, value: line[2], description: line[3], type: "text", valid: false, file: false, encode: true, enable: true, contentType: "text/plain"})); keyValues.push(new KeyValue({
name: line[0],
required: required,
value: line[2],
description: line[3],
type: "text",
valid: false,
file: false,
encode: true,
enable: true,
contentType: "text/plain"
}));
}) })
keyValues.forEach(item => { keyValues.forEach(item => {
this.headers.unshift(item); this.headers.unshift(item);
@ -268,19 +285,19 @@
</script> </script>
<style> <style>
.ms-variable-hidden-row { .ms-variable-hidden-row {
display: none; display: none;
} }
.ms-variable-header { .ms-variable-header {
background: #783887; background: #783887;
color: white; color: white;
height: 18px; height: 18px;
border-radius: 42%; border-radius: 42%;
} }
.ms-variable-link { .ms-variable-link {
float: right; float: right;
margin-right: 45px; margin-right: 45px;
} }
</style> </style>

View File

@ -52,31 +52,31 @@
</template> </template>
<script> <script>
import MsApiAssertionText from "./ApiAssertionText"; import MsApiAssertionText from "./ApiAssertionText";
import MsApiAssertionRegex from "./ApiAssertionRegex"; import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionDuration from "./ApiAssertionDuration"; import MsApiAssertionDuration from "./ApiAssertionDuration";
import {ASSERTION_TYPE, JSONPath} from "../../model/ApiTestModel"; import {ASSERTION_TYPE, JSONPath} from "../../model/ApiTestModel";
import MsApiAssertionsEdit from "./ApiAssertionsEdit"; import MsApiAssertionsEdit from "./ApiAssertionsEdit";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath"; import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
import MsApiAssertionJsr223 from "./ApiAssertionJsr223"; import MsApiAssertionJsr223 from "./ApiAssertionJsr223";
import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList"; import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList";
import MsApiAssertionXPath2 from "./ApiAssertionXPath2"; import MsApiAssertionXPath2 from "./ApiAssertionXPath2";
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import ApiJsonPathSuggestButton from "./ApiJsonPathSuggestButton"; import ApiJsonPathSuggestButton from "./ApiJsonPathSuggestButton";
import MsApiJsonpathSuggest from "./ApiJsonpathSuggest"; import MsApiJsonpathSuggest from "./ApiJsonpathSuggest";
import ApiBaseComponent from "../../../automation/scenario/common/ApiBaseComponent"; import ApiBaseComponent from "../../../automation/scenario/common/ApiBaseComponent";
export default { export default {
name: "MsApiAssertions", name: "MsApiAssertions",
components: { components: {
ApiBaseComponent, ApiBaseComponent,
MsApiJsonpathSuggest, MsApiJsonpathSuggest,
ApiJsonPathSuggestButton, ApiJsonPathSuggestButton,
MsApiAssertionXPath2, MsApiAssertionXPath2,
MsApiAssertionJsr223, MsApiAssertionJsr223,
MsApiJsonpathSuggestList, MsApiJsonpathSuggestList,
MsApiAssertionJsonPath, MsApiAssertionJsonPath,
MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText
}, },
props: { props: {
draggable: { draggable: {

View File

@ -2,16 +2,18 @@
<div class="card-container" v-loading="loading"> <div class="card-container" v-loading="loading">
<el-card class="card-content"> <el-card class="card-content">
<el-button v-if="scenario" style="float: right;margin-right: 20px" size="small" type="primary" @click="handleCommand"> {{$t('commons.test')}}</el-button> <el-button v-if="scenario" style="float: right;margin-right: 20px" size="small" type="primary"
@click="handleCommand"> {{ $t('commons.test') }}
</el-button>
<el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand" <el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@command="handleCommand" size="small" style="float: right;margin-right: 20px"> @command="handleCommand" size="small" style="float: right;margin-right: 20px">
{{$t('commons.test')}} {{ $t('commons.test') }}
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="save_as">{{$t('api_test.definition.request.save_as_case')}}</el-dropdown-item> <el-dropdown-item command="save_as">{{ $t('api_test.definition.request.save_as_case') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p> <p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<!-- 请求参数 --> <!-- 请求参数 -->
<ms-basis-parameters :request="request" ref="requestForm"/> <ms-basis-parameters :request="request" ref="requestForm"/>
@ -34,29 +36,38 @@
</template> </template>
<script> <script>
import MsResponseResult from "../response/ResponseResult"; import MsResponseResult from "../response/ResponseResult";
import MsRequestMetric from "../response/RequestMetric"; import MsRequestMetric from "../response/RequestMetric";
import {getUUID, getCurrentUser} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsResponseText from "../response/ResponseText"; import MsResponseText from "../response/ResponseText";
import MsRun from "../Run"; import MsRun from "../Run";
import {createComponent} from "../jmeter/components"; import {createComponent} from "../jmeter/components";
import {REQ_METHOD} from "../../model/JsonData"; import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail"; import MsRequestResultTail from "../response/RequestResultTail";
import MsBasisParameters from "../request/dubbo/BasisParameters"; import MsBasisParameters from "../request/dubbo/BasisParameters";
import MsJmxStep from "../step/JmxStep"; import MsJmxStep from "../step/JmxStep";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
export default { export default {
name: "ApiConfig", name: "ApiConfig",
components: {MsRequestResultTail, MsResponseResult, MsRequestMetric, MsResponseText, MsRun, MsBasisParameters, MsJmxStep, MsApiCaseList}, components: {
props: { MsRequestResultTail,
currentProtocol: String, MsResponseResult,
scenario: Boolean, MsRequestMetric,
testCase: {}, MsResponseText,
}, MsRun,
data() { MsBasisParameters,
return { MsJmxStep,
rules: { MsApiCaseList
},
props: {
currentProtocol: String,
scenario: Boolean,
testCase: {},
},
data() {
return {
rules: {
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}], method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
url: [{required: true, message: this.$t('api_test.definition.request.path_all_info'), trigger: 'blur'}], url: [{required: true, message: this.$t('api_test.definition.request.path_all_info'), trigger: 'blur'}],
}, },

View File

@ -15,7 +15,8 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button v-if="scenario" size="small" type="primary" @click="handleCommand"> {{$t('commons.test')}}</el-button> <el-button v-if="scenario" size="small" type="primary" @click="handleCommand"> {{ $t('commons.test') }}
</el-button>
<el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand" <el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@command="handleCommand" size="small" v-if="testCase===undefined && !scenario"> @command="handleCommand" size="small" v-if="testCase===undefined && !scenario">
{{$t('commons.test')}} {{$t('commons.test')}}
@ -48,30 +49,39 @@
</template> </template>
<script> <script>
import MsApiRequestForm from "../request/http/ApiHttpRequestForm"; import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
import MsResponseResult from "../response/ResponseResult"; import MsResponseResult from "../response/ResponseResult";
import MsRequestMetric from "../response/RequestMetric"; import MsRequestMetric from "../response/RequestMetric";
import {getUUID, getCurrentUser} from "@/common/js/utils"; import {getCurrentUser, getUUID} from "@/common/js/utils";
import MsResponseText from "../response/ResponseText"; import MsResponseText from "../response/ResponseText";
import MsRun from "../Run"; import MsRun from "../Run";
import {createComponent} from "../jmeter/components"; import {createComponent} from "../jmeter/components";
import {REQ_METHOD} from "../../model/JsonData"; import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail"; import MsRequestResultTail from "../response/RequestResultTail";
import MsJmxStep from "../step/JmxStep"; import MsJmxStep from "../step/JmxStep";
import {KeyValue} from "../../model/ApiTestModel"; import {KeyValue} from "../../model/ApiTestModel";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
export default { export default {
name: "ApiConfig", name: "ApiConfig",
components: {MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsJmxStep, MsApiCaseList}, components: {
props: { MsRequestResultTail,
currentProtocol: String, MsResponseResult,
testCase: {}, MsApiRequestForm,
scenario: Boolean, MsRequestMetric,
}, MsResponseText,
data() { MsRun,
let validateURL = (rule, value, callback) => { MsJmxStep,
try { MsApiCaseList
},
props: {
currentProtocol: String,
testCase: {},
scenario: Boolean,
},
data() {
let validateURL = (rule, value, callback) => {
try {
new URL(this.debugForm.url); new URL(this.debugForm.url);
callback(); callback();
} catch (e) { } catch (e) {

View File

@ -2,17 +2,19 @@
<div class="card-container" v-loading="loading"> <div class="card-container" v-loading="loading">
<el-card class="card-content"> <el-card class="card-content">
<el-button v-if="scenario" style="float: right;margin-right: 20px" size="small" type="primary" @click="handleCommand"> {{$t('commons.test')}}</el-button> <el-button v-if="scenario" style="float: right;margin-right: 20px" size="small" type="primary"
@click="handleCommand"> {{ $t('commons.test') }}
</el-button>
<el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand" <el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@command="handleCommand" size="small" style="float: right;margin-right: 20px"> @command="handleCommand" size="small" style="float: right;margin-right: 20px">
{{$t('commons.test')}} {{ $t('commons.test') }}
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="save_as">{{$t('api_test.definition.request.save_as_case')}}</el-dropdown-item> <el-dropdown-item command="save_as">{{ $t('api_test.definition.request.save_as_case') }}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p> <p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<!-- JDBC 请求参数 --> <!-- JDBC 请求参数 -->
<ms-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/> <ms-basis-parameters :request="request" @callback="runDebug" ref="requestForm"/>
@ -37,31 +39,40 @@
</template> </template>
<script> <script>
import MsResponseResult from "../response/ResponseResult"; import MsResponseResult from "../response/ResponseResult";
import MsRequestMetric from "../response/RequestMetric"; import MsRequestMetric from "../response/RequestMetric";
import {getUUID, getCurrentUser} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsResponseText from "../response/ResponseText"; import MsResponseText from "../response/ResponseText";
import MsRun from "../Run"; import MsRun from "../Run";
import {createComponent} from "../jmeter/components"; import {createComponent} from "../jmeter/components";
import {REQ_METHOD} from "../../model/JsonData"; import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail"; import MsRequestResultTail from "../response/RequestResultTail";
import MsBasisParameters from "../request/database/BasisParameters"; import MsBasisParameters from "../request/database/BasisParameters";
import MsJmxStep from "../step/JmxStep"; import MsJmxStep from "../step/JmxStep";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
export default { export default {
name: "ApiConfig", name: "ApiConfig",
components: {MsRequestResultTail, MsResponseResult, MsRequestMetric, MsResponseText, MsRun, MsBasisParameters, MsJmxStep, MsApiCaseList}, components: {
props: { MsRequestResultTail,
currentProtocol: String, MsResponseResult,
scenario: Boolean, MsRequestMetric,
testCase: {}, MsResponseText,
}, MsRun,
data() { MsBasisParameters,
return { MsJmxStep,
rules: { MsApiCaseList
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}], },
url: [{required: true, message: this.$t('api_test.definition.request.path_all_info'), trigger: 'blur'}], props: {
currentProtocol: String,
scenario: Boolean,
testCase: {},
},
data() {
return {
rules: {
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
url: [{required: true, message: this.$t('api_test.definition.request.path_all_info'), trigger: 'blur'}],
}, },
debugForm: {method: REQ_METHOD[0].id}, debugForm: {method: REQ_METHOD[0].id},
options: [], options: [],

View File

@ -11,13 +11,15 @@
<el-input-number v-model="request.port" controls-position="right" :min="0" :max="65535" size="small"/> <el-input-number v-model="request.port" controls-position="right" :min="0" :max="65535" size="small"/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button v-if="scenario" size="small" type="primary" @click="handleCommand"> {{$t('commons.test')}}</el-button> <el-button v-if="scenario" size="small" type="primary" @click="handleCommand"> {{ $t('commons.test') }}
</el-button>
<el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand" <el-dropdown v-else split-button type="primary" class="ms-api-buttion" @click="handleCommand"
@command="handleCommand" size="small" style="float: right;margin-right: 20px"> @command="handleCommand" size="small" style="float: right;margin-right: 20px">
{{$t('commons.test')}} {{ $t('commons.test') }}
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="save_as">{{$t('api_test.definition.request.save_as_case')}}</el-dropdown-item> <el-dropdown-item command="save_as">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</el-form-item> </el-form-item>
@ -47,30 +49,30 @@
</template> </template>
<script> <script>
import MsApiRequestForm from "../request/http/ApiHttpRequestForm"; import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
import MsResponseResult from "../response/ResponseResult"; import MsResponseResult from "../response/ResponseResult";
import MsRequestMetric from "../response/RequestMetric"; import MsRequestMetric from "../response/RequestMetric";
import {getUUID, getCurrentUser} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsResponseText from "../response/ResponseText"; import MsResponseText from "../response/ResponseText";
import MsRun from "../Run"; import MsRun from "../Run";
import {createComponent} from "../jmeter/components"; import {createComponent} from "../jmeter/components";
import {REQ_METHOD} from "../../model/JsonData"; import {REQ_METHOD} from "../../model/JsonData";
import MsRequestResultTail from "../response/RequestResultTail"; import MsRequestResultTail from "../response/RequestResultTail";
import TcpBasisParameters from "../request/tcp/TcpBasisParameters"; import TcpBasisParameters from "../request/tcp/TcpBasisParameters";
import MsJmxStep from "../step/JmxStep"; import MsJmxStep from "../step/JmxStep";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
export default { export default {
name: "ApiConfig", name: "ApiConfig",
components: { components: {
MsJmxStep, MsJmxStep,
TcpBasisParameters, TcpBasisParameters,
MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsApiCaseList MsRequestResultTail, MsResponseResult, MsApiRequestForm, MsRequestMetric, MsResponseText, MsRun, MsApiCaseList
}, },
props: { props: {
currentProtocol: String, currentProtocol: String,
scenario: Boolean, scenario: Boolean,
testCase: {}, testCase: {},
}, },
data() { data() {
return { return {

View File

@ -10,12 +10,13 @@
:title="$t('api_test.definition.request.extract_param')"> :title="$t('api_test.definition.request.extract_param')">
<div style="margin: 20px" v-loading="loading"> <div style="margin: 20px" v-loading="loading">
<div class="extract-description"> <div class="extract-description">
{{$t('api_test.request.extract.description')}} {{ $t('api_test.request.extract.description') }}
</div> </div>
<div class="extract-add"> <div class="extract-add">
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="2"> <el-col :span="2">
<el-select :disabled="isReadOnly" class="extract-item" v-model="type" :placeholder="$t('api_test.request.extract.select_type')" <el-select :disabled="isReadOnly" class="extract-item" v-model="type"
:placeholder="$t('api_test.request.extract.select_type')"
size="small"> size="small">
<el-option :label="$t('api_test.request.extract.regex')" :value="options.REGEX"/> <el-option :label="$t('api_test.request.extract.regex')" :value="options.REGEX"/>
<el-option label="JSONPath" :value="options.JSON_PATH"/> <el-option label="JSONPath" :value="options.JSON_PATH"/>
@ -26,7 +27,7 @@
<ms-api-extract-common :is-read-only="isReadOnly" :extract-type="type" :list="list" v-if="type" :callback="after"/> <ms-api-extract-common :is-read-only="isReadOnly" :extract-type="type" :list="list" v-if="type" :callback="after"/>
</el-col> </el-col>
<el-button v-if="!type" :disabled="true" type="primary" size="small">{{$t('commons.add')}}</el-button> <el-button v-if="!type" :disabled="true" type="primary" size="small">{{ $t('commons.add') }}</el-button>
</el-row> </el-row>
</div> </div>
@ -40,26 +41,26 @@
</template> </template>
<script> <script>
import {EXTRACT_TYPE} from "../../model/ApiTestModel"; import {EXTRACT_TYPE} from "../../model/ApiTestModel";
import MsApiExtractEdit from "./ApiExtractEdit"; import MsApiExtractEdit from "./ApiExtractEdit";
import MsApiExtractCommon from "./ApiExtractCommon"; import MsApiExtractCommon from "./ApiExtractCommon";
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import ApiJsonPathSuggestButton from "../assertion/ApiJsonPathSuggestButton"; import ApiJsonPathSuggestButton from "../assertion/ApiJsonPathSuggestButton";
import MsApiJsonpathSuggest from "../assertion/ApiJsonpathSuggest"; import MsApiJsonpathSuggest from "../assertion/ApiJsonpathSuggest";
import {ExtractJSONPath} from "../../../test/model/ScenarioModel"; import {ExtractJSONPath} from "../../../test/model/ScenarioModel";
import ApiBaseComponent from "../../../automation/scenario/common/ApiBaseComponent"; import ApiBaseComponent from "../../../automation/scenario/common/ApiBaseComponent";
export default { export default {
name: "MsApiExtract", name: "MsApiExtract",
components: { components: {
ApiBaseComponent, ApiBaseComponent,
MsApiJsonpathSuggest, MsApiJsonpathSuggest,
ApiJsonPathSuggestButton, ApiJsonPathSuggestButton,
MsApiExtractCommon, MsApiExtractCommon,
MsApiExtractEdit, MsApiExtractEdit,
}, },
props: { props: {
extract: {}, extract: {},
response: {}, response: {},
node: {}, node: {},
customizeStyle: { customizeStyle: {

View File

@ -44,7 +44,7 @@
</template> </template>
<script> <script>
import {getUUID, uuid} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer"; import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer"; import MsBottomContainer from "../BottomContainer";
@ -89,25 +89,25 @@ export default {
reportId: "", reportId: "",
} }
}, },
props: {apiData: {}, currentProtocol: String, syncTabs: Array, projectId: String}, props: {apiData: {}, currentProtocol: String, syncTabs: Array, projectId: String},
methods: { methods: {
handleCommand(e) { handleCommand(e) {
switch (e) { switch (e) {
case "load_case": case "load_case":
return this.loadCase(); return this.loadCase();
case "save_as_case": case "save_as_case":
return this.saveAsCase(); return this.saveAsCase();
case "update_api": case "update_api":
return this.updateApi(); return this.updateApi();
case "save_as_api": case "save_as_api":
return this.saveAsApi(); return this.saveAsApi();
default: default:
return this.runTest(); return this.runTest();
} }
}, },
refresh() { refresh() {
this.$emit('refresh'); this.$emit('refresh');
}, },
runTest() { runTest() {
this.loading = true; this.loading = true;
this.api.request.name = this.api.id; this.api.request.name = this.api.id;
@ -161,8 +161,9 @@ export default {
}, },
saveAsApi() { saveAsApi() {
let data = {}; let data = {};
this.api.request.id = uuid(); let req = this.api.request;
data.request = JSON.stringify(this.api.request); req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method; data.method = this.api.method;
data.status = this.api.status; data.status = this.api.status;
data.userId = this.api.userId; data.userId = this.api.userId;

View File

@ -71,27 +71,27 @@
</template> </template>
<script> <script>
import MsApiRequestForm from "../request/http/ApiHttpRequestForm"; import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer"; import MsContainer from "../../../../common/components/MsContainer";
import MsRequestResultTail from "../response/RequestResultTail"; import MsRequestResultTail from "../response/RequestResultTail";
import MsRun from "../Run"; import MsRun from "../Run";
import {REQ_METHOD} from "../../model/JsonData"; import {REQ_METHOD} from "../../model/JsonData";
import EnvironmentSelect from "../environment/EnvironmentSelect"; import EnvironmentSelect from "../environment/EnvironmentSelect";
import MsJmxStep from "../step/JmxStep"; import MsJmxStep from "../step/JmxStep";
export default { export default {
name: "RunTestHTTPPage", name: "RunTestHTTPPage",
components: { components: {
EnvironmentSelect, EnvironmentSelect,
MsApiRequestForm, MsApiRequestForm,
MsApiCaseList, MsApiCaseList,
MsContainer, MsContainer,
MsRequestResultTail, MsRequestResultTail,
MsRun, MsRun,
MsJmxStep MsJmxStep
}, },
data() { data() {
return { return {
visible: false, visible: false,

View File

@ -44,7 +44,7 @@
</template> </template>
<script> <script>
import {getUUID, uuid} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer"; import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer"; import MsBottomContainer from "../BottomContainer";
@ -160,8 +160,9 @@ export default {
}, },
saveAsApi() { saveAsApi() {
let data = {}; let data = {};
this.api.request.id = uuid(); let req = this.api.request;
data.request = JSON.stringify(this.api.request); req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method; data.method = this.api.method;
data.status = this.api.status; data.status = this.api.status;
data.userId = this.api.userId; data.userId = this.api.userId;

View File

@ -55,7 +55,7 @@
<script> <script>
import MsApiRequestForm from "../request/http/ApiHttpRequestForm"; import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
import {getUUID, uuid} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsApiCaseList from "../case/ApiCaseList"; import MsApiCaseList from "../case/ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer"; import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer"; import MsBottomContainer from "../BottomContainer";
@ -173,8 +173,9 @@ export default {
}, },
saveAsApi() { saveAsApi() {
let data = {}; let data = {};
this.api.request.id = uuid(); let req = this.api.request;
data.request = JSON.stringify(this.api.request); req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method; data.method = this.api.method;
data.status = this.api.status; data.status = this.api.status;
data.userId = this.api.userId; data.userId = this.api.userId;