diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index ea31fda093..db3cbf8834 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -55,7 +55,9 @@ public class MsScenario extends MsTestElement { if (StringUtils.isNotEmpty(environmentId)) { ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class); ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId); - config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class)); + if (environment != null && environment.getConfig() != null) { + config.setConfig(JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class)); + } } if (CollectionUtils.isNotEmpty(this.getVariables())) { config.setVariables(this.variables); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java index d1a995ea92..0edce5e72d 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java @@ -116,11 +116,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { } try { if (config != null && config.getConfig() != null) { - String url = ""; - sampler.setDomain(config.getConfig().getHttpConfig().getDomain()); - sampler.setPort(config.getConfig().getHttpConfig().getPort()); - sampler.setProtocol(config.getConfig().getHttpConfig().getProtocol()); - url = config.getConfig().getHttpConfig().getProtocol() + "://" + config.getConfig().getHttpConfig().getSocket(); + String url = config.getConfig().getHttpConfig().getProtocol() + "://" + config.getConfig().getHttpConfig().getSocket(); // 补充如果是完整URL 则用自身URL boolean isUrl = false; if (StringUtils.isNotEmpty(this.getUrl()) && isURL(this.getUrl())) { @@ -128,12 +124,21 @@ public class MsHTTPSamplerProxy extends MsTestElement { isUrl = true; } URL urlObject = new URL(url); + if (isUrl) { + sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8")); + sampler.setPort(urlObject.getPort()); + sampler.setProtocol(urlObject.getProtocol()); + } else { + sampler.setDomain(config.getConfig().getHttpConfig().getDomain()); + sampler.setPort(config.getConfig().getHttpConfig().getPort()); + sampler.setProtocol(config.getConfig().getHttpConfig().getProtocol()); + } String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath(); if (StringUtils.isNotBlank(this.getPath()) && !isUrl) { envPath += this.getPath(); } if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) { - envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8")); + envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"), config); sampler.setPath(envPath); } if (CollectionUtils.isNotEmpty(this.getArguments())) { @@ -150,7 +155,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { sampler.setProtocol(urlObject.getProtocol()); if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) { - sampler.setPath(getRestParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8"))); + sampler.setPath(getRestParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8"), config)); } if (CollectionUtils.isNotEmpty(this.getArguments())) { sampler.setPath(getPostQueryParameters(URLDecoder.decode(urlObject.getPath(), "UTF-8"))); @@ -193,7 +198,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { } } - private String getRestParameters(String path) { + private String getRestParameters(String path, ParameterConfig config) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(path); stringBuffer.append("/"); @@ -201,14 +206,31 @@ public class MsHTTPSamplerProxy extends MsTestElement { this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).forEach(keyValue -> keyValueMap.put(keyValue.getName(), keyValue.getValue()) ); + // 这块是否使用jmeter自身机制? + Map pubKeyValueMap = new HashMap<>(); + if (config != null && config.getVariables() != null) { + config.getVariables().stream().forEach(keyValue -> { + pubKeyValueMap.put(keyValue.getName(), keyValue.getValue()); + }); + } + for (String key : keyValueMap.keySet()) { + if (keyValueMap.get(key) != null && keyValueMap.get(key).startsWith("$")) { + String pubKey = keyValueMap.get(key).substring(2, keyValueMap.get(key).length() - 1); + keyValueMap.put(key, pubKeyValueMap.get(pubKey)); + } + } Pattern p = Pattern.compile("(\\{)([\\w]+)(\\})"); Matcher m = p.matcher(path); StringBuffer sb = new StringBuffer(); - while (m.find()) { - String group = m.group(2); - //替换并且把替换好的值放到sb中 - m.appendReplacement(sb, keyValueMap.get(group)); + try { + while (m.find()) { + String group = m.group(2); + //替换并且把替换好的值放到sb中 + m.appendReplacement(sb, keyValueMap.get(group)); + } + } catch (Exception ex) { + ex.printStackTrace(); } //把符合的数据追加到sb尾 m.appendTail(sb); diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index 9f4a9bbf46..79343a2763 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit 9f4a9bbf46fc1333dbcccea21f83e27e3ec10b1f +Subproject commit 79343a2763b014355f91fc21b2356a95ae437973 diff --git a/frontend/package.json b/frontend/package.json index 8f2fc5b9ee..0d52fe313f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,6 +33,7 @@ "vue": "^2.6.10", "vue-calendar-heatmap": "^0.8.4", "vue-echarts": "^4.1.0", + "vue-float-action-button": "^0.6.6", "vue-i18n": "^8.15.3", "vue-input-tag": "^2.0.7", "vue-pdf": "^4.2.0", diff --git a/frontend/src/business/components/api/automation/report/components/ResponseText.vue b/frontend/src/business/components/api/automation/report/components/ResponseText.vue index 5d10582ba0..d732c953c5 100644 --- a/frontend/src/business/components/api/automation/report/components/ResponseText.vue +++ b/frontend/src/business/components/api/automation/report/components/ResponseText.vue @@ -2,14 +2,15 @@
- -
{{ response.headers }}
-
- + + +
{{ response.headers }}
+
+
{{response.console}}
diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index ee872a5f32..c9bb269508 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -182,42 +182,19 @@
- - {{$t('commons.show_all')}} -
-
- +{{$t('api_test.automation.api_list_import')}} -
-
- +{{$t('api_test.automation.external_import')}} -
-
- +{{$t('api_test.automation.wait_controller')}} -
-
- +{{$t('api_test.automation.if_controller')}} -
-
- +{{$t('api_test.automation.scenario_import')}} -
-
- +{{$t('api_test.automation.customize_script')}} -
-
- +{{$t('api_test.automation.customize_req')}} -
-
- +{{$t('api_test.definition.request.pre_script')}} -
-
- +{{$t('api_test.definition.request.post_script')}} -
-
- +{{$t('api_test.definition.request.assertions_rule')}} -
-
- +{{$t('api_test.definition.request.extract_param')}} -
+ + + +
@@ -282,6 +259,7 @@ import MsScenarioParameters from "./ScenarioParameters"; import ApiImport from "../../definition/components/import/ApiImport"; import InputTag from 'vue-input-tag' + import "@/common/css/material-icons.css" export default { name: "EditApiScenario", @@ -358,12 +336,127 @@ this.operatingElements = ELEMENTS.get("ALL"); this.getMaintainerOptions(); this.getApiScenario(); - this.getEnvironments(); } , watch: {} , + computed: { + buttons() { + let buttons = [ + { + title: this.$t('api_test.automation.api_list_import'), + show: this.showButton("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"), + titleColor: "#F56C6C", + titleBgColor: "#FCF1F1", + icon: "api", + click: this.apiListImport + }, { + title: this.$t('api_test.automation.external_import'), + show: this.showButton("OT_IMPORT"), + titleColor: "#409EFF", + titleBgColor: "#EEF5FE", + icon: "next_plan", + click: () => { + this.addComponent('OT_IMPORT') + } + }, { + title: this.$t('api_test.automation.wait_controller'), + show: this.showButton("ConstantTimer"), + titleColor: "#67C23A", + titleBgColor: "#F2F9EE", + icon: "access_time", + click: () => { + this.addComponent('ConstantTimer') + } + }, { + title: this.$t('api_test.automation.if_controller'), + show: this.showButton("IfController"), + titleColor: "#E6A23C", + titleBgColor: "#FCF6EE", + icon: "alt_route", + click: () => { + this.addComponent('IfController') + } + }, { + title: this.$t('api_test.automation.scenario_import'), + show: this.operatingElements.indexOf('scenario') === 0, + titleColor: "#606266", + titleBgColor: "#F4F4F5", + icon: "movie", + click: () => { + this.addComponent('scenario') + } + }, { + title: this.$t('api_test.automation.customize_script'), + show: this.showButton("JSR223Processor"), + titleColor: "#7B4D12", + titleBgColor: "#F1EEE9", + icon: "code", + click: () => { + this.addComponent('JSR223Processor') + } + }, { + title: this.$t('api_test.automation.customize_req'), + show: this.showButton("CustomizeReq"), + titleColor: "#008080", + titleBgColor: "#EBF2F2", + icon: "tune", + click: () => { + this.addComponent('CustomizeReq') + } + }, { + title: this.$t('api_test.definition.request.pre_script'), + show: this.showButton("JSR223PreProcessor"), + titleColor: "#B8741A", + titleBgColor: "#F9F1EA", + icon: "skip_previous", + click: () => { + this.addComponent('JSR223PreProcessor') + } + }, { + title: this.$t('api_test.definition.request.post_script'), + show: this.showButton("JSR223PostProcessor"), + titleColor: "#783887", + titleBgColor: "#F2ECF3", + icon: "skip_next", + click: () => { + this.addComponent('JSR223PostProcessor') + } + }, { + title: this.$t('api_test.definition.request.assertions_rule'), + show: this.showButton("Assertions"), + titleColor: "#A30014", + titleBgColor: "#F7E6E9", + icon: "fact_check", + click: () => { + this.addComponent('Assertions') + } + }, { + title: this.$t('api_test.definition.request.extract_param'), + show: this.showButton("Extract"), + titleColor: "#015478", + titleBgColor: "#E6EEF2", + icon: "colorize", + click: () => { + this.addComponent('Extract') + } + } + ]; + return buttons.filter(btn => btn.show); + } + }, methods: { + getIdx(index) { + return -1 * index - 2.25; // 为了向下展示菜单 + }, + showButton(...names) { + for (const name of names) { + if (this.operatingElements.includes(name)) { + return true; + } + } + return false; + }, addComponent(type) { switch (type) { case ELEMENT_TYPE.IfController: @@ -586,6 +679,16 @@ this.environments.forEach(environment => { parseEnvironment(environment); }); + let hasEnvironment = false; + for (let i in this.environments) { + if (this.environments[i].id === this.currentEnvironmentId) { + hasEnvironment = true; + break; + } + } + if (!hasEnvironment) { + this.currentEnvironmentId = ''; + } }); } } @@ -718,8 +821,7 @@ }) } }) - } - , + }, getApiScenario() { if (this.currentScenario.tags != undefined && !(this.currentScenario.tags instanceof Array)) { this.currentScenario.tags = JSON.parse(this.currentScenario.tags); @@ -741,6 +843,7 @@ this.path = "/api/automation/create"; } } + this.getEnvironments(); }) } } @@ -842,63 +945,10 @@ margin-top: 5px; } - .ms-right-buttion { - margin-top: 10px; - } - - .ms-btn-1 { - color: #F56C6C; - background-color: #FCF1F1 - } - - .ms-btn-2 { - color: #F56C6C; - background-color: #FCF1F1 - } - - .ms-btn-3 { - color: #67C23A; - background-color: #F2F9EE - } - - .ms-btn-4 { - color: #E6A23C; - background-color: #FCF6EE - } - - .ms-btn-5 { - color: #606266; - background-color: #F4F4F5 - } - - .ms-btn-6 { - color: #7B4D12; - background-color: #F1EEE9 - } - - .ms-btn-7 { - color: #008080; - background-color: #EBF2F2 - } - - .ms-btn-8 { - color: #B8741A; - background-color: #F9F1EA - } - - .ms-btn-9 { - color: #783887; - background-color: #F2ECF3 - } - - .ms-btn-10 { - color: #A30014; - background-color: #F7E6E9 - } - - .ms-btn-11 { - color: #015478; - background-color: #E6EEF2 + #fab { + bottom: unset; + right: 90px; + z-index: 5; } /deep/ .el-tree-node__content { @@ -944,5 +994,4 @@ font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif; font-size: 13px; } - diff --git a/frontend/src/business/components/api/automation/scenario/MsInputTag.vue b/frontend/src/business/components/api/automation/scenario/MsInputTag.vue index 1315e63d6d..674b9336e5 100644 --- a/frontend/src/business/components/api/automation/scenario/MsInputTag.vue +++ b/frontend/src/business/components/api/automation/scenario/MsInputTag.vue @@ -31,14 +31,14 @@ diff --git a/frontend/src/business/components/api/definition/components/list/ApiList.vue b/frontend/src/business/components/api/definition/components/list/ApiList.vue index 2fec9cc9fc..000f4a6cb8 100644 --- a/frontend/src/business/components/api/definition/components/list/ApiList.vue +++ b/frontend/src/business/components/api/definition/components/list/ApiList.vue @@ -248,7 +248,7 @@ let arr = Array.from(this.selectRows); // 选中1个以上的用例时显示更多操作 if (this.selectRows.size === 1) { - this.$set(arr[0], "showMore", false); + this.$set(arr[0], "showMore", true); } else if (this.selectRows.size === 2) { arr.forEach(row => { this.$set(row, "showMore", true); diff --git a/frontend/src/business/components/api/definition/components/response/ResponseResult.vue b/frontend/src/business/components/api/definition/components/response/ResponseResult.vue index 8be2966cc5..547feb25ac 100644 --- a/frontend/src/business/components/api/definition/components/response/ResponseResult.vue +++ b/frontend/src/business/components/api/definition/components/response/ResponseResult.vue @@ -2,13 +2,14 @@
- -
{{ response.responseResult.headers }}
-
+ + +
{{ response.responseResult.headers }}
+
@@ -80,7 +81,7 @@ data() { return { isActive: true, - activeName: "headers", + activeName: "body", modes: ['text', 'json', 'xml', 'html'], sqlModes: ['text', 'table'], mode: BODY_FORMAT.TEXT diff --git a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue index 861047c291..b2fa12af0b 100644 --- a/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue +++ b/frontend/src/business/components/api/definition/components/runtest/RunTestHTTPPage.vue @@ -217,6 +217,7 @@ let url = "/api/definition/update"; let bodyFiles = this.getBodyUploadFiles(); this.api.method = this.api.request.method; + this.api.path = this.api.request.path; this.$fileUpload(url, null, bodyFiles, this.api, () => { this.$success(this.$t('commons.save_success')); this.$emit('saveApi', this.api); @@ -273,7 +274,7 @@ environmentConfigClose() { this.getEnvironments(); }, - refresh(){ + refresh() { this.$emit('refresh'); }, getResult() { diff --git a/frontend/src/business/components/api/definition/model/ApiTestModel.js b/frontend/src/business/components/api/definition/model/ApiTestModel.js index 8bcb40a93f..4e8d5ff8fb 100644 --- a/frontend/src/business/components/api/definition/model/ApiTestModel.js +++ b/frontend/src/business/components/api/definition/model/ApiTestModel.js @@ -843,6 +843,7 @@ export class JSR223Processor extends BaseConfig { this.type = "JSR223Processor"; this.script = undefined; this.language = "beanshell"; + this.scriptLanguage = "java"; this.enable = true; this.hashTree = []; this.set(options); diff --git a/frontend/src/business/components/common/components/MsDrawer.vue b/frontend/src/business/components/common/components/MsDrawer.vue index 46fa836b16..dd1ae608e3 100644 --- a/frontend/src/business/components/common/components/MsDrawer.vue +++ b/frontend/src/business/components/common/components/MsDrawer.vue @@ -178,7 +178,9 @@ } .ms-drawer-header { - position: relative; + position: fixed; + width: 100%; + z-index: 999; } .el-icon-close { diff --git a/frontend/src/business/components/common/components/MsJsonCodeEdit.vue b/frontend/src/business/components/common/components/MsJsonCodeEdit.vue index e908453689..5b8b1313bf 100644 --- a/frontend/src/business/components/common/components/MsJsonCodeEdit.vue +++ b/frontend/src/business/components/common/components/MsJsonCodeEdit.vue @@ -17,12 +17,12 @@ }, mode: { type: String, - default: "tree" + default: "code" }, modes: { type: Array, default: function () { - return ["tree", "code"]; + return ["code"]; } } }, diff --git a/frontend/src/business/main.js b/frontend/src/business/main.js index cf25f4cf37..aa30149491 100644 --- a/frontend/src/business/main.js +++ b/frontend/src/business/main.js @@ -17,6 +17,7 @@ import CalendarHeatmap from "../common/js/calendar-heatmap"; import '../common/css/menu-header.css'; import '../common/css/main.css'; import CKEditor from '@ckeditor/ckeditor5-vue'; +import VueFab from 'vue-float-action-button' Vue.config.productionTip = false; Vue.use(icon); @@ -29,7 +30,8 @@ Vue.use(chart); Vue.use(CalendarHeatmap); Vue.use(message); Vue.use(CKEditor); -Vue.use(YanProgress) +Vue.use(YanProgress); +Vue.use(VueFab); // v-permission Vue.directive('permission', permission); diff --git a/frontend/src/common/css/main.css b/frontend/src/common/css/main.css index a5bf4ed31b..ac4755b733 100644 --- a/frontend/src/common/css/main.css +++ b/frontend/src/common/css/main.css @@ -134,6 +134,6 @@ html,body { } ::-webkit-scrollbar-track{ border-radius: 1em; - background-color: rgba(50,50,50,.1); + background-color: transparent; position: fixed; } diff --git a/frontend/src/common/css/material-icons.css b/frontend/src/common/css/material-icons.css new file mode 100644 index 0000000000..6c227cdc37 --- /dev/null +++ b/frontend/src/common/css/material-icons.css @@ -0,0 +1,22 @@ +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url(./material.woff2) format('woff2'); +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; +} diff --git a/frontend/src/common/css/material.woff2 b/frontend/src/common/css/material.woff2 new file mode 100644 index 0000000000..38e24a17fb Binary files /dev/null and b/frontend/src/common/css/material.woff2 differ