fix(Mock期望): #1003659 #1003753 新建Mock规则时自动加载接口定义中的参数,去掉页面多余的内容;Mock响应自定义脚本实现优化

--story=1003659 --user=宋天阳 新建Mock规则时自动加载接口定义中的参数,去掉页面多余的内容
https://www.tapd.cn/55049933/s/1063157;--story=1003753 --user=宋天阳
Mock响应自定义脚本实现优化 https://www.tapd.cn/55049933/s/1063158
This commit is contained in:
song-tianyang 2021-11-02 18:51:34 +08:00 committed by song-tianyang
parent b62d62f1f3
commit d2c48916c0
11 changed files with 558 additions and 165 deletions

View File

@ -1,6 +1,7 @@
package io.metersphere.api.controller;
import io.metersphere.api.dto.mock.MockApiUtils;
import io.metersphere.api.dto.mock.MockParamSuggestions;
import io.metersphere.api.dto.mockconfig.MockConfigRequest;
import io.metersphere.api.dto.mockconfig.MockExpectConfigRequest;
import io.metersphere.api.dto.mockconfig.response.MockConfigResponse;
@ -69,9 +70,9 @@ public class MockConfigController {
}
@GetMapping("/getApiParams/{id}")
public List<Map<String, String>> getApiParams(@PathVariable String id) {
public Map<String, List<MockParamSuggestions>> getApiParams(@PathVariable String id) {
ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = apiDefinitionService.getBLOBs(id);
List<Map<String, String>> apiParams = mockConfigService.getApiParamsByApiDefinitionBLOBs(apiDefinitionWithBLOBs);
Map<String, List<MockParamSuggestions>> apiParams = mockConfigService.getApiParamsByApiDefinitionBLOBs(apiDefinitionWithBLOBs);
return apiParams;
}

View File

@ -5,9 +5,9 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;
import io.metersphere.api.dto.mockconfig.response.JsonSchemaReturnObj;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.json.JSONSchemaGenerator;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.XMLUtils;
import io.metersphere.jmeter.utils.ScriptEngineUtils;
import org.apache.commons.collections.MapUtils;
@ -16,6 +16,7 @@ import org.apache.jmeter.protocol.java.sampler.JSR223Sampler;
import org.apache.jmeter.samplers.SampleResult;
import org.json.XML;
import javax.script.ScriptException;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.*;
@ -40,11 +41,8 @@ public class MockApiUtils {
Map<String,String> mockExpectHeaders = new HashMap<>();
for(int i = 0; i < mockExpectHeaderArray.size(); i++){
JSONObject obj = mockExpectHeaderArray.getJSONObject(i);
if(obj.containsKey("name") && obj.containsKey("value") && obj.containsKey("enable")){
boolean enable = obj.getBoolean("enable");
if(enable){
mockExpectHeaders.put(obj.getString("name"),obj.getString("value"));
}
if(obj.containsKey("name") && obj.containsKey("value")){
mockExpectHeaders.put(obj.getString("name"),obj.getString("value"));
}
}
if(MapUtils.isEmpty(requestHeaderMap) && MapUtils.isNotEmpty(mockExpectHeaders)){
@ -212,11 +210,8 @@ public class MockApiUtils {
JSONObject returnObject = new JSONObject();
for(int i = 0; i < array.size();i ++){
JSONObject obj = array.getJSONObject(i);
if(obj.containsKey("name") && obj.containsKey("value") && obj.containsKey("enable")){
boolean isEnable = obj.getBoolean("enable");
if(isEnable){
returnObject.put(obj.getString("name"),obj.getString("value"));
}
if(obj.containsKey("name") && obj.containsKey("value")){
returnObject.put(obj.getString("name"),obj.getString("value"));
}
}
return returnObject;
@ -354,14 +349,17 @@ public class MockApiUtils {
String script = scriptObj.getString("script");
String scriptLanguage =scriptObj.getString("scriptLanguage");
Map<String,String> scrpitParseMap = parseScript(script,url,headerMap,requestMockParams);
if(scrpitParseMap.containsKey("returnMsg")){
returnStr = scrpitParseMap.get("returnMsg");
String baseScript = parseScript(url,headerMap,requestMockParams);
try {
script = baseScript + script;
System.out.println(script);
if(StringUtils.isEmpty(scriptLanguage)){
scriptLanguage = "beanshell";
}
returnStr = runScript(script,scriptLanguage);
}catch (Exception e){
LogUtil.error(e);
}
if(scrpitParseMap.containsKey("script")){
script = scrpitParseMap.get("script");
}
runScript(script,scriptLanguage);
}
}
@ -370,75 +368,59 @@ public class MockApiUtils {
}
}
private static Map<String,String> parseScript(String script,String url,Map<String,String> headerMap,RequestMockParams requestMockParams) {
Map<String,String> returnMap = new HashMap<>();
String returnMsg = "";
String newScript = "";
if(StringUtils.isNotEmpty(script)){
String [] scriptRowArr = StringUtils.split(script,"\n");
for (String scriptItemRows : scriptRowArr) {
String [] scriptItemArr = scriptItemRows.split(";");
for (String scriptRow :scriptItemArr) {
scriptRow = scriptRow.trim();
if(StringUtils.startsWith(scriptRow,"returnMsg.add(") && StringUtils.endsWith(scriptRow,")")){
scriptRow = scriptRow.substring(14,scriptRow.length()-1).trim();
if(StringUtils.equalsIgnoreCase(scriptRow,"@address")){
returnMsg += url;
}else if(StringUtils.startsWith(scriptRow,"@header(${") && StringUtils.endsWith(scriptRow,"})")){
String paramName = scriptRow.substring(10,scriptRow.length()-2);
if(headerMap.containsKey(paramName)){
returnMsg += headerMap.get(paramName);
}
}else if(StringUtils.startsWith(scriptRow,"@body(${") && StringUtils.endsWith(scriptRow,"})")){
String paramName = scriptRow.substring(8,scriptRow.length()-2);
if(requestMockParams.getBodyParams() != null && requestMockParams.getBodyParams().size() > 0){
JSONObject bodyParamObj = requestMockParams.getBodyParams().getJSONObject(0);
if(bodyParamObj.containsKey(paramName)){
returnMsg += String.valueOf(bodyParamObj.get(paramName));
}
}
}else if(StringUtils.equalsIgnoreCase(scriptRow,"@bodyRaw")){
if(requestMockParams.getBodyParams() != null && requestMockParams.getBodyParams().size() > 0){
JSONObject bodyParamObj = requestMockParams.getBodyParams().getJSONObject(0);
if(bodyParamObj.containsKey("raw")){
returnMsg += String.valueOf(bodyParamObj.get("raw"));
}
}
}else if(StringUtils.startsWith(scriptRow,"@query(${") && StringUtils.endsWith(scriptRow,"})")){
String paramName = scriptRow.substring(9,scriptRow.length()-2);
if(requestMockParams.getQueryParamsObj() != null && requestMockParams.getQueryParamsObj().containsKey(paramName)){
returnMsg += String.valueOf(requestMockParams.getQueryParamsObj().get(paramName));
}
}else if(StringUtils.startsWith(scriptRow,"@rest(${") && StringUtils.endsWith(scriptRow,"})")){
String paramName = scriptRow.substring(8,scriptRow.length()-2);
if(requestMockParams.getRestParamsObj() != null && requestMockParams.getRestParamsObj().containsKey(paramName)){
returnMsg += String.valueOf(requestMockParams.getRestParamsObj().get(paramName));
}
}else {
returnMsg += scriptRow;
}
}else {
newScript += scriptRow +";";
private static String parseScript(String url,Map<String,String> headerMap,RequestMockParams requestMockParams) {
StringBuffer scriptStringBuffer = new StringBuffer();
scriptStringBuffer.append("import java.util.HashMap;\n\n");
scriptStringBuffer.append("HashMap requestParams = new HashMap();\n");
scriptStringBuffer.append("requestParams.put(\"address\",\""+url+"\");\n");
//写入请求头
for (Map.Entry<String, String> headEntry: headerMap.entrySet()){
String headerKey = headEntry.getKey();
String headerValue = headEntry.getValue();
scriptStringBuffer.append("requestParams.put(\"header."+headerKey+"\",\""+headerValue+"\");\n");
}
//写入body参数
if(requestMockParams.getBodyParams() != null){
if(requestMockParams.getBodyParams().size() == 1){
//参数是jsonObject
JSONObject bodyParamObj = requestMockParams.getBodyParams().getJSONObject(0);
for(String key : bodyParamObj.keySet()){
String value = String.valueOf(bodyParamObj.get(key));
scriptStringBuffer.append("requestParams.put(\"body."+key+"\",\""+value+"\");\n");
if(StringUtils.equalsIgnoreCase(key,"raw")){
scriptStringBuffer.append("requestParams.put(\"bodyRaw\",\""+value+"\");\n");
}
}
if(StringUtils.isNotEmpty(newScript)){
newScript += "\n";
}
if(StringUtils.isNotEmpty(returnMsg)){
returnMsg += "\n";
}
}else {
scriptStringBuffer.append("requestParams.put(\"bodyRaw\",\""+requestMockParams.getBodyParams().toJSONString()+"\");\n");
}
}
//写入query参数
if(requestMockParams.getQueryParamsObj() != null){
JSONObject queryParamsObj = requestMockParams.getQueryParamsObj();
for(String key : queryParamsObj.keySet()){
String value = String.valueOf(queryParamsObj.get(key));
scriptStringBuffer.append("requestParams.put(\"query."+key+"\",\""+value+"\");\n");
}
}
returnMap.put("script",newScript);
returnMap.put("returnMsg",returnMsg);
return returnMap;
//写入rest参数
if(requestMockParams.getRestParamsObj() != null){
JSONObject restParamsObj = requestMockParams.getRestParamsObj();
for(String key : restParamsObj.keySet()){
String value = String.valueOf(restParamsObj.get(key));
scriptStringBuffer.append("requestParams.put(\"rest."+key+"\",\""+value+"\");\n");
}
}
return scriptStringBuffer.toString();
}
private static void runScript(String script, String scriptLanguage) {
private static String runScript(String script, String scriptLanguage) throws ScriptException {
JSR223Sampler jmeterScriptSampler = new JSR223Sampler();
jmeterScriptSampler.setScriptLanguage(scriptLanguage);
jmeterScriptSampler.setScript(script);
jmeterScriptSampler.sample(null);
SampleResult result = jmeterScriptSampler.sample(null);
return result.getResponseDataAsString();
}

View File

@ -0,0 +1,10 @@
package io.metersphere.api.dto.mock;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MockParamSuggestions {
private String value;
}

View File

@ -10,6 +10,7 @@ import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.automation.parse.TcpTreeTableDataParser;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.mock.MockApiUtils;
import io.metersphere.api.dto.mock.MockParamSuggestions;
import io.metersphere.api.dto.mock.RequestMockParams;
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
import io.metersphere.api.dto.mockconfig.MockConfigRequest;
@ -358,14 +359,11 @@ public class MockConfigService {
JSONArray headerArr = expectParamsObj.getJSONArray("headers");
for (int i = 0; i < headerArr.size(); i++) {
JSONObject jsonObject = headerArr.getJSONObject(i);
if (jsonObject.containsKey("enable") && jsonObject.containsKey("name") && jsonObject.containsKey("value")) {
boolean isEnable = jsonObject.getBoolean("enable");
if (isEnable) {
String headerName = jsonObject.getString("name");
String headerValue = jsonObject.getString("value");
if (!requestHeaderMap.containsKey(headerName) || !StringUtils.equals(requestHeaderMap.get(headerName), headerValue)) {
return false;
}
if (jsonObject.containsKey("name") && jsonObject.containsKey("value")) {
String headerName = jsonObject.getString("name");
String headerValue = jsonObject.getString("value");
if (!requestHeaderMap.containsKey(headerName) || !StringUtils.equals(requestHeaderMap.get(headerName), headerValue)) {
return false;
}
}
}
@ -510,11 +508,8 @@ public class MockConfigService {
JSONArray restArray = paramsObj.getJSONArray("rest");
for (int i = 0; i < restArray.size(); i++) {
JSONObject restObj = restArray.getJSONObject(i);
if (restObj.containsKey("enable") && restObj.containsKey("name") && restObj.containsKey("value")) {
boolean isEnable = restObj.getBoolean("enable");
if (isEnable) {
return null;
}
if (restObj.containsKey("name") && restObj.containsKey("value")) {
return null;
}
}
}
@ -523,11 +518,8 @@ public class MockConfigService {
JSONArray argumentsArray = paramsObj.getJSONArray("arguments");
for (int i = 0; i < argumentsArray.size(); i++) {
JSONObject argumentsObj = argumentsArray.getJSONObject(i);
if (argumentsObj.containsKey("enable") && argumentsObj.containsKey("name") && argumentsObj.containsKey("value")) {
boolean isEnable = argumentsObj.getBoolean("enable");
if (isEnable) {
return null;
}
if (argumentsObj.containsKey("name") && argumentsObj.containsKey("value")) {
return null;
}
}
}
@ -566,11 +558,8 @@ public class MockConfigService {
JSONArray kvsArray = bodyObj.getJSONArray("kvs");
for (int i = 0; i < kvsArray.size(); i++) {
JSONObject kvsObj = kvsArray.getJSONObject(i);
if (kvsObj.containsKey("enable") && kvsObj.containsKey("name") && kvsObj.containsKey("value")) {
boolean isEnable = kvsObj.getBoolean("enable");
if (isEnable) {
return null;
}
if (kvsObj.containsKey("name") && kvsObj.containsKey("value")) {
return null;
}
}
}
@ -732,14 +721,11 @@ public class MockConfigService {
JSONArray jsonArray = responseJsonObj.getJSONArray("headers");
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
if (object.containsKey("name") && object.containsKey("enable") && object.containsKey("value")) {
boolean isEnable = object.getBoolean("enable");
if (isEnable) {
String name = String.valueOf(object.get("name")).trim();
String value = String.valueOf(object.get("value")).trim();
if (StringUtils.isNotEmpty(name)) {
response.setHeader(name, value);
}
if (object.containsKey("name") && object.containsKey("value")) {
String name = String.valueOf(object.get("name")).trim();
String value = String.valueOf(object.get("value")).trim();
if (StringUtils.isNotEmpty(name)) {
response.setHeader(name, value);
}
}
}
@ -966,9 +952,9 @@ public class MockConfigService {
}
mockConfigMapper.deleteByExample(configExample);
}
public List<Map<String, String>> getApiParamsByApiDefinitionBLOBs(ApiDefinitionWithBLOBs apiModel) {
public Map<String, List<MockParamSuggestions>> getApiParamsByApiDefinitionBLOBs(ApiDefinitionWithBLOBs apiModel) {
if (apiModel == null) {
return new ArrayList<>();
return new HashMap<>();
} else if (StringUtils.equalsIgnoreCase("tcp", apiModel.getMethod())) {
return this.getTCPApiParams(apiModel);
} else {
@ -976,8 +962,8 @@ public class MockConfigService {
}
}
private List<Map<String, String>> getTCPApiParams(ApiDefinitionWithBLOBs apiModel) {
List<Map<String, String>> list = new ArrayList<>();
private Map<String, List<MockParamSuggestions>> getTCPApiParams(ApiDefinitionWithBLOBs apiModel) {
Map<String, List<MockParamSuggestions>> returnMap = new HashMap<>();
List<String> paramNameList = new ArrayList<>();
if (apiModel != null) {
if (apiModel.getRequest() != null) {
@ -997,18 +983,23 @@ public class MockConfigService {
}
}
}
for (String param : paramNameList) {
Map<String, String> map = new HashMap<>();
map.put("value", param);
list.add(map);
}
return list;
List<MockParamSuggestions> list = new ArrayList<>();
paramNameList.forEach(item -> {
MockParamSuggestions model = new MockParamSuggestions();
model.setValue(item);
list.add(model);
});
returnMap.put("value",list);
return returnMap;
}
private List<Map<String, String>> getHTTPApiParams(ApiDefinitionWithBLOBs apiModel) {
List<Map<String, String>> list = new ArrayList<>();
List<String> paramNameList = new ArrayList<>();
private Map<String, List<MockParamSuggestions>> getHTTPApiParams(ApiDefinitionWithBLOBs apiModel) {
Map<String, List<MockParamSuggestions>> returnMap = new HashMap<>();
List<String> queryParamList = new ArrayList<>();
List<String> restParamList = new ArrayList<>();
List<String> formDataList = new ArrayList<>();
if (apiModel != null) {
if (apiModel.getRequest() != null) {
JSONObject requestObj = this.genJSONObject(apiModel.getRequest());
@ -1020,8 +1011,8 @@ public class MockConfigService {
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name") && !paramNameList.contains(headObj.containsKey("name"))) {
paramNameList.add(String.valueOf(headObj.get("name")));
if (headObj.containsKey("name") && !queryParamList.contains(headObj.containsKey("name"))) {
queryParamList.add(String.valueOf(headObj.get("name")));
}
}
} catch (Exception e) {
@ -1032,8 +1023,8 @@ public class MockConfigService {
JSONArray headArr = requestObj.getJSONArray("rest");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name") && !paramNameList.contains(headObj.containsKey("name"))) {
paramNameList.add(String.valueOf(headObj.get("name")));
if (headObj.containsKey("name") && !restParamList.contains(headObj.containsKey("name"))) {
restParamList.add(String.valueOf(headObj.get("name")));
}
}
} catch (Exception e) {
@ -1052,8 +1043,8 @@ public class MockConfigService {
Map<String, String> previewObjMap = new LinkedHashMap<>();
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("name") && !paramNameList.contains(kv.containsKey("name"))) {
paramNameList.add(String.valueOf(kv.get("name")));
if (kv.containsKey("name") && !formDataList.contains(kv.containsKey("name"))) {
formDataList.add(String.valueOf(kv.get("name")));
}
}
}
@ -1067,12 +1058,34 @@ public class MockConfigService {
}
}
for (String param : paramNameList) {
Map<String, String> map = new HashMap<>();
map.put("value", param);
list.add(map);
if(CollectionUtils.isNotEmpty(queryParamList)){
List<MockParamSuggestions> list = new ArrayList<>();
queryParamList.forEach(item -> {
MockParamSuggestions model = new MockParamSuggestions();
model.setValue(item);
list.add(model);
});
returnMap.put("query",list);
}
return list;
if(CollectionUtils.isNotEmpty(restParamList)){
List<MockParamSuggestions> list = new ArrayList<>();
restParamList.forEach(item -> {
MockParamSuggestions model = new MockParamSuggestions();
model.setValue(item);
list.add(model);
});
returnMap.put("rest",list);
}
if(CollectionUtils.isNotEmpty(formDataList)){
List<MockParamSuggestions> list = new ArrayList<>();
formDataList.forEach(item -> {
MockParamSuggestions model = new MockParamSuggestions();
model.setValue(item);
list.add(model);
});
returnMap.put("form",list);
}
return returnMap;
}
private JSONObject genJSONObject(String request) {

View File

@ -21,12 +21,13 @@
{{ $t('api_test.definition.request.body_raw') }}
</el-radio>
</el-radio-group>
<div style="min-width: 1200px;" v-if="body.type == 'Form Data' || body.type == 'WWW_FORM'">
<div style="width: 98%;" v-if="body.type == 'Form Data' || body.type == 'WWW_FORM'">
<el-row v-if="body.type == 'Form Data' || body.type == 'WWW_FORM'">
<el-link class="ms-el-link" @click="batchAdd"> {{ $t("commons.batch_add") }}</el-link>
</el-row>
<ms-api-variable
<mock-api-variable
:with-mor-setting="true"
:suggestions="suggestions"
:is-read-only="isReadOnly"
:parameters="body.kvs"
:isShowEnable="isShowEnable"
@ -77,7 +78,7 @@ import {BODY_TYPE, KeyValue} from "@/business/components/api/definition/model/Ap
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import MsJsonCodeEdit from "@/business/components/common/json-schema/JsonSchemaEditor";
import MsDropdown from "@/business/components/common/components/MsDropdown";
import MsApiVariable from "@/business/components/api/definition/components/ApiVariable";
import MockApiVariable from "@/business/components/api/definition/components/mock/Components/MockApiVariable";
import MsApiFromUrlVariable from "@/business/components/api/definition/components/body/ApiFromUrlVariable";
import BatchAddParameter from "@/business/components/api/definition/components/basis/BatchAddParameter";
import Convert from "@/business/components/common/json-schema/convert/convert";
@ -86,7 +87,7 @@ import Convert from "@/business/components/common/json-schema/convert/convert";
export default {
name: "MockApiBody",
components: {
MsApiVariable,
MockApiVariable,
MsDropdown,
MsCodeEdit,
MsApiKeyValue,
@ -97,6 +98,7 @@ export default {
props: {
body: {},
headers: Array,
suggestions: Array,
isReadOnly: {
type: Boolean,
default: false

View File

@ -46,27 +46,27 @@ export default {
children: [
{
title: this.$t('api_test.request.address'),
value: 'returnMsg.add(@address);',
value: 'var returnMsg = requestParams.get("address");\nreturn returnMsg;',
},
{
title: "Header "+this.$t('api_test.definition.document.request_param'),
value: 'returnMsg.add(@header(${param}));',
value: 'var returnMsg = requestParams.get("header.${param}");\nreturn returnMsg;',
},
{
title: this.$t('api_test.request.body')+this.$t('api_test.variable'),
value: 'returnMsg.add(@body(${param}));',
value: 'var returnMsg = requestParams.get("body.${param}");\nreturn returnMsg;',
},
{
title: this.$t('api_test.request.body')+this.$t('api_test.variable')+" (Raw)",
value: 'returnMsg.add(@bodyRaw);',
value: 'var returnMsg = requestParams.get("bodyRaw");\nreturn returnMsg;',
},
{
title: "Query "+this.$t('api_test.definition.document.request_param'),
value: 'returnMsg.add(@query(${param}));',
value: 'var returnMsg = requestParams.get("query.${param}");\nreturn returnMsg;',
},
{
title: "Rest "+this.$t('api_test.definition.document.request_param'),
value: 'returnMsg.add(@rest(${param}));',
value: 'var returnMsg = requestParams.get("rest.${param}");\nreturn returnMsg;',
},
]
@ -94,7 +94,7 @@ export default {
],
isCodeEditAlive: true,
languages: [
'beanshell',"groovy"
'beanshell'
// , "python", "nashornScript", "rhinoScript"
],
codeEditModeMap: {

View File

@ -0,0 +1,357 @@
<template>
<div style="margin-bottom: 20px">
<span class="kv-description" v-if="description">
{{ description }}
</span>
<!-- <el-row>-->
<!-- <el-checkbox v-model="isSelectAll" v-if="parameters.length > 1"/>-->
<!-- </el-row>-->
<div class="item kv-row" v-for="(item, index) in parameters" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<!-- <el-col class="kv-checkbox" v-if="isShowEnable">-->
<!-- <el-checkbox v-if="!isDisable(index)" v-model="item.enable"-->
<!-- :disabled="isReadOnly"/>-->
<!-- </el-col>-->
<!-- <span style="margin-left: 10px" v-else></span>-->
<span style="margin-left: 10px"></span>
<i class="el-icon-top" style="cursor:pointer" @click="moveTop(index)"/>
<i class="el-icon-bottom" style="cursor:pointer;" @click="moveBottom(index)"/>
<el-col class="item">
<el-input v-if="!suggestions" :disabled="isReadOnly" v-model="item.name" size="small" maxlength="200"
@change="change" :placeholder="keyText" show-word-limit>
<template v-slot:prepend>
<el-select v-if="type === 'body'" :disabled="isReadOnly" class="kv-type" v-model="item.type"
@change="typeChange(item)">
<el-option value="text"/>
<el-option value="file"/>
<el-option value="json"/>
</el-select>
</template>
</el-input>
<el-autocomplete :disabled="isReadOnly" v-if="suggestions" v-model="item.name" size="small"
:fetch-suggestions="querySearch" @change="change" :placeholder="keyText" show-word-limit/>
</el-col>
<!-- <el-col class="item kv-select">-->
<!-- <el-select v-model="item.required" size="small">-->
<!-- <el-option v-for="req in requireds" :key="req.id" :label="req.name" :value="req.id"/>-->
<!-- </el-select>-->
<!-- </el-col>-->
<el-col class="item" v-if="isActive && item.type !== 'file'">
<el-autocomplete
:disabled="isReadOnly"
size="small"
class="input-with-autocomplete"
v-model="item.value"
:fetch-suggestions="funcSearch"
:placeholder="valueText"
value-key="name"
highlight-first-item
@select="change">
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced(item)"></i>
</el-autocomplete>
</el-col>
<el-col class="item">
<el-input v-model="item.description" size="small" maxlength="200"
:placeholder="$t('commons.description')" show-word-limit>
</el-input>
<el-autocomplete :disabled="isReadOnly" v-if="suggestions" v-model="item.name" size="small"
:fetch-suggestions="querySearch" @change="change" :placeholder="keyText" show-word-limit/>
</el-col>
<el-col v-if="isActive && item.type === 'file'" class="item">
<ms-api-body-file-upload :parameter="item"/>
</el-col>
<el-col v-if="type === 'body'" class="item kv-select">
<el-input :disabled="isReadOnly" v-model="item.contentType" size="small"
@change="change" :placeholder="$t('api_test.request.content_type')" show-word-limit>
</el-input>
</el-col>
<!-- <el-col v-if="withMorSetting" class="item kv-setting">-->
<!-- <el-tooltip effect="dark" :content="$t('schema.adv_setting')" placement="top">-->
<!-- <i class="el-icon-setting" @click="openApiVariableSetting(item)"/>-->
<!-- </el-tooltip>-->
<!-- </el-col>-->
<el-col class="item kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
:disabled="isDisable(index) || isReadOnly"/>
</el-col>
</el-row>
</div>
<ms-api-variable-advance ref="variableAdvance" :environment="environment" :scenario="scenario"
:append-to-body="appendDialogToBody"
:parameters="parameters"
:current-item="currentItem"/>
<ms-api-variable-json :append-to-body="appendDialogToBody" ref="variableJson" @callback="callback"/>
<api-variable-setting :append-to-body="appendDialogToBody"
ref="apiVariableSetting"/>
</div>
</template>
<script>
// import {KeyValue, Scenario} from "../model/ApiTestModel";
import {KeyValue,Scenario} from "@/business/components/api/definition/model/ApiTestModel";
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
// import MsApiVariableAdvance from "./ApiVariableAdvance";
import MsApiVariableAdvance from "@/business/components/api/definition/components/ApiVariableAdvance";
import MsApiVariableJson from "@/business/components/api/definition/components/ApiVariableJson";
// import MsApiBodyFileUpload from "@/business/components/api/definition/body/ApiBodyFileUpload";
import MsApiBodyFileUpload from "@/business/components/api/definition/components/body/ApiBodyFileUpload";
import Vue from 'vue';
import ApiVariableSetting from "@/business/components/api/definition/components/ApiVariableSetting";
export default {
name: "MsApiVariable",
components: {ApiVariableSetting, MsApiBodyFileUpload, MsApiVariableAdvance, MsApiVariableJson},
props: {
keyPlaceholder: String,
valuePlaceholder: String,
description: String,
parameters: Array,
rest: Array,
environment: Object,
scenario: Scenario,
type: {
type: String,
default: ''
},
appendDialogToBody: {
type: Boolean,
default() {
return false;
}
},
isReadOnly: {
type: Boolean,
default: false
},
isShowEnable: {
type: Boolean,
default: true
},
suggestions: Array,
withMorSetting: Boolean
},
data() {
return {
currentItem: null,
requireds: [
{name: this.$t('commons.selector.required'), id: true},
{name: this.$t('commons.selector.not_required'), id: false}
],
isSelectAll: true,
isActive: true,
}
},
watch: {
isSelectAll: function (to, from) {
if (from == false && to == true) {
this.selectAll();
} else if (from == true && to == false) {
this.invertSelect();
}
},
},
computed: {
keyText() {
return this.keyPlaceholder || this.$t("api_test.key");
},
valueText() {
return this.valuePlaceholder || this.$t("api_test.value");
}
},
methods: {
moveBottom(index) {
if (this.parameters.length < 2 || index === this.parameters.length - 2) {
return;
}
let thisRow = this.parameters[index];
let nextRow = this.parameters[index + 1];
Vue.set(this.parameters, index + 1, thisRow);
Vue.set(this.parameters, index, nextRow)
},
moveTop(index) {
if (index === 0) {
return;
}
let thisRow = this.parameters[index];
let lastRow = this.parameters[index - 1];
Vue.set(this.parameters, index - 1, thisRow);
Vue.set(this.parameters, index, lastRow)
},
remove: function (index) {
//
this.parameters.splice(index, 1);
this.$emit('change', this.parameters);
},
change: function () {
let isNeedCreate = true;
let removeIndex = -1;
this.parameters.forEach((item, index) => {
if (!item.name && !item.value) {
//
if (index !== this.parameters.length - 1) {
removeIndex = index;
}
//
isNeedCreate = false;
}
});
if (isNeedCreate) {
this.parameters.push(new KeyValue({
type: 'text',
enable: true,
uuid: this.uuid(),
contentType: 'text/plain'
}));
}
this.$emit('change', this.parameters);
// TODO key
},
isDisable: function (index) {
return this.parameters.length - 1 == index;
},
querySearch(queryString, cb) {
let suggestions = this.suggestions;
let results = queryString ? suggestions.filter(this.createFilter(queryString)) : suggestions;
cb(results);
},
createFilter(queryString) {
return (restaurant) => {
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
funcSearch(queryString, cb) {
let funcs = MOCKJS_FUNC.concat(JMETER_FUNC);
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
// callback
cb(results);
},
funcFilter(queryString) {
return (func) => {
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
};
},
uuid: function () {
return (((1 + Math.random()) * 0x100000) | 0).toString(16).substring(1);
},
advanced(item) {
if (item.type === 'json') {
this.$refs.variableJson.open(item);
this.currentItem = item;
} else {
this.$refs.variableAdvance.open();
this.currentItem = item;
}
},
typeChange(item) {
if (item.type === 'file') {
item.contentType = 'application/octet-stream';
} else if (item.type === 'text') {
item.contentType = 'text/plain';
} else {
item.contentType = 'application/json'
}
this.reload();
},
selectAll() {
this.parameters.forEach(item => {
item.enable = true;
});
},
invertSelect() {
this.parameters.forEach(item => {
item.enable = false;
});
},
reload() {
this.isActive = false;
this.$nextTick(() => {
this.isActive = true;
});
},
openApiVariableSetting(item) {
this.$refs.apiVariableSetting.open(item);
},
callback(item) {
this.currentItem.value = item;
this.currentItem = null;
}
},
created() {
if (this.parameters.length === 0 || this.parameters[this.parameters.length - 1].name) {
this.parameters.push(new KeyValue({
type: 'text',
enable: true,
required: true,
uuid: this.uuid(),
contentType: 'text/plain'
}));
}
}
}
</script>
<style scoped>
.kv-description {
font-size: 13px;
}
.kv-row {
margin-top: 10px;
}
.kv-delete {
width: 60px;
}
.kv-select {
width: 50%;
}
.el-autocomplete {
width: 100%;
}
.kv-checkbox {
width: 20px;
margin-right: 10px;
}
.advanced-item-value >>> .el-dialog__body {
padding: 15px 25px;
}
.el-row {
margin-bottom: 5px;
}
.kv-type {
width: 70px;
}
.pointer {
cursor: pointer;
color: #1E90FF;
}
.kv-setting {
width: 40px;
padding: 0px !important;
}
</style>

View File

@ -17,7 +17,8 @@
<el-row>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}</el-link>
</el-row>
<ms-api-key-value :append-to-body="true" :show-desc="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :suggestions="headerSuggestions" :items="request.headers" :need-mock="true"/>
<ms-api-key-value :append-to-body="true" :show-desc="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable"
:suggestions="headerSuggestions" :items="request.headers" :need-mock="true"/>
</el-tab-pane>
<!--query 参数-->
@ -31,7 +32,10 @@
<el-row>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}</el-link>
</el-row>
<ms-api-variable :append-dialog-to-body="true" :with-mor-setting="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :parameters="request.arguments"/>
<mock-api-variable :append-dialog-to-body="true"
:suggestions="apiParams.query"
:with-mor-setting="true"
:is-read-only="isReadOnly" :isShowEnable="isShowEnable" :parameters="request.arguments"/>
</el-tab-pane>
<!--REST 参数-->
@ -47,12 +51,18 @@
<el-row>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}</el-link>
</el-row>
<ms-api-variable :append-dialog-to-body="true" :with-mor-setting="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :parameters="request.rest"/>
<mock-api-variable :append-dialog-to-body="true"
:suggestions="apiParams.rest"
:with-mor-setting="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :parameters="request.rest"/>
</el-tab-pane>
<!--请求体-->
<el-tab-pane v-if="isBodyShow" :label="$t('api_test.request.body')" name="body" style="overflow: auto">
<mock-api-body @headersChange="reloadBody" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :headers="request.headers" :body="request.body"/>
<mock-api-body @headersChange="reloadBody"
:suggestions="apiParams.form"
:is-read-only="isReadOnly"
:isShowEnable="isShowEnable"
:headers="request.headers" :body="request.body"/>
</el-tab-pane>
<el-tab-pane name="create" v-if="hasPermission('PROJECT_API_DEFINITION:READ+CREATE_API') && hasLicense() && definitionTest">
<template v-slot:label>
@ -72,7 +82,7 @@ import MsApiKeyValue from "@/business/components/api/definition/components/ApiKe
import MsApiAuthConfig from "@/business/components/api/definition/components/auth/ApiAuthConfig";
import ApiRequestMethodSelect from "@/business/components/api/definition/components/collapse/ApiRequestMethodSelect";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsApiVariable from "@/business/components/api/definition/components/ApiVariable";
import MockApiVariable from "@/business/components/api/definition/components/mock/Components/MockApiVariable";
import MsApiAssertions from "@/business/components/api/definition/components/assertion/ApiAssertions";
import MsApiExtract from "@/business/components/api/definition/components/extract/ApiExtract";
import {Body, KeyValue} from "@/business/components/api/definition/model/ApiTestModel";
@ -92,7 +102,7 @@ export default {
MsJsr233Processor,
MsApiAdvancedConfig,
BatchAddParameter,
MsApiVariable,
MockApiVariable,
ApiRequestMethodSelect,
MsApiExtract,
MsApiAuthConfig,
@ -120,6 +130,7 @@ export default {
},
isShowEnable: Boolean,
jsonPathList: Array,
apiParams: Object,
isReadOnly: {
type: Boolean,
default: false

View File

@ -20,9 +20,10 @@
:request="mockExpectConfig.request" style="margin: 10px 10px;" ref="tcpParam"></tcp-params>
<mock-request-param
v-else
:isShowEnable="true"
:isShowEnable="false"
:referenced="true"
:is-read-only="false"
:api-params="apiParams"
:request="mockExpectConfig.request.params"/>
</el-row>
@ -66,7 +67,7 @@ export default {
MsDrawer,MockConfigHeader,MockRowVariables,MsCodeEdit,MockRequestParam,MockResponseParam,TcpParams
},
props: {
apiParams: Array,
apiParams: Object,
apiId:String,
mockConfigId:String,
isTcp:{

View File

@ -69,7 +69,10 @@
</ms-table-column>
</ms-table>
</div>
<mock-edit-drawer :is-tcp="isTcp" :api-id="this.baseMockConfigData.mockConfig.apiId" @refreshMockInfo="refreshMockInfo" :mock-config-id="mockConfigData.mockConfig.id" ref="mockEditDrawer"/>
<mock-edit-drawer :is-tcp="isTcp" :api-id="this.baseMockConfigData.mockConfig.apiId"
:api-params="apiParams"
@refreshMockInfo="refreshMockInfo"
:mock-config-id="mockConfigData.mockConfig.id" ref="mockEditDrawer"/>
</div>
</template>
@ -100,7 +103,7 @@ export default {
visible: false,
mockConfigData: {},
tableSearch:"",
apiParams: [],
apiParams: {},
pageSize: 10,
screenHeight:document.documentElement.clientHeight - 250,
operators: [
@ -125,7 +128,6 @@ export default {
},
created() {
this.mockConfigData = this.baseMockConfigData;
this.searchApiParams(this.mockConfigData.mockConfig.apiId);
},
computed: {
projectId() {
@ -136,7 +138,17 @@ export default {
searchApiParams(apiId) {
let selectUrl = "/mockConfig/getApiParams/" + apiId;
this.$get(selectUrl, response => {
this.apiParams = response.data;
if(!this.apiParams.query){
this.apiParams.query = [];
}
if(!this.apiParams.rest){
this.apiParams.rest = [];
}
if(!this.apiParams.form){
this.apiParams.form = [];
}
});
},
changeStatus(row) {
@ -196,6 +208,7 @@ export default {
});
},
addApiMock(){
this.searchApiParams(this.mockConfigData.mockConfig.apiId);
this.$refs.mockEditDrawer.open();
},
removeExpect(row) {

View File

@ -183,15 +183,18 @@ export default {
},
created() {
this.mockConfigData = this.baseMockConfigData;
this.searchApiParams(this.mockConfigData.mockConfig.apiId);
// this.searchApiParams(this.mockConfigData.mockConfig.apiId);
},
methods: {
searchApiParams(apiId) {
let selectUrl = "/mockConfig/getApiParams/" + apiId;
this.$get(selectUrl, response => {
this.apiParams = response.data;
});
},
// searchApiParams(apiId) {
// let selectUrl = "/mockConfig/getApiParams/" + apiId;
// this.$get(selectUrl, response => {
// let respData = response.data;
// if(respData.value){
// this.apiParams = respData.value;
// }
// });
// },
copyExpect(row) {
let selectUrl = "/mockConfig/mockExpectConfig/" + row.id;
this.$get(selectUrl, response => {