feat(接口定义): 完成提取参数和断言规则

This commit is contained in:
fit2-zhao 2020-11-23 15:17:19 +08:00
parent 595c9572de
commit 7f2fe8acd1
23 changed files with 141 additions and 108 deletions

View File

@ -220,6 +220,7 @@ public class ApiDefinitionService {
createBodyFiles(bodyUploadIds, bodyFiles);
HashTree hashTree = request.getTestElement().generateHashTree();
request.getTestElement().getJmx(hashTree);
// 调用执行方法
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.DELIMIT.name());
return request.getId();

@ -1 +1 @@
Subproject commit 24047fea950a74f7848a9fdaa857a22b884c4ce2
Subproject commit 419c75bca64b7c5bfbd1194d7f0fd9919f0caa04

View File

@ -167,7 +167,6 @@ check_owner_comment=The current user does not have permission to manipulate this
upload_content_is_null=Imported content is empty
test_plan_notification=Test plan notification
task_defect_notification=Task defect notification
task_notification=Jenkins Task notification
task_notification_=Timing task result notification
api_definition_url_not_repeating=The interface request address already exists
task_notification_jenkins=Jenkins Task notification

View File

@ -168,7 +168,6 @@ check_owner_comment=当前用户没有操作此评论的权限
upload_content_is_null=导入内容为空
test_plan_notification=测试计划通知
task_defect_notification=缺陷任务通知
task_notification=jenkins任务通知
task_notification_=定时任务结果通知
api_definition_url_not_repeating=接口请求地址已经存在
task_notification_jenkins=jenkins任务通知

View File

@ -171,7 +171,5 @@ test_plan_notification=測試計畫通知
task_defect_notification=缺陷任務通知
task_notification_jenkins=jenkins任務通知
task_notification=任務通知
task_notification=jenkins任務通知
task_notification_=定時任務通知
api_definition_url_not_repeating=接口請求地址已經存在

View File

