diff --git a/backend/src/main/java/io/metersphere/api/parse/MsParser.java b/backend/src/main/java/io/metersphere/api/parse/MsParser.java index 4a909cfbcd..4e9c90f5b5 100644 --- a/backend/src/main/java/io/metersphere/api/parse/MsParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/MsParser.java @@ -44,18 +44,7 @@ public class MsParser extends ApiImportAbstractParser { requestTmpObject.keySet().forEach(key -> requestObject.put(key, requestTmpObject.get(key))); requestObject.put("name", requestName); - JSONArray bodies = requestObject.getJSONArray("body"); - if (StringUtils.equalsIgnoreCase(requestObject.getString("method"), HttpMethod.POST.name()) && bodies != null) { - StringBuilder bodyStr = new StringBuilder(); - for (int i = 0; i < bodies.size(); i++) { - String body = bodies.getString(i); - bodyStr.append(body); - } - JSONObject bodyObject = new JSONObject(); - bodyObject.put("raw", bodyStr); - bodyObject.put("type", MsRequestBodyType.RAW.value()); - requestObject.put("body", bodyObject); - } + parseBody(requestObject); requestsObjects.add(requestObject); }); scenario.put("requests", requestsObjects); @@ -66,4 +55,39 @@ public class MsParser extends ApiImportAbstractParser { return result.toJSONString(); } } + + private void parseBody(JSONObject requestObject) { + if (requestObject.containsKey("body")) { + Object body = requestObject.get("body"); + if (body instanceof JSONArray) { + JSONArray bodies = requestObject.getJSONArray("body"); + if (StringUtils.equalsIgnoreCase(requestObject.getString("method"), HttpMethod.POST.name()) && bodies != null) { + StringBuilder bodyStr = new StringBuilder(); + for (int i = 0; i < bodies.size(); i++) { + String tmp = bodies.getString(i); + bodyStr.append(tmp); + } + JSONObject bodyObject = new JSONObject(); + bodyObject.put("raw", bodyStr); + bodyObject.put("type", MsRequestBodyType.RAW.value()); + requestObject.put("body", bodyObject); + } + } else if (body instanceof JSONObject) { + JSONObject bodyObj = requestObject.getJSONObject("body"); + if (StringUtils.equalsIgnoreCase(requestObject.getString("method"), HttpMethod.POST.name()) && bodyObj != null) { + JSONArray kvs = new JSONArray(); + bodyObj.keySet().forEach(key -> { + JSONObject kv = new JSONObject(); + kv.put("name", key); + kv.put("value", bodyObj.getString(key)); + kvs.add(kv); + }); + JSONObject bodyRes = new JSONObject(); + bodyRes.put("kvs", kvs); + bodyRes.put("type", MsRequestBodyType.KV.value()); + requestObject.put("body", bodyRes); + } + } + } + } } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml index 511700aa93..b29d44d1c3 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml @@ -165,11 +165,17 @@ #{value} - + and test_case.method in #{value} + + + and test_plan_test_case.status in + + #{value} + diff --git a/backend/src/main/java/io/metersphere/commons/constants/TestCaseConstants.java b/backend/src/main/java/io/metersphere/commons/constants/TestCaseConstants.java index 06410341dc..0844c34bb1 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/TestCaseConstants.java +++ b/backend/src/main/java/io/metersphere/commons/constants/TestCaseConstants.java @@ -1,5 +1,48 @@ package io.metersphere.commons.constants; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + public class TestCaseConstants { + public static final int MAX_NODE_DEPTH = 5; + + public enum Type { + Functional("functional"), Performance("performance"), Aapi("api"); + + private String value; + + Type(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + public static List getValues() { + List types = Arrays.asList(Type.values()); + return types.stream().map(Type::getValue).collect(Collectors.toList()); + } + } + + public enum Method { + Manual("manual"), Auto("auto"); + + private String value; + + Method(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + public static List getValues() { + List types = Arrays.asList(Method.values()); + return types.stream().map(Method::getValue).collect(Collectors.toList()); + } + } } diff --git a/backend/src/main/java/io/metersphere/excel/listener/TestCaseDataListener.java b/backend/src/main/java/io/metersphere/excel/listener/TestCaseDataListener.java index c5efa2da88..d4d590586d 100644 --- a/backend/src/main/java/io/metersphere/excel/listener/TestCaseDataListener.java +++ b/backend/src/main/java/io/metersphere/excel/listener/TestCaseDataListener.java @@ -41,16 +41,20 @@ public class TestCaseDataListener extends EasyExcelListener { String[] nodes = nodePath.split("/"); if (nodes.length > TestCaseConstants.MAX_NODE_DEPTH + 1) { stringBuilder.append(Translator.get("test_case_node_level_tip") + - TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level")); + TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level") + "; "); } for (int i = 0; i < nodes.length; i++) { if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) { - stringBuilder.append(Translator.get("module_not_null")); + stringBuilder.append(Translator.get("module_not_null") + "; "); break; } } } + if (StringUtils.equals(data.getType(), TestCaseConstants.Type.Functional.getValue()) && StringUtils.equals(data.getMethod(), TestCaseConstants.Method.Auto.getValue())) { + stringBuilder.append(Translator.get("functional_method_tip") + "; "); + } + if (!userIds.contains(data.getMaintainer())) { stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; "); } diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java index 9834357188..d193d5b008 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java @@ -415,7 +415,7 @@ public class TestCaseNodeService { List updateNodes = new ArrayList<>(); - buildUpdateTestCase(nodeTree, testCases, updateNodes, "/", null, 1); + buildUpdateTestCase(nodeTree, testCases, updateNodes, "/", "0", 1); updateNodes = updateNodes.stream() .filter(item -> nodeIds.contains(item.getId())) diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java index 3b4f73b266..ab9ef07a63 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseService.java @@ -9,6 +9,7 @@ import io.metersphere.base.domain.*; import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.ext.ExtTestCaseMapper; import io.metersphere.commons.constants.RoleConstants; +import io.metersphere.commons.constants.TestCaseConstants; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.user.SessionUser; import io.metersphere.commons.utils.BeanUtils; @@ -309,8 +310,8 @@ public class TestCaseService { private List generateExportTemplate() { List list = new ArrayList<>(); StringBuilder path = new StringBuilder(""); - List types = Arrays.asList("functional", "performance", "api"); - List methods = Arrays.asList("manual", "auto"); + List types = TestCaseConstants.Type.getValues(); + List methods = TestCaseConstants.Method.getValues(); SessionUser user = SessionUtils.getUser(); for (int i = 1; i <= 5; i++) { TestCaseExcelData data = new TestCaseExcelData(); @@ -318,8 +319,13 @@ public class TestCaseService { path.append("/" + Translator.get("module") + i); data.setNodePath(path.toString()); data.setPriority("P" + i % 4); - data.setType(types.get(i % 3)); - data.setMethod(methods.get(i % 2)); + String type = types.get(i % 3); + data.setType(type); + if (StringUtils.equals(TestCaseConstants.Type.Functional.getValue(), type)) { + data.setMethod(TestCaseConstants.Method.Manual.getValue()); + } else { + data.setMethod(methods.get(i % 2)); + } data.setPrerequisite(Translator.get("preconditions_optional")); data.setStepDesc("1. " + Translator.get("step_tip_separate") + "\n2. " + Translator.get("step_tip_order") + "\n3. " + Translator.get("step_tip_optional")); diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index 23b93a72a3..6f07a9bf57 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -117,6 +117,7 @@ plan_name_already_exists=Test plan name already exists test_case_already_exists_excel=There are duplicate test cases in the import file test_case_module_already_exists=The module name already exists at the same level api_test_name_already_exists=Test name already exists +functional_method_tip=Functional test not support auto method #ldap ldap_url_is_null=LDAP address is empty diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index f7af46c6cc..a4e890d91c 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -117,6 +117,7 @@ plan_name_already_exists=测试计划名称已存在 test_case_already_exists_excel=导入文件中存在重复用例 test_case_module_already_exists=同层级下已存在该模块名称 api_test_name_already_exists=测试名称已经存在 +functional_method_tip=功能测试不支持自动方式 #ldap ldap_url_is_null=LDAP地址为空 diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index efdd9d2ce0..326ed9f4f1 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -117,6 +117,7 @@ plan_name_already_exists=測試計劃名稱已存在 test_case_already_exists_excel=導入文件中存在重復用例 test_case_module_already_exists=同層級下已存在該模塊名稱 api_test_name_already_exists=測試名稱已經存在 +functional_method_tip=功能測試不支持自動方式 #ldap ldap_url_is_null=LDAP地址為空 diff --git a/frontend/src/business/components/common/components/MsScheduleConfig.vue b/frontend/src/business/components/common/components/MsScheduleConfig.vue index cb1ed5a58a..029174abb4 100644 --- a/frontend/src/business/components/common/components/MsScheduleConfig.vue +++ b/frontend/src/business/components/common/components/MsScheduleConfig.vue @@ -1,11 +1,11 @@ + + + + + + + + + + + - + @@ -201,8 +217,13 @@ } this.$post("/workspace/" + saveType, this.form, () => { this.dialogWsAddVisible = false; + this.dialogWsUpdateVisible = false; this.list(); - Message.success(this.$t('commons.save_success')); + if (saveType == 'add') { + Message.success(this.$t('commons.save_success')); + } else if (saveType == 'update') { + Message.success(this.$t('commons.modify_success')); + } }); } else { return false; @@ -210,7 +231,7 @@ }); }, edit(row) { - this.dialogWsAddVisible = true; + this.dialogWsUpdateVisible = true; this.form = Object.assign({}, row); }, handleDelete(workspace) { @@ -423,6 +444,7 @@ return { result: {}, dialogWsAddVisible: false, + dialogWsUpdateVisible: false, dialogWsMemberVisible: false, dialogWsMemberAddVisible: false, dialogWsMemberUpdateVisible: false, diff --git a/frontend/src/business/components/settings/system/User.vue b/frontend/src/business/components/settings/system/User.vue index 7481d32f37..685a1c989f 100644 --- a/frontend/src/business/components/settings/system/User.vue +++ b/frontend/src/business/components/settings/system/User.vue @@ -369,7 +369,7 @@ {required: true, message: this.$t('user.input_email'), trigger: 'blur'}, { required: true, - pattern: /^([A-Za-z0-9_\-.])+@([A-Za-z0-9]+\.)+[A-Za-z]{2,6}$/, + pattern: /^[a-zA-Z0-9_._-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, message: this.$t('user.email_format_is_incorrect'), trigger: 'blur' } diff --git a/frontend/src/business/components/track/common/NodeTree.vue b/frontend/src/business/components/track/common/NodeTree.vue index 01bc74ce5c..c1762f8506 100644 --- a/frontend/src/business/components/track/common/NodeTree.vue +++ b/frontend/src/business/components/track/common/NodeTree.vue @@ -107,6 +107,16 @@ export default { }, methods: { handleDragEnd(draggingNode, dropNode, dropType, ev) { + let param = this.buildParam(draggingNode, dropNode, dropType); + console.log(this.treeNodes); + this.$post("/case/node/drag", param, () => { + draggingNode.data.level = param.level; + this.refreshTable(); + }, (error) => { + this.refreshNode(); + }); + }, + buildParam(draggingNode, dropNode, dropType) { let param = {}; param.id = draggingNode.data.id; param.name = draggingNode.data.name; @@ -115,7 +125,7 @@ export default { param.parentId = dropNode.data.id; param.level = dropNode.data.level + 1; } else { - if (dropNode.parent.id === 0) { + if (!dropNode.parent.id || dropNode.parent.id === 0) { param.parentId = 0; param.level = 1; } else { @@ -135,12 +145,9 @@ export default { } } } + param.nodeIds = nodeIds; - this.$post("/case/node/drag", param, () => { - this.refreshTable(); - }, (error) => { - this.refreshNode(); - }); + return param; }, refreshTable() { this.$emit('refreshTable');