feat(接口定义): 增加断言
This commit is contained in:
parent
58cbe145f7
commit
06e8d48344
|
@ -4,6 +4,7 @@ import com.alibaba.fastjson.annotation.JSONField;
|
|||
import com.alibaba.fastjson.annotation.JSONType;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
|
||||
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
|
||||
import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager;
|
||||
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
|
||||
|
@ -29,9 +30,10 @@ import java.util.List;
|
|||
@JsonSubTypes.Type(value = MsTestPlan.class, name = "TestPlan"),
|
||||
@JsonSubTypes.Type(value = MsThreadGroup.class, name = "ThreadGroup"),
|
||||
@JsonSubTypes.Type(value = MsAuthManager.class, name = "AuthManager"),
|
||||
@JsonSubTypes.Type(value = MsAssertions.class, name = "Assertions"),
|
||||
|
||||
})
|
||||
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223PostProcessor.class, MsJSR223PreProcessor.class,MsTestPlan.class,MsThreadGroup.class, AuthManager.class}, typeKey = "type")
|
||||
@JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223PostProcessor.class, MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class}, typeKey = "type")
|
||||
@Data
|
||||
public abstract class MsTestElement {
|
||||
private String type;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package io.metersphere.api.dto.definition.request.assertions;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MsAssertionDuration extends MsAssertionType {
|
||||
private long value;
|
||||
|
||||
public MsAssertionDuration() {
|
||||
setType(MsAssertionType.DURATION);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return value > 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.api.dto.definition.request.assertions;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MsAssertionJSR223 extends MsAssertionType {
|
||||
private String variable;
|
||||
private String operator;
|
||||
private String value;
|
||||
private String desc;
|
||||
private String name;
|
||||
private String script;
|
||||
private String language;
|
||||
|
||||
public MsAssertionJSR223() {
|
||||
setType(MsAssertionType.JSR223);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(script) && StringUtils.isNotBlank(language);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package io.metersphere.api.dto.definition.request.assertions;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MsAssertionJsonPath extends MsAssertionType {
|
||||
private String expect;
|
||||
private String expression;
|
||||
private String description;
|
||||
|
||||
public MsAssertionJsonPath() {
|
||||
setType(MsAssertionType.JSON_PATH);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(expression);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.metersphere.api.dto.definition.request.assertions;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MsAssertionRegex extends MsAssertionType {
|
||||
private String subject;
|
||||
private String expression;
|
||||
private String description;
|
||||
private boolean assumeSuccess;
|
||||
|
||||
public MsAssertionRegex() {
|
||||
setType(MsAssertionType.REGEX);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(subject) && StringUtils.isNotBlank(expression);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.api.dto.definition.request.assertions;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MsAssertionType {
|
||||
public final static String REGEX = "Regex";
|
||||
public final static String DURATION = "Duration";
|
||||
public final static String JSON_PATH = "JSONPath";
|
||||
public final static String JSR223 = "JSR223";
|
||||
public final static String TEXT = "Text";
|
||||
public final static String XPATH2 = "XPath2";
|
||||
|
||||
private String type;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package io.metersphere.api.dto.definition.request.assertions;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MsAssertionXPath2 extends MsAssertionType {
|
||||
private String expression;
|
||||
|
||||
public MsAssertionXPath2() {
|
||||
setType(MsAssertionType.XPATH2);
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return StringUtils.isNotBlank(expression);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package io.metersphere.api.dto.definition.request.assertions;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONType;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@JSONType(typeName = "Assertions")
|
||||
public class MsAssertions extends MsTestElement {
|
||||
private List<MsAssertionRegex> regex;
|
||||
private List<MsAssertionJsonPath> jsonPath;
|
||||
private List<MsAssertionJSR223> jsr223;
|
||||
private List<MsAssertionXPath2> xpath2;
|
||||
private MsAssertionDuration duration;
|
||||
private String type = "Assertions";
|
||||
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
|
||||
// final HashTree testPlanTree = tree.add(getPlan());
|
||||
// if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||
// hashTree.forEach(el -> {
|
||||
// el.toHashTree(testPlanTree, el.getHashTree());
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,6 @@ import io.metersphere.api.dto.definition.request.MsTestElement;
|
|||
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
|
||||
import io.metersphere.api.dto.definition.request.prop.BoolProp;
|
||||
import io.metersphere.api.dto.definition.request.prop.StringProp;
|
||||
import io.metersphere.api.dto.scenario.AuthConfig;
|
||||
import io.metersphere.api.dto.scenario.Body;
|
||||
import io.metersphere.api.dto.scenario.KeyValue;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
|
@ -72,7 +71,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
private List<KeyValue> rest;
|
||||
|
||||
@JSONField(ordinal = 20)
|
||||
private AuthConfig authConfig;
|
||||
private String url;
|
||||
|
||||
@JSONField(ordinal = 21)
|
||||
private BoolProp followRedirects;
|
||||
|
@ -83,8 +82,6 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
@JSONField(ordinal = 23)
|
||||
private String useEnvironment;
|
||||
|
||||
@JSONField(ordinal = 24)
|
||||
private String url;
|
||||
|
||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree) {
|
||||
HTTPSamplerProxy sampler = new HTTPSamplerProxy();
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row type="flex" align="middle" v-if="!edit">
|
||||
<div class="assertion-item label">
|
||||
{{ assertion.desc }}
|
||||
</div>
|
||||
<div class="assertion-item btn">
|
||||
<el-button :disabled="isReadOnly" type="success" size="small" @click="detail">
|
||||
{{ $t('commons.edit') }}
|
||||
</el-button>
|
||||
<el-button :disabled="isReadOnly" type="primary" size="small" @click="add">
|
||||
{{ $t('api_test.request.assertions.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row type="flex" justify="space-between" align="middle" v-else>
|
||||
<div class="assertion-item label">
|
||||
{{ assertion.desc }}
|
||||
</div>
|
||||
<div class="assertion-item btn circle">
|
||||
<el-button :disabled="isReadOnly" type="success" size="mini" icon="el-icon-edit" circle @click="detail"/>
|
||||
<el-button :disabled="isReadOnly" type="danger" size="mini" icon="el-icon-delete" circle @click="remove"/>
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<el-dialog :title="$t('api_test.request.assertions.script')" :visible.sync="visible" width="900px">
|
||||
<el-row type="flex" justify="space-between" align="middle" class="quick-script-block">
|
||||
<div class="assertion-item input">
|
||||
<el-input size="small" v-model="assertion.variable"
|
||||
:placeholder="$t('api_test.request.assertions.variable_name')" @change="quickScript"/>
|
||||
</div>
|
||||
|
||||
<div class="assertion-item select">
|
||||
<el-select v-model="assertion.operator" :placeholder="$t('commons.please_select')" size="small"
|
||||
@change="changeOperator">
|
||||
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value"/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="assertion-item input">
|
||||
<el-input size="small" v-model="assertion.value" :placeholder="$t('api_test.value')"
|
||||
@change="quickScript" v-if="!hasEmptyOperator"/>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-input size="small" v-model="assertion.desc" :placeholder="$t('api_test.request.assertions.script_name')"
|
||||
class="quick-script-block"/>
|
||||
<ms-jsr233-processor ref="jsr233" :is-read-only="isReadOnly" :jsr223-processor="assertion" :templates="templates"
|
||||
:height="300"/>
|
||||
<template v-slot:footer v-if="!edit">
|
||||
<ms-dialog-footer
|
||||
@cancel="close"
|
||||
@confirm="confirm"/>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {AssertionJSR223} from "../../model/ApiTestModel";
|
||||
import MsJsr233Processor from "../processor/Jsr233Processor";
|
||||
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||
|
||||
export default {
|
||||
name: "MsApiAssertionJsr223",
|
||||
components: {MsDialogFooter, MsJsr233Processor},
|
||||
props: {
|
||||
assertion: {
|
||||
type: AssertionJSR223,
|
||||
default: () => {
|
||||
return new AssertionJSR223();
|
||||
}
|
||||
},
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
index: Number,
|
||||
list: Array,
|
||||
callback: Function,
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
operators: {
|
||||
EQ: {
|
||||
label: "commons.adv_search.operators.equals",
|
||||
value: "=="
|
||||
},
|
||||
NE: {
|
||||
label: "commons.adv_search.operators.not_equals",
|
||||
value: "!="
|
||||
},
|
||||
CONTAINS: {
|
||||
label: "commons.adv_search.operators.like",
|
||||
value: "contains"
|
||||
},
|
||||
NOT_CONTAINS: {
|
||||
label: "commons.adv_search.operators.not_like",
|
||||
value: "not contains"
|
||||
},
|
||||
GT: {
|
||||
label: "commons.adv_search.operators.gt",
|
||||
value: ">"
|
||||
},
|
||||
LT: {
|
||||
label: "commons.adv_search.operators.lt",
|
||||
value: "<"
|
||||
},
|
||||
IS_EMPTY: {
|
||||
label: "commons.adv_search.operators.is_empty",
|
||||
value: "is empty"
|
||||
},
|
||||
IS_NOT_EMPTY: {
|
||||
label: "commons.adv_search.operators.is_not_empty",
|
||||
value: "is not empty"
|
||||
}
|
||||
},
|
||||
templates: [
|
||||
{
|
||||
title: this.$t('api_test.request.assertions.set_failure_status'),
|
||||
value: 'AssertionResult.setFailure(true)',
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.request.assertions.set_failure_msg'),
|
||||
value: 'AssertionResult.setFailureMessage("msg")',
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
add() {
|
||||
this.list.push(new AssertionJSR223(this.assertion));
|
||||
this.callback();
|
||||
},
|
||||
remove() {
|
||||
this.list.splice(this.index, 1);
|
||||
},
|
||||
changeOperator(value) {
|
||||
if (value.indexOf("empty") > 0 && !!this.assertion.value) {
|
||||
this.assertion.value = "";
|
||||
}
|
||||
this.quickScript();
|
||||
},
|
||||
quickScript() {
|
||||
if (this.assertion.variable && this.assertion.operator) {
|
||||
let variable = this.assertion.variable;
|
||||
let operator = this.assertion.operator;
|
||||
let value = this.assertion.value || "";
|
||||
let desc = "${" + variable + "} " + operator + " '" + value + "'";
|
||||
let script = "value = vars.get(\"" + variable + "\");\n"
|
||||
switch (this.assertion.operator) {
|
||||
case "==":
|
||||
script += "result = \"" + value + "\".equals(value);\n";
|
||||
break;
|
||||
case "!=":
|
||||
script += "result = !\"" + value + "\".equals(value);\n";
|
||||
break;
|
||||
case "contains":
|
||||
script += "result = value.contains(\"" + value + "\");\n";
|
||||
break;
|
||||
case "not contains":
|
||||
script += "result = !value.contains(\"" + value + "\");\n";
|
||||
break;
|
||||
case ">":
|
||||
desc = "${" + variable + "} " + operator + " " + value;
|
||||
script += "number = Integer.parseInt(value);\n" +
|
||||
"result = number > " + value + ";\n";
|
||||
break;
|
||||
case "<":
|
||||
desc = "${" + variable + "} " + operator + " " + value;
|
||||
script += "number = Integer.parseInt(value);\n" +
|
||||
"result = number < " + value + ";\n";
|
||||
break;
|
||||
case "is empty":
|
||||
desc = "${" + variable + "} " + operator
|
||||
script += "result = value == void || value.length() == 0;\n";
|
||||
break;
|
||||
case "is not empty":
|
||||
desc = "${" + variable + "} " + operator
|
||||
script += "result = value != void && value.length() > 0;\n";
|
||||
break;
|
||||
}
|
||||
let msg = "assertion [" + desc + "]: false;"
|
||||
script += "if (!result){\n" +
|
||||
"\tmsg = \"" + msg + "\";\n" +
|
||||
"\tAssertionResult.setFailureMessage(msg);\n" +
|
||||
"\tAssertionResult.setFailure(true);\n" +
|
||||
"}";
|
||||
|
||||
this.assertion.desc = desc;
|
||||
this.assertion.script = script;
|
||||
this.$refs.jsr233.reload();
|
||||
}
|
||||
|
||||
},
|
||||
detail() {
|
||||
this.visible = true;
|
||||
},
|
||||
close() {
|
||||
this.visible = false;
|
||||
},
|
||||
confirm() {
|
||||
if (!this.edit) {
|
||||
this.add();
|
||||
}
|
||||
if (!this.assertion.desc) {
|
||||
this.assertion.desc = this.assertion.script;
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
hasEmptyOperator() {
|
||||
return !!this.assertion.operator && this.assertion.operator.indexOf("empty") > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.assertion-item {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.assertion-item + .assertion-item {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.assertion-item.input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.assertion-item.select {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.assertion-item.label {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.assertion-item.btn {
|
||||
min-width: 130px;
|
||||
}
|
||||
|
||||
.assertion-item.btn.circle {
|
||||
text-align: right;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.quick-script-block {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,72 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
|
||||
<el-col>
|
||||
<el-input :disabled="isReadOnly" v-model="xPath2.expression" maxlength="200" size="small" show-word-limit
|
||||
:placeholder="$t('api_test.request.extract.xpath_expression')"/>
|
||||
</el-col>
|
||||
<el-col class="assertion-btn">
|
||||
<el-button :disabled="isReadOnly" type="danger" size="mini" icon="el-icon-delete" circle @click="remove" v-if="edit"/>
|
||||
<el-button :disabled="isReadOnly" type="primary" size="small" @click="add" v-else>
|
||||
{{ $t('api_test.request.assertions.add') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {XPath2} from "../../model/ApiTestModel";
|
||||
|
||||
export default {
|
||||
name: "MsApiAssertionXPath2",
|
||||
|
||||
props: {
|
||||
xPath2: {
|
||||
type: XPath2,
|
||||
default: () => {
|
||||
return new XPath2();
|
||||
}
|
||||
},
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
index: Number,
|
||||
list: Array,
|
||||
callback: Function,
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
add: function () {
|
||||
this.list.push(this.getXPath2());
|
||||
this.callback();
|
||||
},
|
||||
remove: function () {
|
||||
this.list.splice(this.index, 1);
|
||||
},
|
||||
getXPath2() {
|
||||
return new XPath2(this.xPath2);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.assertion-select {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.assertion-item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.assertion-btn {
|
||||
text-align: center;
|
||||
width: 60px;
|
||||
}
|
||||
</style>
|
|
@ -1,47 +1,56 @@
|
|||
<template>
|
||||
<div class="assertion-add" style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 99% ;margin-top: 10px">
|
||||
<el-button class="ms-left-buttion" size="small" type="danger" plain>断言规则</el-button>
|
||||
<div class="assertion-add" style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 98%;">
|
||||
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin-top: 20px">
|
||||
<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="$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"/>
|
||||
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/>
|
||||
<el-option :label="$t('api_test.request.assertions.jsr223')" :value="options.JSR223"/>
|
||||
</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"
|
||||
<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"
|
||||
<ms-api-assertion-x-path2 :is-read-only="isReadOnly" :list="assertions.xpath2" v-if="type === options.XPATH2"
|
||||
: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>
|
||||
<ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223" v-if="type === options.JSR223"
|
||||
:callback="after"/>
|
||||
<el-button v-if="!type" :disabled="true" type="primary" size="small">
|
||||
{{ $t('api_test.request.assertions.add') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
||||
<!--<div v-if="!scenario">-->
|
||||
<!--<el-row :gutter="10" class="json-path-suggest-button">-->
|
||||
<!--<el-link size="small" type="primary" @click="suggestJsonOpen" style="margin-right: 20px">-->
|
||||
<!--{{ $t('api_test.request.assertions.json_path_suggest') }}-->
|
||||
<!--</el-link>-->
|
||||
<!--<el-link size="small" type="danger" @click="clearJson">-->
|
||||
<!--{{ $t('api_test.request.assertions.json_path_clear') }}-->
|
||||
<!--</el-link>-->
|
||||
<!--</el-row>-->
|
||||
<!--</div>-->
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-row :gutter="10" class="json-path-suggest-button">
|
||||
<el-link size="small" type="primary" @click="suggestJsonOpen">
|
||||
{{$t('api_test.request.assertions.json_path_suggest')}}
|
||||
</el-link>
|
||||
<el-link size="small" type="danger" @click="clearJson" style="margin-left: 20px">
|
||||
{{$t('api_test.request.assertions.json_path_clear')}}
|
||||
</el-link>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<ms-api-jsonpath-suggest-list @addJsonpathSuggest="addJsonpathSuggest" :request="assertions"
|
||||
ref="jsonpathSuggestList"/>
|
||||
<!--<ms-api-jsonpath-suggest-list @addJsonpathSuggest="addJsonpathSuggest" :request="request"-->
|
||||
<!--ref="jsonpathSuggestList"/>-->
|
||||
|
||||
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions"/>
|
||||
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions" style="margin-bottom: 20px"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -49,23 +58,28 @@
|
|||
import MsApiAssertionText from "./ApiAssertionText";
|
||||
import MsApiAssertionRegex from "./ApiAssertionRegex";
|
||||
import MsApiAssertionDuration from "./ApiAssertionDuration";
|
||||
import {ASSERTION_TYPE, Assertions, HttpRequest, JSONPath} from "../../model/ApiTestModel";
|
||||
import {ASSERTION_TYPE, Assertions, JSONPath, Scenario} from "../../model/ApiTestModel";
|
||||
import MsApiAssertionsEdit from "./ApiAssertionsEdit";
|
||||
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
|
||||
import MsApiAssertionJsr223 from "./ApiAssertionJsr223";
|
||||
import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList";
|
||||
import MsApiAssertionXPath2 from "./ApiAssertionXPath2";
|
||||
|
||||
export default {
|
||||
name: "MsApiAssertions",
|
||||
|
||||
components: {
|
||||
MsApiAssertionXPath2,
|
||||
MsApiAssertionJsr223,
|
||||
MsApiJsonpathSuggestList,
|
||||
MsApiAssertionJsonPath,
|
||||
MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText
|
||||
},
|
||||
|
||||
props: {
|
||||
assertions: {},
|
||||
assertions: Assertions,
|
||||
request: {},
|
||||
scenario: Scenario,
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
|
@ -115,7 +129,6 @@
|
|||
|
||||
.assertion-add {
|
||||
padding: 10px;
|
||||
border: #DCDFE6 solid 1px;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
@ -143,10 +156,8 @@
|
|||
}
|
||||
|
||||
.json-path-suggest-button {
|
||||
text-align: left;
|
||||
margin-left: 20px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -25,10 +25,6 @@
|
|||
{{ $t('api_test.definition.request.body_binary') }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<!--
|
||||
<ms-dropdown :default-command="body.format" v-if="body.type == 'Raw'" :commands="modes" @command="modeChange"/>
|
||||
-->
|
||||
<ms-api-variable :is-read-only="isReadOnly"
|
||||
:parameters="body.kvs"
|
||||
:isShowEnable="isShowEnable"
|
||||
|
@ -64,7 +60,7 @@
|
|||
|
||||
<script>
|
||||
import MsApiKeyValue from "../ApiKeyValue";
|
||||
import {Body, BODY_FORMAT, BODY_TYPE, KeyValue, Scenario} from "../../model/ApiTestModel";
|
||||
import {BODY_FORMAT, BODY_TYPE, KeyValue} from "../../model/ApiTestModel";
|
||||
import MsCodeEdit from "../../../../common/components/MsCodeEdit";
|
||||
import MsJsonCodeEdit from "../../../../common/components/MsJsonCodeEdit";
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {boolProp, elementProp, stringProp} from "../../../props";
|
||||
import Sampler from "../sampler";
|
||||
import {BaseConfig, BODY_TYPE, KeyValue, Body} from "../../../../../model/ApiTestModel";
|
||||
|
||||
import {Body} from "../../../../../model/ApiTestModel";
|
||||
const DEFAULT_OPTIONS = {
|
||||
options: {
|
||||
attributes: {
|
||||
|
@ -32,8 +31,7 @@ export default class HTTPSamplerProxy extends Sampler {
|
|||
this.embeddedUrlRe = this.initStringProp('HTTPSampler.embedded_url_re');
|
||||
this.connectTimeout = this.initStringProp('HTTPSampler.connect_timeout');
|
||||
this.responseTimeout = this.initStringProp('HTTPSampler.response_timeout');
|
||||
// 初始化认证对象 和主体对象
|
||||
this.authConfig = {};
|
||||
// 初始化主体对象
|
||||
this.body = new Body();
|
||||
|
||||
this.arguments = [];
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<el-col :span="21">
|
||||
<!-- HTTP 请求参数 -->
|
||||
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100%">
|
||||
<el-tabs v-model="activeName" style="margin: 20px">
|
||||
<el-tabs v-model="activeName" style="margin: 20px;min-height: 200px">
|
||||
<!-- 请求头-->
|
||||
<el-tab-pane :label="$t('api_test.request.headers')" name="headers">
|
||||
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.request.headers')" placement="top-start" slot="label">
|
||||
|
@ -46,6 +46,7 @@
|
|||
<el-tab-pane :label="$t('api_test.request.body')" name="body">
|
||||
<ms-api-body :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :headers="headers" :body="request.body"/>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 认证配置 -->
|
||||
<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">
|
||||
|
@ -65,11 +66,13 @@
|
|||
<ms-jsr233-processor v-if="row.label ==='JSR223 PostProcessor'" @remove="remove" :is-read-only="false" title="后置脚本" style-type="success"
|
||||
:jsr223-processor="row"/>
|
||||
|
||||
<!--<ms-api-assertions v-if="row.label.indexOf('Assertion')>0" :is-read-only="isReadOnly" :request="request"/>-->
|
||||
|
||||
<!--<ms-api-extract :is-read-only="isReadOnly" v-if="row.label==='JSONPostProcessor'" :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">
|
||||
|
@ -77,9 +80,9 @@
|
|||
<br/>
|
||||
<el-button class="ms-left-buttion" size="small" type="success" @click="addPost" plain>+后置脚本</el-button>
|
||||
<br/>
|
||||
<!--<el-button class="ms-left-buttion" size="small" type="danger" @click="addAssertions" plain>+断言规则</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="danger" @click="addAssertions" plain>+断言规则</el-button>
|
||||
<br/>
|
||||
<el-button class="ms-left-buttion" size="small" type="info" @click="addExtract" plain>+提取参数</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
@ -96,6 +99,7 @@
|
|||
import {createComponent} from "../jmeter/components";
|
||||
import MsApiAssertions from "../assertion/ApiAssertions";
|
||||
import MsApiExtract from "../extract/ApiExtract";
|
||||
import {Assertions} from "../../model/ApiTestModel";
|
||||
|
||||
export default {
|
||||
name: "MsApiHttpRequestForm",
|
||||
|
@ -139,9 +143,17 @@
|
|||
},
|
||||
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");
|
||||
|
@ -154,8 +166,9 @@
|
|||
this.reload();
|
||||
},
|
||||
addAssertions() {
|
||||
let jsonPathAssertion = createComponent("JSONPathAssertion");
|
||||
this.request.hashTree.push(jsonPathAssertion);
|
||||
//let jsonPathAssertion = createComponent("JSONPathAssertion");
|
||||
let assertions = new Assertions();
|
||||
this.request.hashTree.push(assertions);
|
||||
this.reload();
|
||||
},
|
||||
addExtract() {
|
||||
|
|
|
@ -5,13 +5,10 @@
|
|||
<el-collapse-transition>
|
||||
<el-tabs v-model="activeName" v-show="isActive" style="margin: 20px">
|
||||
<el-tab-pane :label="$t('api_test.definition.request.response_header')" name="headers" class="pane">
|
||||
<ms-api-key-value :isShowEnable="false" :suggestions="headerSuggestions"
|
||||
:items="response.headers"/>
|
||||
<ms-api-key-value :isShowEnable="false" :suggestions="headerSuggestions" :items="response.headers"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('api_test.definition.request.response_body')" name="body" class="pane">
|
||||
<ms-api-body
|
||||
:body="response.body"
|
||||
:extract="response.extract"/>
|
||||
<ms-api-body :isShowEnable="false" :body="response.body" :headers="response.headers"/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane :label="$t('api_test.definition.request.status_code')" name="status_code" class="pane">
|
||||
|
|
|
@ -98,7 +98,9 @@ export const ASSERTION_TYPE = {
|
|||
TEXT: "Text",
|
||||
REGEX: "Regex",
|
||||
JSON_PATH: "JSON",
|
||||
DURATION: "Duration"
|
||||
DURATION: "Duration",
|
||||
JSR223: "JSR223",
|
||||
XPATH2: "XPath2",
|
||||
}
|
||||
|
||||
export const ASSERTION_REGEX_SUBJECT = {
|
||||
|
@ -759,13 +761,16 @@ export class KeyValue extends BaseConfig {
|
|||
export class Assertions extends BaseConfig {
|
||||
constructor(options) {
|
||||
super();
|
||||
this.type = "Assertions";
|
||||
this.text = [];
|
||||
this.regex = [];
|
||||
this.jsonPath = [];
|
||||
this.jsr223 = [];
|
||||
this.xpath2 = [];
|
||||
this.duration = undefined;
|
||||
|
||||
this.set(options);
|
||||
this.sets({text: Text, regex: Regex, jsonPath: JSONPath}, options);
|
||||
this.sets({text: Text, regex: Regex, jsonPath: JSONPath, jsr223: AssertionJSR223, xpath2: XPath2}, options);
|
||||
}
|
||||
|
||||
initOptions(options) {
|
||||
|
@ -782,6 +787,37 @@ export class AssertionType extends BaseConfig {
|
|||
}
|
||||
}
|
||||
|
||||
export class AssertionJSR223 extends AssertionType {
|
||||
constructor(options) {
|
||||
super(ASSERTION_TYPE.JSR223);
|
||||
this.variable = undefined;
|
||||
this.operator = undefined;
|
||||
this.value = undefined;
|
||||
this.desc = undefined;
|
||||
|
||||
this.name = undefined;
|
||||
this.script = undefined;
|
||||
this.language = "beanshell";
|
||||
this.set(options);
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return !!this.script && !!this.language;
|
||||
}
|
||||
}
|
||||
|
||||
export class Text extends AssertionType {
|
||||
constructor(options) {
|
||||
super(ASSERTION_TYPE.TEXT);
|
||||
this.subject = undefined;
|
||||
this.condition = undefined;
|
||||
this.value = undefined;
|
||||
|
||||
this.set(options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class BeanShellProcessor extends BaseConfig {
|
||||
constructor(options) {
|
||||
super();
|
||||
|
@ -800,17 +836,6 @@ export class JSR223Processor extends BaseConfig {
|
|||
}
|
||||
}
|
||||
|
||||
export class Text extends AssertionType {
|
||||
constructor(options) {
|
||||
super(ASSERTION_TYPE.TEXT);
|
||||
this.subject = undefined;
|
||||
this.condition = undefined;
|
||||
this.value = undefined;
|
||||
|
||||
this.set(options);
|
||||
}
|
||||
}
|
||||
|
||||
export class Regex extends AssertionType {
|
||||
constructor(options) {
|
||||
super(ASSERTION_TYPE.REGEX);
|
||||
|
@ -846,6 +871,20 @@ export class JSONPath extends AssertionType {
|
|||
}
|
||||
}
|
||||
|
||||
export class XPath2 extends AssertionType {
|
||||
constructor(options) {
|
||||
super(ASSERTION_TYPE.XPATH2);
|
||||
this.expression = undefined;
|
||||
this.description = undefined;
|
||||
this.set(options);
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return !!this.expression;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class Duration extends AssertionType {
|
||||
constructor(options) {
|
||||
super(ASSERTION_TYPE.DURATION);
|
||||
|
|
Loading…
Reference in New Issue