@ -17,14 +17,12 @@
<script>
import {Duration} from "../../model/ApiTestModel";
export default {
name: "MsApiAssertionDuration",
props: {
duration: Duration,
value: [Number, String],
duration:{},
edit: Boolean,
callback: Function,
isReadOnly: {
@ -42,6 +40,7 @@
},
remove() {
this.duration.value = undefined;
},
change(value) {
if (this.validate()) {

View File

@ -27,7 +27,6 @@
props: {
jsonPath: {
type: JSONPath,
default: () => {
return new JSONPath();
}

View File

@ -64,7 +64,6 @@ export default {
components: {MsDialogFooter, MsJsr233Processor},
props: {
assertion: {
type: AssertionJSR223,
default: () => {
return new AssertionJSR223();
}

View File

@ -37,7 +37,6 @@ export default {
props: {
regex: {
type: Regex,
default: () => {
return new Regex();
}

View File

@ -23,7 +23,6 @@
props: {
xPath2: {
type: XPath2,
default: () => {
return new XPath2();
}

View File

@ -1,12 +1,18 @@
<template>
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin-top: 20px">
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin-top: 20px" v-loading="loading">
<div>
<el-button class="ms-left-buttion" size="small" type="danger" plain>{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<el-button size="small" style="float: right;margin-top: 0px" @click="remove">移除</el-button>
</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.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="'XPath'" :value="options.XPATH2"/>
@ -15,8 +21,10 @@
</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-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"
@ -77,7 +85,7 @@
},
props: {
assertions: Assertions,
assertions: {},
request: {},
scenario: Scenario,
isReadOnly: {
@ -91,12 +99,14 @@
options: ASSERTION_TYPE,
time: "",
type: "",
loading: false,
}
},
methods: {
after() {
this.type = "";
this.reload();
},
suggestJsonOpen() {
if (!this.request.debugRequestResult) {
@ -105,6 +115,15 @@
}
this.$refs.jsonpathSuggestList.open();
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
remove(){
this.$emit('remove', this.assertions);
},
addJsonpathSuggest(jsonPathList) {
jsonPathList.forEach(jsonPath => {
let jsonItem = new JSONPath();

View File

@ -54,7 +54,6 @@
<script>
import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionDuration from "./ApiAssertionDuration";
import {Assertions} from "../../model/ApiTestModel";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
import MsApiAssertionXPath2 from "./ApiAssertionXPath2";
@ -67,7 +66,7 @@ export default {
MsApiAssertionJsr223, MsApiAssertionJsonPath, MsApiAssertionDuration, MsApiAssertionRegex},
props: {
assertions: Assertions,
assertions: {},
isReadOnly: {
type: Boolean,
default: false

View File

@ -50,64 +50,65 @@
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {HttpRequest} from "../../model/ApiTestModel";
export default {
name: "MsApiJsonpathSuggestList",
components: {MsDialogFooter},
data() {
return {
result: {},
dialogFormVisible: false,
isCheckAll: false,
selectItems: new Set(),
jsonPathList: [],
};
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {HttpRequest} from "../../model/ApiTestModel";
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();
},
props: {
request: HttpRequest,
open() {
this.getJsonPaths();
},
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;
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>

View File

@ -1,6 +1,8 @@
<template>
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin-top: 20px">
<el-button class="ms-left-buttion" size="small" type="info" plain>提取参数</el-button>
<el-button class="ms-left-buttion" size="small" type="info" plain>{{$t('api_test.definition.request.extract_param')}}</el-button>
<el-button size="small" style="float: right;margin-top: 0px" @click="remove">移除</el-button>
<div style="margin: 20px">
<div class="extract-description">
{{$t('api_test.request.extract.description')}}
@ -59,7 +61,11 @@
methods: {
after() {
this.type = "";
}
},
remove() {
this.$emit('remove', this.extract);
},
},
computed: {

View File

@ -43,7 +43,6 @@
}
},
common: {
type: ExtractCommon,
default: () => {
return new ExtractCommon();
}

View File

@ -43,7 +43,7 @@
components: {MsApiExtractCommon},
props: {
extract: Extract,
extract: {},
isReadOnly: {
type: Boolean,
default: false

View File

@ -19,7 +19,7 @@
<!--query 参数-->
<el-tab-pane :label="$t('api_test.definition.request.query_param')" name="parameters" :disabled="request.rest.length>1">
<el-tooltip class="item-tabs" effect="dark" content="地址栏中跟在?后面的参数,如updateapi?id=112" placement="top-start" slot="label">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.query_info')" placement="top-start" slot="label">
<span>{{$t('api_test.definition.request.query_param')}}
<div class="el-step__icon is-text ms-api-col ms-query" v-if="request.arguments.length>1">
<div class="el-step__icon-inner">{{request.arguments.length-1}}</div>
@ -31,7 +31,7 @@
<!--REST 参数-->
<el-tab-pane :label="$t('api_test.definition.request.rest_param')" name="rest" :disabled="request.arguments.length>1">
<el-tooltip class="item-tabs" effect="dark" content="地址栏中被斜杠/分隔的参数如updateapi/{id}" placement="top-start" slot="label">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.rest_info')" placement="top-start" slot="label">
<span>
{{$t('api_test.definition.request.rest_param')}}
<div class="el-step__icon is-text ms-api-col ms-query" v-if="request.rest.length>1">
@ -49,7 +49,7 @@
<!-- 认证配置 -->
<el-tab-pane :label="$t('api_test.definition.request.auth_config')" name="authConfig">
<el-tooltip class="item-tabs" effect="dark" content="请求需要进行权限校验" placement="top-start" slot="label">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.auth_config_info')" placement="top-start" slot="label">
<span>{{$t('api_test.definition.request.auth_config')}}</span>
</el-tooltip>
@ -58,31 +58,30 @@
</el-tabs>
</div>
<!--定制脚本-->
<div v-for="row in request.hashTree" :key="row.id" v-loading="isReloadData">
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @remove="remove" :is-read-only="false" title="前置脚本" style-type="warning"
<!-- 前置脚本 -->
<ms-jsr233-processor v-if="row.label ==='JSR223 PreProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.pre_script')" style-type="warning"
:jsr223-processor="row"/>
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" title="后置脚本" style-type="success"
<!--后置脚本-->
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" :title="$t('api_test.definition.request.post_script')" style-type="success"
:jsr223-processor="row"/>
<!--断言规则-->
<ms-api-assertions v-if="row.type==='Assertions'" @remove="remove" :is-read-only="isReadOnly" :assertions="row"/>
<!--提取规则-->
<ms-api-extract :is-read-only="isReadOnly" @remove="remove" v-if="row.type==='Extract'" :extract="row"/>
<ms-api-assertions v-if="row.type==='Assertions'" :is-read-only="isReadOnly" :assertions="row"/>
</div>
<!--
<ms-api-extract :is-read-only="isReadOnly" v-if="row.label==='JSONPostProcessor'" :extract="row"/>
-->
</el-col>
<!--操作按钮-->
<el-col :span="3" class="ms-left-cell">
<el-button class="ms-left-buttion" size="small" type="warning" @click="addPre" plain>+前置脚本</el-button>
<el-button class="ms-left-buttion" size="small" type="warning" @click="addPre" plain>+{{$t('api_test.definition.request.pre_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="success" @click="addPost" plain>+后置脚本</el-button>
<el-button class="ms-left-buttion" size="small" type="success" @click="addPost" plain>+{{$t('api_test.definition.request.post_script')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="danger" @click="addAssertions" plain>+断言规则</el-button>
<el-button class="ms-left-buttion" size="small" type="danger" @click="addAssertions" plain>+{{$t('api_test.definition.request.assertions_rule')}}</el-button>
<br/>
<el-button class="ms-left-buttion" size="small" type="info" @click="addExtract" plain>+提取参数</el-button>
<el-button class="ms-left-buttion" size="small" type="info" @click="addExtract" plain>+{{$t('api_test.definition.request.extract_param')}}</el-button>
</el-col>
</el-row>
</template>
@ -99,7 +98,7 @@
import {createComponent} from "../jmeter/components";
import MsApiAssertions from "../assertion/ApiAssertions";
import MsApiExtract from "../extract/ApiExtract";
import {Assertions} from "../../model/ApiTestModel";
import {Assertions, Extract} from "../../model/ApiTestModel";
export default {
name: "MsApiHttpRequestForm",
@ -143,17 +142,8 @@
},
headerSuggestions: REQUEST_HEADERS,
isReloadData: false,
assertions: [],
}
},
created() {
this.request.hashTree.forEach(row => {
if (row.type === "Assertions") {
row = new Assertions({text: row.text, regex: row.regex, jsonPath: row.jsonPath, jsr223: row.jsr223, xpath2: row.xpath2, duration: row.duration});
}
})
console.log(this.assertions)
},
methods: {
addPre() {
let jsr223PreProcessor = createComponent("JSR223PreProcessor");
@ -166,13 +156,12 @@
this.reload();
},
addAssertions() {
//let jsonPathAssertion = createComponent("JSONPathAssertion");
let assertions = new Assertions();
this.request.hashTree.push(assertions);
this.reload();
},
addExtract() {
let jsonPostProcessor = createComponent("JSONPostProcessor");
let jsonPostProcessor = new Extract();
this.request.hashTree.push(jsonPostProcessor);
this.reload();
},

View File

@ -16,6 +16,15 @@
<pre>{{response.responseResult.console}}</pre>
</el-tab-pane>
<el-tab-pane :label="$t('api_report.assertions')" name="assertions" class="pane assertions">
<ms-assertion-results :assertions="response.responseResult.assertions"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.request.extract.label')" name="label" class="pane">
<pre>{{response.responseResult.vars}}</pre>
</el-tab-pane>
<el-tab-pane v-if="activeName == 'body'" :disabled="true" name="mode" class="pane cookie">
<template v-slot:label>
<ms-dropdown :commands="modes" :default-command="mode" @command="modeChange"/>

View File

@ -901,6 +901,7 @@ export class Duration extends AssertionType {
export class Extract extends BaseConfig {
constructor(options) {
super();
this.type = "Extract";
this.regex = [];
this.json = [];
this.xpath = [];

@ -1 +1 @@
Subproject commit eb237fb6bfeba8d99e4db52450ae92f3cdd4ea33
Subproject commit 33bbdb3f528c914bf333b2c1839dd6d3bbd9b569

View File

@ -518,6 +518,13 @@ export default {
response_body: "Response body",
console: "Console",
status_code: "Status code",
query_info: "Follow the address bar? The following parameters, such as updateapi?id=112",
rest_info: "Slash/separated parameters in the address bar, such as updateapi/{id}",
auth_config_info: "Request requires permission verification",
pre_script: "Prescript",
post_script: "Postscript",
extract_param: "Extract parameters",
}
},
environment: {

View File

@ -519,7 +519,12 @@ export default {
response_body: "响应体",
console: "控制台",
status_code: "状态码",
query_info: "地址栏中跟在?后面的参数,如updateapi?id=112",
rest_info: "地址栏中被斜杠/分隔的参数如updateapi/{id}",
auth_config_info: "请求需要进行权限校验",
pre_script: "前置脚本",
post_script: "后置脚本",
extract_param:"提取参数",
}
},
environment: {

View File

@ -519,6 +519,12 @@ export default {
response_body: "響應體",
console: "控制臺",
status_code: "狀態碼",
query_info: "地址欄中跟在?後面的參數,如updateapi?id=112",
rest_info: "地址欄中被斜杠/分隔的參數如updateapi/{id}",
auth_config_info: "請求需要進行權限校驗",
pre_script: "前置腳本",
post_script: "後置腳本",
extract_param: "提取參數",
}
},