refactor(接口测试): 优化jsonpath推荐

This commit is contained in:
chenjianxing 2020-10-26 19:12:46 +08:00
parent 42ef1bcc89
commit 8efda5ef5e
8 changed files with 535 additions and 482 deletions

View File

@ -17,7 +17,7 @@ public class JsonPathUtils {
public static List<HashMap> getListJson(String jsonString) {
JSONObject jsonObject =JSONObject.parseObject(jsonString);
JSONObject jsonObject = JSONObject.parseObject(jsonString);
List<HashMap> allJsons =new ArrayList<>();
// 获取到所有jsonpath后获取所有的key
@ -40,127 +40,87 @@ public class JsonPathUtils {
jsonPaths.remove(parentNodeJsonPath);
}
List<String> jsonPathList = new ArrayList<>();
Iterator<String> jsonPath = jsonPaths.iterator();
///替换为点.
while (jsonPath.hasNext()) {
Map<String,String> item = new HashMap<>();
String o_json_path = "$" + jsonPath.next().replaceAll("/", ".");
String value = JSONPath.eval(jsonObject,o_json_path).toString();
String value = JSONPath.eval(jsonObject, o_json_path).toString();
if(o_json_path.toLowerCase().contains("id")) {
continue;
}
if(value.equals("") || value.equals("[]") || o_json_path.equals("")) {
continue;
}
String json_path = formatJson(o_json_path);
//System.out.println(json_path);
item.put("json_path", json_path);
item.put("json_value", addEscapeForString(value));
allJsons.add((HashMap)item);
jsonPathList.add(json_path);
}
//排序
Collections.sort(jsonPathList);
Collections.sort(allJsons, (a, b) ->
( (String)a.get("json_path") )
.compareTo( (String)b.get("json_path") )
);
return allJsons;
}
private static String formatJson(String json_path){
String ret="";
// 正则表达式
String reg = ".(\\d{1,3}).{0,1}";
Boolean change_flag = false;
Matcher m1 = Pattern.compile(reg).matcher(json_path);
String newStr="";
int rest = 0;
String tail = "";
while (m1.find()) {
while (m1.find()) {
int start = m1.start();
int end = m1.end() - 1;
if(json_path.charAt(start) != '.' || json_path.charAt(end) != '.') {
continue;
}
newStr += json_path.substring(rest,m1.start()) +"[*]." ;
newStr += json_path.substring(rest,m1.start()) +"[" + json_path.substring(start + 1, end) + "]." ;
rest = m1.end();
tail = json_path.substring(m1.end());
change_flag = true;
}
if(change_flag) {
ret = newStr + tail;
} else {
ret = json_path;
}
return ret;
}
private static String addEscapeForString(String input) {
String ret="";
String reg = "[?*/]";
Boolean change_flag = false;
Matcher m1 = Pattern.compile(reg).matcher(input);
String newStr="";
int rest = 0;
String tail = "";
while (m1.find()) {
int start = m1.start();
int end = m1.end() - 1;
newStr += input.substring(rest,m1.start()) + "\\" + m1.group(0) ;
rest = m1.end();
tail = input.substring(m1.end());
change_flag = true;
}
if(change_flag) {
ret = newStr + tail;
} else {
ret = input;
}
return ret;
}
}

View File

@ -1,141 +1,142 @@
<template>
<div>
<div class="assertion-add">
<el-row :gutter="10">
<el-col :span="4">
<el-select :disabled="isReadOnly" class="assertion-item" v-model="type" :placeholder="$t('api_test.request.assertions.select_type')"
size="small">
<el-option :label="$t('api_test.request.assertions.text')" :value="options.TEXT"/>
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/>
</el-select>
</el-col>
<el-col :span="20">
<ms-api-assertion-text :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.TEXT" :callback="after"/>
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX" :callback="after"/>
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath" v-if="type === options.JSON_PATH" :callback="after"/>
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
v-if="type === options.DURATION" :callback="after"/>
<el-button v-if="!type" :disabled="true" type="primary" size="small">Add</el-button>
</el-col>
</el-row>
</div>
<div >
<el-row :gutter="10" style="text-align: right;">
<el-button
size="small"
type="primary"
@click="suggestJson"
>推荐JSONPath断言</el-button>
<el-button
size="small"
type="danger"
@click="clearJson"
>清空JSONPath断言</el-button>
</el-row>
</div>
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions"/>
</div>
</template>
<script>
import MsApiAssertionText from "./ApiAssertionText";
import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionDuration from "./ApiAssertionDuration";
import {ASSERTION_TYPE, Assertions, JSONPath} from "../../model/ScenarioModel";
import MsApiAssertionsEdit from "./ApiAssertionsEdit";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
export default {
name: "MsApiAssertions",
components: {
MsApiAssertionJsonPath,
MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText},
props: {
assertions: Assertions,
jsonPathList: Array,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
options: ASSERTION_TYPE,
time: "",
type: "",
}
},
methods: {
after() {
this.type = "";
},
suggestJson() {
console.log("This is suggestJson")
// console.log(this.jsonPathList);
this.jsonPathList.forEach((item) => {
let jsonItem = new JSONPath();
jsonItem.expression=item.json_path;
jsonItem.expect=item.json_value;
jsonItem.setJSONPathDescription();
this.assertions.jsonPath.push(jsonItem);
});
},
clearJson() {
console.log("This is suggestJson")
// console.log(this.jsonPathList);
this.assertions.jsonPath = [];
}
}
}
</script>
<style scoped>
.assertion-item {
width: 100%;
}
.assertion-add {
padding: 10px;
border: #DCDFE6 solid 1px;
margin: 5px 0;
border-radius: 5px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
</style>
<template>
<div>
<div class="assertion-add">
<el-row :gutter="10">
<el-col :span="4">
<el-select :disabled="isReadOnly" class="assertion-item" v-model="type" :placeholder="$t('api_test.request.assertions.select_type')"
size="small">
<el-option :label="$t('api_test.request.assertions.text')" :value="options.TEXT"/>
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/>
</el-select>
</el-col>
<el-col :span="20">
<ms-api-assertion-text :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.TEXT" :callback="after"/>
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX" :callback="after"/>
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath" v-if="type === options.JSON_PATH" :callback="after"/>
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
v-if="type === options.DURATION" :callback="after"/>
<el-button v-if="!type" :disabled="true" type="primary" size="small">Add</el-button>
</el-col>
</el-row>
</div>
<div>
<el-row :gutter="10" class="json-path-suggest-button">
<el-button size="small" type="primary" @click="suggestJsonOpen">
{{$t('api_test.request.assertions.json_path_suggest')}}
</el-button>
<el-button size="small" type="danger" @click="clearJson">
{{$t('api_test.request.assertions.json_path_clear')}}
</el-button>
</el-row>
</div>
<ms-api-jsonpath-suggest-list @addJsonpathSuggest="addJsonpathSuggest" :request="request" ref="jsonpathSuggestList"/>
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions"/>
</div>
</template>
<script>
import MsApiAssertionText from "./ApiAssertionText";
import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionDuration from "./ApiAssertionDuration";
import {ASSERTION_TYPE, Assertions, HttpRequest, JSONPath} from "../../model/ScenarioModel";
import MsApiAssertionsEdit from "./ApiAssertionsEdit";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList";
export default {
name: "MsApiAssertions",
components: {
MsApiJsonpathSuggestList,
MsApiAssertionJsonPath,
MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText},
props: {
assertions: Assertions,
request: HttpRequest,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
return {
options: ASSERTION_TYPE,
time: "",
type: "",
}
},
methods: {
after() {
this.type = "";
},
suggestJsonOpen() {
if (!this.request.debugRequestResult) {
this.$message(this.$t('api_test.request.assertions.debug_first'));
return;
}
this.$refs.jsonpathSuggestList.open();
},
addJsonpathSuggest(jsonPathList) {
jsonPathList.forEach(jsonPath => {
let jsonItem = new JSONPath();
jsonItem.expression = jsonPath.json_path;
jsonItem.expect = jsonPath.json_value;
jsonItem.setJSONPathDescription();
this.assertions.jsonPath.push(jsonItem);
});
},
clearJson() {
this.assertions.jsonPath = [];
}
}
}
</script>
<style scoped>
.assertion-item {
width: 100%;
}
.assertion-add {
padding: 10px;
border: #DCDFE6 solid 1px;
margin: 5px 0;
border-radius: 5px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
.json-path-suggest-button {
text-align: right;
}
</style>

View File

@ -0,0 +1,115 @@
<template>
<el-dialog :title="$t('api_test.request.assertions.json_path_add')"
:visible.sync="dialogFormVisible"
@close="close"
width="60%" v-loading="result.loading"
:close-on-click-modal="false"
top="50px">
<el-container class="main-content">
<el-container>
<el-main class="case-content">
<el-table
:data="jsonPathList"
row-key="id"
@select-all="handleSelectAll"
@select="handleSelectionChange"
height="50vh"
ref="table">
<el-table-column type="selection"/>
<el-table-column
prop="name"
:label="$t('api_test.request.extract.json_path_expression')"
style="width: 100%">
<template v-slot:default="scope">
{{scope.row.json_path}}
</template>
</el-table-column>
<el-table-column
prop="name"
:label="$t('api_test.request.assertions.value')"
style="width: 100%">
<template v-slot:default="scope">
{{scope.row.json_value}}
</template>
</el-table-column>
</el-table>
</el-main>
</el-container>
</el-container>
<template v-slot:footer>
<ms-dialog-footer @cancel="dialogFormVisible = false" @confirm="commit"/>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {HttpRequest} from "../../model/ScenarioModel";
export default {
name: "MsApiJsonpathSuggestList",
components: {MsDialogFooter},
data() {
return {
result: {},
dialogFormVisible: false,
isCheckAll: false,
selectItems: new Set(),
jsonPathList: [],
};
},
props: {
request: HttpRequest,
},
methods: {
close() {
this.selectItems.clear();
},
open() {
this.getJsonPaths();
},
getJsonPaths() {
if (this.request.debugRequestResult) {
let param = {
jsonPath: this.request.debugRequestResult.responseResult.body
};
this.result = this.$post("/api/getJsonPaths", param).then(response => {
this.jsonPathList = response.data.data;
this.dialogFormVisible = true;
}).catch(() => {
this.$warning(this.$t('api_test.request.assertions.json_path_err'));
this.dialogFormVisible = false;
});
}
},
handleSelectAll(selection) {
if (selection.length > 0) {
this.selectItems = new Set(this.jsonPathList);
} else {
this.selectItems = new Set();
}
},
handleSelectionChange(selection, row) {
if (this.selectItems.has(row)) {
this.selectItems.delete(row);
} else {
this.selectItems.add(row);
}
},
commit() {
this.$emit("addJsonpathSuggest", this.selectItems);
this.dialogFormVisible = false;
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,237 +1,237 @@
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<el-form :model="request" :rules="rules" ref="request" label-width="100px" :disabled="isReadOnly">
<el-form-item :label="$t('api_test.request.name')" prop="name">
<el-input :disabled="isReadOnly" v-model="request.name" maxlength="300" show-word-limit/>
</el-form-item>
<el-form-item v-if="!request.useEnvironment" :label="$t('api_test.request.url')" prop="url"
class="adjust-margin-bottom">
<el-input :disabled="isReadOnly" v-model="request.url" maxlength="500"
:placeholder="$t('api_test.request.url_description')" @change="urlChange" clearable>
<template v-slot:prepend>
<ApiRequestMethodSelect :is-read-only="isReadOnly" :request="request" @change="methodChange"/>
</template>
</el-input>
</el-form-item>
<el-form-item v-if="request.useEnvironment" :label="$t('api_test.request.path')" prop="path">
<el-input :disabled="isReadOnly" v-model="request.path" maxlength="500"
:placeholder="$t('api_test.request.path_description')" @change="pathChange" clearable>
<template v-slot:prepend>
<ApiRequestMethodSelect :is-read-only="isReadOnly" :request="request" @change="methodChange"/>
</template>
</el-input>
</el-form-item>
<el-form-item v-if="request.useEnvironment" :label="$t('api_test.request.address')" class="adjust-margin-bottom">
<el-tag class="environment-display">
<span class="environment-name">{{ scenario.environment ? scenario.environment.name + ': ' : '' }}</span>
<span class="environment-url">{{ displayUrl }}</span>
<span v-if="!displayUrl"
class="environment-url-tip">{{ $t('api_test.request.please_configure_socket_in_environment') }}</span>
</el-tag>
</el-form-item>
<el-form-item>
<el-switch
v-model="request.useEnvironment"
:active-text="$t('api_test.request.refer_to_environment')" @change="useEnvironmentChange">
</el-switch>
<el-checkbox class="follow-redirects-item" v-model="request.followRedirects">{{$t('api_test.request.follow_redirects')}}</el-checkbox>
<el-checkbox class="do-multipart-post" v-model="request.doMultipartPost">{{$t('api_test.request.do_multipart_post')}}</el-checkbox>
</el-form-item>
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small"
type="primary" @click="runDebug">{{ $t('api_test.request.debug') }}
</el-button>
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_test.request.parameters')" name="parameters">
<ms-api-variable :is-read-only="isReadOnly"
:parameters="request.parameters"
:environment="scenario.environment"
:scenario="scenario"
:extract="request.extract"
:description="$t('api_test.request.parameters_desc')"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.headers')" name="headers">
<ms-api-key-value :is-read-only="isReadOnly" :isShowEnable="true" :suggestions="headerSuggestions" :items="request.headers"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.body')" name="body">
<ms-api-body :is-read-only="isReadOnly"
:body="request.body"
:scenario="scenario"
:extract="request.extract"
:environment="scenario.environment"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
<ms-api-assertions :jsonPathList="jsonPathList" :is-read-only="isReadOnly" :assertions="request.assertions"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.extract.label')" name="extract">
<ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.pre_exec_script')" name="jsr223PreProcessor">
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PreProcessor"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.post_exec_script')" name="jsr223PostProcessor">
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PostProcessor"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.timeout_config')" name="advancedConfig">
<ms-api-advanced-config :is-read-only="isReadOnly" :request="request"/>
</el-tab-pane>
</el-tabs>
</el-form>
</template>
<script>
import MsApiKeyValue from "../ApiKeyValue";
import MsApiBody from "../body/ApiBody";
import MsApiAssertions from "../assertion/ApiAssertions";
import {HttpRequest, KeyValue, Scenario} from "../../model/ScenarioModel";
import MsApiExtract from "../extract/ApiExtract";
import ApiRequestMethodSelect from "../collapse/ApiRequestMethodSelect";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsApiVariable from "@/business/components/api/test/components/ApiVariable";
import MsJsr233Processor from "../processor/Jsr233Processor";
import MsApiAdvancedConfig from "../ApiAdvancedConfig";
export default {
name: "MsApiHttpRequestForm",
components: {
MsJsr233Processor,
MsApiAdvancedConfig,
MsApiVariable, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiBody, MsApiKeyValue},
props: {
request: HttpRequest,
jsonPathList: Array,
scenario: Scenario,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
let validateURL = (rule, value, callback) => {
try {
new URL(this.addProtocol(this.request.url));
} catch (e) {
callback(this.$t('api_test.request.url_invalid'));
}
};
return {
activeName: "parameters",
rules: {
name: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
url: [
{max: 500, required: true, message: this.$t('commons.input_limit', [1, 500]), trigger: 'blur'},
{validator: validateURL, trigger: 'blur'}
],
path: [
{max: 500, message: this.$t('commons.input_limit', [0, 500]), trigger: 'blur'},
]
},
headerSuggestions: REQUEST_HEADERS
}
},
methods: {
urlChange() {
if (!this.request.url) return;
let url = this.getURL(this.addProtocol(this.request.url));
if (url) {
this.request.url = decodeURIComponent(url.origin + url.pathname);
}
},
pathChange() {
if (!this.request.path) return;
let url = this.getURL(this.displayUrl);
let urlStr = url.origin + url.pathname;
let envUrl = this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket;
this.request.path = decodeURIComponent(urlStr.substring(envUrl.length, urlStr.length));
},
getURL(urlStr) {
try {
let url = new URL(urlStr);
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.parameters.splice(0, 0, new KeyValue({name: key, value: value}));
}
});
return url;
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
methodChange(value) {
if (value === 'GET' && this.activeName === 'body') {
this.activeName = 'parameters';
}
},
useEnvironmentChange(value) {
if (value && !this.scenario.environment) {
this.$error(this.$t('api_test.request.please_add_environment_to_scenario'), 2000);
this.request.useEnvironment = false;
}
this.$refs["request"].clearValidate();
},
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
}
}
return url;
},
runDebug() {
this.$emit('runDebug');
}
},
computed: {
displayUrl() {
return (this.scenario.environment && this.scenario.environment.config.httpConfig.socket) ?
this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket + (this.request.path ? this.request.path : '')
: '';
}
}
}
</script>
<style scoped>
.el-tag {
width: 100%;
height: 40px;
line-height: 40px;
}
.environment-display {
font-size: 14px;
}
.environment-name {
font-weight: bold;
font-style: italic;
}
.adjust-margin-bottom {
margin-bottom: 10px;
}
.environment-url-tip {
color: #F56C6C;
}
.follow-redirects-item {
margin-left: 30px;
}
.do-multipart-post {
margin-left: 10px;
}
</style>
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<el-form :model="request" :rules="rules" ref="request" label-width="100px" :disabled="isReadOnly">
<el-form-item :label="$t('api_test.request.name')" prop="name">
<el-input :disabled="isReadOnly" v-model="request.name" maxlength="300" show-word-limit/>
</el-form-item>
<el-form-item v-if="!request.useEnvironment" :label="$t('api_test.request.url')" prop="url"
class="adjust-margin-bottom">
<el-input :disabled="isReadOnly" v-model="request.url" maxlength="500"
:placeholder="$t('api_test.request.url_description')" @change="urlChange" clearable>
<template v-slot:prepend>
<ApiRequestMethodSelect :is-read-only="isReadOnly" :request="request" @change="methodChange"/>
</template>
</el-input>
</el-form-item>
<el-form-item v-if="request.useEnvironment" :label="$t('api_test.request.path')" prop="path">
<el-input :disabled="isReadOnly" v-model="request.path" maxlength="500"
:placeholder="$t('api_test.request.path_description')" @change="pathChange" clearable>
<template v-slot:prepend>
<ApiRequestMethodSelect :is-read-only="isReadOnly" :request="request" @change="methodChange"/>
</template>
</el-input>
</el-form-item>
<el-form-item v-if="request.useEnvironment" :label="$t('api_test.request.address')" class="adjust-margin-bottom">
<el-tag class="environment-display">
<span class="environment-name">{{ scenario.environment ? scenario.environment.name + ': ' : '' }}</span>
<span class="environment-url">{{ displayUrl }}</span>
<span v-if="!displayUrl"
class="environment-url-tip">{{ $t('api_test.request.please_configure_socket_in_environment') }}</span>
</el-tag>
</el-form-item>
<el-form-item>
<el-switch
v-model="request.useEnvironment"
:active-text="$t('api_test.request.refer_to_environment')" @change="useEnvironmentChange">
</el-switch>
<el-checkbox class="follow-redirects-item" v-model="request.followRedirects">{{$t('api_test.request.follow_redirects')}}</el-checkbox>
<el-checkbox class="do-multipart-post" v-model="request.doMultipartPost">{{$t('api_test.request.do_multipart_post')}}</el-checkbox>
</el-form-item>
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small"
type="primary" @click="runDebug">{{ $t('api_test.request.debug') }}
</el-button>
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_test.request.parameters')" name="parameters">
<ms-api-variable :is-read-only="isReadOnly"
:parameters="request.parameters"
:environment="scenario.environment"
:scenario="scenario"
:extract="request.extract"
:description="$t('api_test.request.parameters_desc')"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.headers')" name="headers">
<ms-api-key-value :is-read-only="isReadOnly" :isShowEnable="true" :suggestions="headerSuggestions" :items="request.headers"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.body')" name="body">
<ms-api-body :is-read-only="isReadOnly"
:body="request.body"
:scenario="scenario"
:extract="request.extract"
:environment="scenario.environment"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
<ms-api-assertions :request="request" :is-read-only="isReadOnly" :assertions="request.assertions"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.extract.label')" name="extract">
<ms-api-extract :is-read-only="isReadOnly" :extract="request.extract"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.pre_exec_script')" name="jsr223PreProcessor">
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PreProcessor"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.processor.post_exec_script')" name="jsr223PostProcessor">
<ms-jsr233-processor :is-read-only="isReadOnly" :jsr223-processor="request.jsr223PostProcessor"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.timeout_config')" name="advancedConfig">
<ms-api-advanced-config :is-read-only="isReadOnly" :request="request"/>
</el-tab-pane>
</el-tabs>
</el-form>
</template>
<script>
import MsApiKeyValue from "../ApiKeyValue";
import MsApiBody from "../body/ApiBody";
import MsApiAssertions from "../assertion/ApiAssertions";
import {HttpRequest, KeyValue, Scenario} from "../../model/ScenarioModel";
import MsApiExtract from "../extract/ApiExtract";
import ApiRequestMethodSelect from "../collapse/ApiRequestMethodSelect";
import {REQUEST_HEADERS} from "@/common/js/constants";
import MsApiVariable from "@/business/components/api/test/components/ApiVariable";
import MsJsr233Processor from "../processor/Jsr233Processor";
import MsApiAdvancedConfig from "../ApiAdvancedConfig";
export default {
name: "MsApiHttpRequestForm",
components: {
MsJsr233Processor,
MsApiAdvancedConfig,
MsApiVariable, ApiRequestMethodSelect, MsApiExtract, MsApiAssertions, MsApiBody, MsApiKeyValue},
props: {
request: HttpRequest,
jsonPathList: Array,
scenario: Scenario,
isReadOnly: {
type: Boolean,
default: false
}
},
data() {
let validateURL = (rule, value, callback) => {
try {
new URL(this.addProtocol(this.request.url));
} catch (e) {
callback(this.$t('api_test.request.url_invalid'));
}
};
return {
activeName: "parameters",
rules: {
name: [
{max: 300, message: this.$t('commons.input_limit', [1, 300]), trigger: 'blur'}
],
url: [
{max: 500, required: true, message: this.$t('commons.input_limit', [1, 500]), trigger: 'blur'},
{validator: validateURL, trigger: 'blur'}
],
path: [
{max: 500, message: this.$t('commons.input_limit', [0, 500]), trigger: 'blur'},
]
},
headerSuggestions: REQUEST_HEADERS
}
},
methods: {
urlChange() {
if (!this.request.url) return;
let url = this.getURL(this.addProtocol(this.request.url));
if (url) {
this.request.url = decodeURIComponent(url.origin + url.pathname);
}
},
pathChange() {
if (!this.request.path) return;
let url = this.getURL(this.displayUrl);
let urlStr = url.origin + url.pathname;
let envUrl = this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket;
this.request.path = decodeURIComponent(urlStr.substring(envUrl.length, urlStr.length));
},
getURL(urlStr) {
try {
let url = new URL(urlStr);
url.searchParams.forEach((value, key) => {
if (key && value) {
this.request.parameters.splice(0, 0, new KeyValue({name: key, value: value}));
}
});
return url;
} catch (e) {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
methodChange(value) {
if (value === 'GET' && this.activeName === 'body') {
this.activeName = 'parameters';
}
},
useEnvironmentChange(value) {
if (value && !this.scenario.environment) {
this.$error(this.$t('api_test.request.please_add_environment_to_scenario'), 2000);
this.request.useEnvironment = false;
}
this.$refs["request"].clearValidate();
},
addProtocol(url) {
if (url) {
if (!url.toLowerCase().startsWith("https") && !url.toLowerCase().startsWith("http")) {
return "https://" + url;
}
}
return url;
},
runDebug() {
this.$emit('runDebug');
}
},
computed: {
displayUrl() {
return (this.scenario.environment && this.scenario.environment.config.httpConfig.socket) ?
this.scenario.environment.config.httpConfig.protocol + '://' + this.scenario.environment.config.httpConfig.socket + (this.request.path ? this.request.path : '')
: '';
}
}
}
</script>
<style scoped>
.el-tag {
width: 100%;
height: 40px;
line-height: 40px;
}
.environment-display {
font-size: 14px;
}
.environment-name {
font-weight: bold;
font-style: italic;
}
.adjust-margin-bottom {
margin-bottom: 10px;
}
.environment-url-tip {
color: #F56C6C;
}
.follow-redirects-item {
margin-left: 30px;
}
.do-multipart-post {
margin-left: 10px;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div class="request-form">
<component @runDebug="runDebug" :is="component" :jsonPathList="jsonPathList" :is-read-only="isReadOnly" :request="request" :scenario="scenario"/>
<component @runDebug="runDebug" :is="component" :is-read-only="isReadOnly" :request="request" :scenario="scenario"/>
<el-divider v-if="isCompleted"></el-divider>
<ms-request-result-tail v-loading="debugReportLoading" v-if="isCompleted" :request="request.debugRequestResult ? request.debugRequestResult : {responseResult: {}, subRequestResults: []}"
:scenario-name="request.debugScenario ? request.debugScenario.name : ''" ref="msDebugResult"/>
@ -96,37 +96,6 @@ export default {
if (res.scenarios && res.scenarios.length > 0) {
this.request.debugScenario = res.scenarios[0];
this.request.debugRequestResult = this.request.debugScenario.requestResults[0];
//add by Cuipeng
this.debugResultDetails=this.request.debugRequestResult.responseResult.body;
// console.log(this.debugResultDetails);
try {
let param = {
jsonPath: this.debugResultDetails
};
this.$post("/api/getJsonPaths", param).then(response1 => {
this.jsonPathList = response1.data.data;
// console.log(this.jsonPathList);
}).catch(() => {
this.$warning("获取推荐jsonpath列表失败");
});
} catch (e) {
alert("调试结果的返回不是一个json");
throw e;
}
//add by Cuipeng
this.deleteReport(this.debugReportId);
} else {
this.request.debugScenario = new Scenario();

View File

@ -557,7 +557,12 @@ export default {
expect: "Expect Value",
expression: "Expression",
response_in_time: "Response in time",
ignore_status: "Ignore Status"
ignore_status: "Ignore Status",
json_path_add: "Add JONPATH Assertions",
json_path_err: "The response result is not in JSON format",
json_path_suggest: "JSONPath Assertion Suggest",
json_path_clear: "Clear JSONPath Assertion",
debug_first: "First, debug to get the response",
},
extract: {
label: "Extract from response",

View File

@ -557,7 +557,11 @@ export default {
expect: "期望值",
expression: "Perl型正则表达式",
response_in_time: "响应时间在...毫秒以内",
ignore_status: "忽略状态"
json_path_add: "添加 JONPATH 断言",
json_path_err: "响应结果不是 JSON 格式",
json_path_suggest: "推荐JSONPath断言",
json_path_clear: "清空JSONPath断言",
debug_first: "请先执行调试获取响应结果",
},
extract: {
label: "提取",

View File

@ -217,20 +217,25 @@ export default {
delete_warning: '刪除該組織將同步刪除該組織下所有相關工作空間和相關工作空間下的所有項目,以及項目中的所有用例、接口測試、性能測試等,確定要刪除嗎?',
service_integration: '服務集成',
defect_manage: '缺陷管理平臺',
message_settings:'消息設',
message_settings:'消息設',
message:{
jenkins_task_notification: 'Jenkins任務通知',
test_plan_task_notification: '測試計任務通知',
jenkins_task_notification: 'Jenkins接口調用任務通知',
test_plan_task_notification: '測試計任務通知',
test_review_task_notice: '測試評審任務通知',
defect_task_notification: '缺陷任務通知',
create_new_notification: '創建新通知',
select_events: '選擇事件',
select_receiving_method: '選擇接收管道',
defect_task_notification: '缺陷任務通知',
select_receiving_method: '選擇接收方式',
mail: '郵件',
nail_robot: '釘釘機器人',
enterprise_wechat_robot: '企業微信機器人',
message_webhook: '接收管道為釘釘和企業機器人時webhook為必填項\n' +
'\n'
notes: '註意: 1.事件,接收方式,接收人為必填項;\n' +
' 2.接收方式除郵件外webhook為必填\n' +
' 3.機器人選擇為群機器人,安全驗證選擇“自定義關鍵詞” "任務通知"',
message: '事件,接收人,接收方式為必填項',
message_webhook: '接收方式為釘釘和企業機器人時webhook為必填項'
},
integration: {
select_defect_platform: '請選擇要集成的缺陷管理平臺:',
@ -254,17 +259,7 @@ export default {
successful_operation: '操作成功',
not_integrated: '未集成該平臺',
choose_platform: '請選擇集成的平臺',
verified: '驗證通過',
mail: '郵件',
nail_robot: '釘釘機器人',
enterprise_wechat_robot: '企業微信機器人',
notes: '注意1.事件,接收管道,接收人為必填項;\n' +
'\n' +
'2.接收管道除郵件外webhook為必填\n' +
'\n' +
'3.機器人選擇為群機器人,安全驗證選擇“自定義關鍵字”:“任務通知”',
message: '事件,接收人,接收管道為必填項\n' +
'\n'
verified: '驗證通過'
}
},
project: {
@ -562,7 +557,11 @@ export default {
expect: "期望值",
expression: "Perl型正則表達式",
response_in_time: "響應時間在...毫秒以內",
ignore_status: "忽略狀態"
json_path_add: "添加 JONPATH 斷言",
json_path_err: "響應結果不是 JSON 格式",
json_path_suggest: "推薦JSONPath斷言",
json_path_clear: "清空JSONPath斷言",
debug_first: "請先執行調試獲取響應結果",
},
extract: {
label: "提取",