This commit is contained in:
chenjianxing 2020-10-28 17:34:26 +08:00
commit 0dbf3b943d
17 changed files with 2050 additions and 1669 deletions

View File

@ -0,0 +1,20 @@
package io.metersphere.api.dto.scenario.assertions;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class AssertionJSR223 extends AssertionType {
private String variable;
private String operator;
private String value;
private String desc;
private String name;
private String script;
private String language;
public AssertionJSR223() {
setType(AssertionType.JSR223);
}
}

View File

@ -7,6 +7,7 @@ public class AssertionType {
public final static String REGEX = "Regex"; public final static String REGEX = "Regex";
public final static String DURATION = "Duration"; public final static String DURATION = "Duration";
public final static String JSON_PATH = "JSONPath"; public final static String JSON_PATH = "JSONPath";
public final static String JSR223 = "JSR223";
public final static String TEXT = "Text"; public final static String TEXT = "Text";
private String type; private String type;

View File

@ -8,5 +8,6 @@ import java.util.List;
public class Assertions { public class Assertions {
private List<AssertionRegex> regex; private List<AssertionRegex> regex;
private List<AssertionJsonPath> jsonPath; private List<AssertionJsonPath> jsonPath;
private List<AssertionJSR223> jsr223;
private AssertionDuration duration; private AssertionDuration duration;
} }

View File

@ -7,7 +7,9 @@
</el-col> </el-col>
<el-col class="assertion-btn"> <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="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>Add</el-button> <el-button :disabled="isReadOnly" type="primary" size="small" @click="add" v-else>
{{ $t('api_test.request.assertions.add') }}
</el-button>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>

View File

@ -11,7 +11,9 @@
</el-col> </el-col>
<el-col class="assertion-btn"> <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="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>Add</el-button> <el-button :disabled="isReadOnly" type="primary" size="small" @click="add" v-else>
{{ $t('api_test.request.assertions.add') }}
</el-button>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>

View File

@ -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/ScenarioModel";
import MsJsr233Processor from "@/business/components/api/test/components/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>

View File

@ -21,7 +21,9 @@
<el-col class="assertion-btn"> <el-col class="assertion-btn">
<el-button :disabled="isReadOnly" type="danger" size="mini" icon="el-icon-delete" circle @click="remove" <el-button :disabled="isReadOnly" type="danger" size="mini" icon="el-icon-delete" circle @click="remove"
v-if="edit"/> v-if="edit"/>
<el-button :disabled="isReadOnly" type="primary" size="small" @click="add" v-else>Add</el-button> <el-button :disabled="isReadOnly" type="primary" size="small" @click="add" v-else>
{{ $t('api_test.request.assertions.add') }}
</el-button>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>

View File

@ -29,7 +29,9 @@
</el-checkbox> </el-checkbox>
</el-col> </el-col>
<el-col class="assertion-btn"> <el-col class="assertion-btn">
<el-button :disabled="isReadOnly" type="primary" size="small" @click="add">Add</el-button> <el-button :disabled="isReadOnly" type="primary" size="small" @click="add">
{{ $t('api_test.request.assertions.add') }}
</el-button>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>

View File

@ -9,6 +9,7 @@
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/> <el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
<el-option :label="'JSONPath'" :value="options.JSON_PATH"/> <el-option :label="'JSONPath'" :value="options.JSON_PATH"/>
<el-option :label="$t('api_test.request.assertions.response_time')" :value="options.DURATION"/> <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-select>
</el-col> </el-col>
<el-col :span="20"> <el-col :span="20">
@ -17,7 +18,10 @@
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath" v-if="type === options.JSON_PATH" :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" <ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
v-if="type === options.DURATION" :callback="after"/> 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-col>
</el-row> </el-row>
</div> </div>
@ -46,12 +50,14 @@
import {ASSERTION_TYPE, Assertions, HttpRequest, JSONPath} from "../../model/ScenarioModel"; import {ASSERTION_TYPE, Assertions, HttpRequest, JSONPath} from "../../model/ScenarioModel";
import MsApiAssertionsEdit from "./ApiAssertionsEdit"; import MsApiAssertionsEdit from "./ApiAssertionsEdit";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath"; import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList"; import MsApiJsonpathSuggestList from "./ApiJsonpathSuggestList";
export default { export default {
name: "MsApiAssertions", name: "MsApiAssertions",
components: { components: {
MsApiAssertionJsr223,
MsApiJsonpathSuggestList, MsApiJsonpathSuggestList,
MsApiAssertionJsonPath, MsApiAssertionJsonPath,
MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText}, MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText},

View File

@ -2,42 +2,56 @@
<div> <div>
<div class="assertion-item-editing regex" v-if="assertions.regex.length > 0"> <div class="assertion-item-editing regex" v-if="assertions.regex.length > 0">
<div> <div>
{{$t("api_test.request.assertions.regex")}} {{ $t("api_test.request.assertions.regex") }}
</div> </div>
<div class="regex-item" v-for="(regex, index) in assertions.regex" :key="index"> <div class="regex-item" v-for="(regex, index) in assertions.regex" :key="index">
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" :regex="regex" :edit="true" :index="index"/> <ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex"
:regex="regex" :edit="true" :index="index"/>
</div> </div>
</div> </div>
<div class="assertion-item-editing json_path" v-if="assertions.jsonPath.length > 0"> <div class="assertion-item-editing json_path" v-if="assertions.jsonPath.length > 0">
<div> <div>
{{'JSONPath'}} {{ 'JSONPath' }}
</div> </div>
<div class="regex-item" v-for="(jsonPath, index) in assertions.jsonPath" :key="index"> <div class="regex-item" v-for="(jsonPath, index) in assertions.jsonPath" :key="index">
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath" :json-path="jsonPath" :edit="true" :index="index"/> <ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath"
:json-path="jsonPath" :edit="true" :index="index"/>
</div>
</div>
<div class="assertion-item-editing jsr223" v-if="assertions.jsr223.length > 0">
<div>
{{ $t("api_test.request.assertions.script") }}
</div>
<div class="regex-item" v-for="(assertion, index) in assertions.jsr223" :key="index">
<ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223"
:assertion="assertion" :edit="true" :index="index"/>
</div> </div>
</div> </div>
<div class="assertion-item-editing response-time" v-if="isShow"> <div class="assertion-item-editing response-time" v-if="isShow">
<div> <div>
{{$t("api_test.request.assertions.response_time")}} {{ $t("api_test.request.assertions.response_time") }}
</div> </div>
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="assertions.duration.value" :duration="assertions.duration" :edit="true"/> <ms-api-assertion-duration :is-read-only="isReadOnly" v-model="assertions.duration.value"
:duration="assertions.duration" :edit="true"/>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import MsApiAssertionRegex from "./ApiAssertionRegex"; import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionDuration from "./ApiAssertionDuration"; import MsApiAssertionDuration from "./ApiAssertionDuration";
import {Assertions} from "../../model/ScenarioModel"; import {Assertions} from "../../model/ScenarioModel";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath"; import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
export default { export default {
name: "MsApiAssertionsEdit", name: "MsApiAssertionsEdit",
components: {MsApiAssertionJsonPath, MsApiAssertionDuration, MsApiAssertionRegex}, components: {MsApiAssertionJsr223, MsApiAssertionJsonPath, MsApiAssertionDuration, MsApiAssertionRegex},
props: { props: {
assertions: Assertions, assertions: Assertions,
@ -53,30 +67,34 @@
return rt.value !== undefined; return rt.value !== undefined;
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
.assertion-item-editing { .assertion-item-editing {
padding-left: 10px; padding-left: 10px;
margin-top: 10px; margin-top: 10px;
} }
.assertion-item-editing.regex { .assertion-item-editing.regex {
border-left: 2px solid #7B0274; border-left: 2px solid #7B0274;
} }
.assertion-item-editing.json_path { .assertion-item-editing.json_path {
border-left: 2px solid #44B3D2; border-left: 2px solid #44B3D2;
} }
.assertion-item-editing.response-time { .assertion-item-editing.response-time {
border-left: 2px solid #DD0240; border-left: 2px solid #DD0240;
} }
.regex-item { .assertion-item-editing.jsr223 {
border-left: 2px solid #1FDD02;
}
.regex-item {
margin-top: 10px; margin-top: 10px;
} }
</style> </style>

View File

@ -1,17 +1,21 @@
<template> <template>
<div > <div>
<el-row> <el-row>
<el-col :span="20" class="script-content"> <el-col :span="20">
<ms-code-edit v-if="isCodeEditAlive" :mode="codeEditModeMap[jsr223Processor.language]" :read-only="isReadOnly" :data.sync="jsr223Processor.script" theme="eclipse" :modes="['java','python']" ref="codeEdit"/> <ms-code-edit v-if="isCodeEditAlive" :mode="codeEditModeMap[jsr223Processor.language]" :read-only="isReadOnly"
:data.sync="jsr223Processor.script" theme="eclipse" :modes="['java','python']" ref="codeEdit"
:height="height"/>
</el-col> </el-col>
<el-col :span="4" class="script-index"> <el-col :span="4" class="script-index">
<ms-dropdown :default-command="jsr223Processor.language" :commands="languages" @command="languageChange"/> <ms-dropdown :default-command="jsr223Processor.language" :commands="languages" @command="languageChange"/>
<div class="template-title">{{$t('api_test.request.processor.code_template')}}</div> <div class="template-title">{{ $t('api_test.request.processor.code_template') }}</div>
<div v-for="(template, index) in codeTemplates" :key="index" class="code-template"> <div v-for="(template, index) in codeTemplates" :key="index" class="code-template">
<el-link :disabled="template.disabled" @click="addTemplate(template)">{{template.title}}</el-link> <el-link :disabled="template.disabled" @click="addTemplate(template)">{{ template.title }}</el-link>
</div> </div>
<div class="document-url"> <div class="document-url">
<el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor" type="primary">{{$t('commons.reference_documentation')}}</el-link> <el-link href="https://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PostProcessor"
type="primary">{{ $t('commons.reference_documentation') }}
</el-link>
<ms-instructions-icon :content="$t('api_test.request.processor.bean_shell_processor_tip')"/> <ms-instructions-icon :content="$t('api_test.request.processor.bean_shell_processor_tip')"/>
</div> </div>
</el-col> </el-col>
@ -20,15 +24,37 @@
</template> </template>
<script> <script>
import MsCodeEdit from "../../../../common/components/MsCodeEdit"; import MsCodeEdit from "../../../../common/components/MsCodeEdit";
import MsInstructionsIcon from "../../../../common/components/MsInstructionsIcon"; import MsInstructionsIcon from "../../../../common/components/MsInstructionsIcon";
import MsDropdown from "../../../../common/components/MsDropdown"; import MsDropdown from "../../../../common/components/MsDropdown";
export default {
export default {
name: "MsJsr233Processor", name: "MsJsr233Processor",
components: {MsDropdown, MsInstructionsIcon, MsCodeEdit}, components: {MsDropdown, MsInstructionsIcon, MsCodeEdit},
props: {
type: {
type: String,
},
isReadOnly: {
type: Boolean,
default: false
},
jsr223Processor: {
type: Object,
},
isPreProcessor: {
type: Boolean,
default: false
},
templates: {
type: Array,
default: () => []
},
height: {
type: [String, Number],
default: 230
}
},
data() { data() {
return { return {
codeTemplates: [ codeTemplates: [
@ -62,11 +88,12 @@
title: this.$t('api_test.request.processor.code_template_get_response_result'), title: this.$t('api_test.request.processor.code_template_get_response_result'),
value: 'prev.getResponseDataAsString()', value: 'prev.getResponseDataAsString()',
disabled: this.isPreProcessor disabled: this.isPreProcessor
} },
...this.templates
], ],
isCodeEditAlive: true, isCodeEditAlive: true,
languages: [ languages: [
'beanshell',"python" 'beanshell', "python"
], ],
codeEditModeMap: { codeEditModeMap: {
beanshell: 'java', beanshell: 'java',
@ -74,22 +101,6 @@
} }
} }
}, },
props: {
type: {
type: String,
},
isReadOnly: {
type: Boolean,
default: false
},
jsr223Processor: {
type: Object,
},
isPreProcessor: {
type: Boolean,
default: false
}
},
watch: { watch: {
jsr223Processor() { jsr223Processor() {
this.reload(); this.reload();
@ -114,39 +125,35 @@
this.jsr223Processor.language = language; this.jsr223Processor.language = language;
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
.ace_editor { .ace_editor {
border-radius: 5px; border-radius: 5px;
} }
.script-content { .script-index {
height: calc(100vh - 570px);
}
.script-index {
padding: 0 20px; padding: 0 20px;
} }
.template-title { .template-title {
margin-bottom: 5px; margin-bottom: 5px;
font-weight: bold; font-weight: bold;
font-size: 15px; font-size: 15px;
} }
.document-url { .document-url {
margin-top: 10px; margin-top: 10px;
} }
.instructions-icon { .instructions-icon {
margin-left: 5px; margin-left: 5px;
} }
.ms-dropdown { .ms-dropdown {
margin-bottom: 20px; margin-bottom: 20px;
} }
</style> </style>

View File

@ -501,6 +501,12 @@ export class JSR223Processor extends DefaultTestElement {
} }
} }
export class JSR223Assertion extends JSR223Processor {
constructor(testName, processor) {
super('JSR223Assertion', 'TestBeanGUI', 'JSR223Assertion', testName, processor)
}
}
export class JSR223PreProcessor extends JSR223Processor { export class JSR223PreProcessor extends JSR223Processor {
constructor(testName, processor) { constructor(testName, processor) {
super('JSR223PreProcessor', 'TestBeanGUI', 'JSR223PreProcessor', testName, processor) super('JSR223PreProcessor', 'TestBeanGUI', 'JSR223PreProcessor', testName, processor)

View File

@ -25,7 +25,7 @@ import {
ThreadGroup, ThreadGroup,
XPath2Extractor, XPath2Extractor,
IfController as JMXIfController, IfController as JMXIfController,
ConstantTimer as JMXConstantTimer, TCPSampler, ConstantTimer as JMXConstantTimer, TCPSampler, JSR223Assertion,
} from "./JMX"; } from "./JMX";
import Mock from "mockjs"; import Mock from "mockjs";
import {funcFilters} from "@/common/js/func-filter"; import {funcFilters} from "@/common/js/func-filter";
@ -94,7 +94,8 @@ export const ASSERTION_TYPE = {
TEXT: "Text", TEXT: "Text",
REGEX: "Regex", REGEX: "Regex",
JSON_PATH: "JSON", JSON_PATH: "JSON",
DURATION: "Duration" DURATION: "Duration",
JSR223: "JSR223",
} }
export const ASSERTION_REGEX_SUBJECT = { export const ASSERTION_REGEX_SUBJECT = {
@ -716,16 +717,34 @@ export class KeyValue extends BaseConfig {
} }
} }
export class BeanShellProcessor extends BaseConfig {
constructor(options) {
super();
this.script = undefined;
this.set(options);
}
}
export class JSR223Processor extends BaseConfig {
constructor(options) {
super();
this.script = undefined;
this.language = "beanshell";
this.set(options);
}
}
export class Assertions extends BaseConfig { export class Assertions extends BaseConfig {
constructor(options) { constructor(options) {
super(); super();
this.text = []; this.text = [];
this.regex = []; this.regex = [];
this.jsonPath = []; this.jsonPath = [];
this.jsr223 = [];
this.duration = undefined; this.duration = undefined;
this.set(options); this.set(options);
this.sets({text: Text, regex: Regex, jsonPath: JSONPath}, options); this.sets({text: Text, regex: Regex, jsonPath: JSONPath, jsr223: AssertionJSR223}, options);
} }
initOptions(options) { initOptions(options) {
@ -742,22 +761,23 @@ export class AssertionType extends BaseConfig {
} }
} }
export class BeanShellProcessor extends BaseConfig { export class AssertionJSR223 extends AssertionType {
constructor(options) { constructor(options) {
super(); super(ASSERTION_TYPE.JSR223);
this.script = undefined; this.variable = undefined;
this.set(options); this.operator = undefined;
} this.value = undefined;
} this.desc = undefined;
this.name = undefined;
export class JSR223Processor extends BaseConfig {
constructor(options) {
super();
this.script = undefined; this.script = undefined;
this.language = "beanshell"; this.language = "beanshell";
this.set(options); this.set(options);
} }
isValid() {
return !!this.script && !!this.language;
}
} }
export class Text extends AssertionType { export class Text extends AssertionType {
@ -1406,6 +1426,12 @@ class JMXGenerator {
}) })
} }
if (assertions.jsr223.length > 0) {
assertions.jsr223.filter(this.filter).forEach(item => {
httpSamplerProxy.put(this.getJSR223Assertion(item));
})
}
if (assertions.duration.isValid()) { if (assertions.duration.isValid()) {
let name = "Response In Time: " + assertions.duration.value let name = "Response In Time: " + assertions.duration.value
httpSamplerProxy.put(new DurationAssertion(name, assertions.duration.value)); httpSamplerProxy.put(new DurationAssertion(name, assertions.duration.value));
@ -1417,6 +1443,11 @@ class JMXGenerator {
return new JSONPathAssertion(name, jsonPath); return new JSONPathAssertion(name, jsonPath);
} }
getJSR223Assertion(item) {
let name = item.desc;
return new JSR223Assertion(name, item);
}
getResponseAssertion(regex) { getResponseAssertion(regex) {
let name = regex.description; let name = regex.description;
let type = JMX_ASSERTION_CONDITION.CONTAINS; // 固定用Match自己写正则 let type = JMX_ASSERTION_CONDITION.CONTAINS; // 固定用Match自己写正则

View File

@ -1,5 +1,5 @@
<template> <template>
<editor v-model="formatData" :lang="mode" @init="editorInit" :theme="theme"/> <editor v-model="formatData" :lang="mode" @init="editorInit" :theme="theme" :height="height"/>
</template> </template>
<script> <script>
@ -12,6 +12,7 @@
} }
}, },
props: { props: {
height: [String, Number],
data: { data: {
type: String type: String
}, },

View File

@ -1,6 +1,6 @@
export default { export default {
commons: { commons: {
comment:'comment', comment: 'comment',
examples: 'examples', examples: 'examples',
help_documentation: 'Help documentation', help_documentation: 'Help documentation',
delete_cancelled: 'Delete cancelled', delete_cancelled: 'Delete cancelled',
@ -216,8 +216,8 @@ export default {
select: 'Select Organization', select: 'Select Organization',
service_integration: 'Service integration', service_integration: 'Service integration',
defect_manage: 'Defect management platform', defect_manage: 'Defect management platform',
message_settings:'Message settings', message_settings: 'Message settings',
message:{ message: {
jenkins_task_notification: 'Jenkins task notification', jenkins_task_notification: 'Jenkins task notification',
test_plan_task_notification: 'Test plan task notification', test_plan_task_notification: 'Test plan task notification',
test_review_task_notice: 'Test review task notice', test_review_task_notice: 'Test review task notice',
@ -558,6 +558,12 @@ export default {
expression: "Expression", expression: "Expression",
response_in_time: "Response in time", response_in_time: "Response in time",
ignore_status: "Ignore Status", ignore_status: "Ignore Status",
add: "Add",
script_name: "Script name",
script: "Script",
variable_name: "Variable name",
set_failure_status: "Set failure status",
set_failure_msg: "Set failure message",
json_path_add: "Add JONPATH Assertions", json_path_add: "Add JONPATH Assertions",
json_path_err: "The response result is not in JSON format", json_path_err: "The response result is not in JSON format",
json_path_suggest: "JSONPath Assertion Suggest", json_path_suggest: "JSONPath Assertion Suggest",

View File

@ -1,6 +1,6 @@
export default { export default {
commons: { commons: {
comment:'评论', comment: '评论',
examples: '示例', examples: '示例',
help_documentation: '帮助文档', help_documentation: '帮助文档',
delete_cancelled: '已取消删除', delete_cancelled: '已取消删除',
@ -217,8 +217,8 @@ export default {
delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?',
service_integration: '服务集成', service_integration: '服务集成',
defect_manage: '缺陷管理平台', defect_manage: '缺陷管理平台',
message_settings:'消息设置', message_settings: '消息设置',
message:{ message: {
jenkins_task_notification: 'Jenkins接口调用任务通知', jenkins_task_notification: 'Jenkins接口调用任务通知',
test_plan_task_notification: '测试计划任务通知', test_plan_task_notification: '测试计划任务通知',
test_review_task_notice: '测试评审任务通知', test_review_task_notice: '测试评审任务通知',
@ -545,6 +545,7 @@ export default {
text: "文本", text: "文本",
regex: "正则", regex: "正则",
response_time: "响应时间", response_time: "响应时间",
jsr223: "脚本",
select_type: "请选择类型", select_type: "请选择类型",
select_subject: "请选择对象", select_subject: "请选择对象",
select_condition: "请选择条件", select_condition: "请选择条件",
@ -562,6 +563,13 @@ export default {
json_path_suggest: "推荐JSONPath断言", json_path_suggest: "推荐JSONPath断言",
json_path_clear: "清空JSONPath断言", json_path_clear: "清空JSONPath断言",
debug_first: "请先执行调试获取响应结果", debug_first: "请先执行调试获取响应结果",
ignore_status: "忽略状态",
add: "添加",
script_name: "脚本名称",
script: "脚本",
variable_name: "变量名称",
set_failure_status: "设置失败状态",
set_failure_msg: "设置失败消息",
}, },
extract: { extract: {
label: "提取", label: "提取",

View File

@ -562,6 +562,13 @@ export default {
json_path_suggest: "推薦JSONPath斷言", json_path_suggest: "推薦JSONPath斷言",
json_path_clear: "清空JSONPath斷言", json_path_clear: "清空JSONPath斷言",
debug_first: "請先執行調試獲取響應結果", debug_first: "請先執行調試獲取響應結果",
ignore_status: "忽略狀態",
add: "添加",
script_name: "腳本名稱",
script: "腳本",
variable_name: "變量名稱",
set_failure_status: "設置失敗狀態",
set_failure_msg: "設置失敗消息",
}, },
extract: { extract: {
label: "提取", label: "提取",