场景公用变量和Header

This commit is contained in:
q4speed 2020-05-13 12:59:41 +08:00
parent 62bf729e8c
commit 709c207fcc
12 changed files with 234 additions and 40 deletions

View File

@ -6,10 +6,12 @@
<div class="kv-row" v-for="(item, index) in items" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col>
<el-input v-model="item.name" placeholder="Key" size="small" maxlength="100" @change="change"/>
<el-input v-model="item.name" size="small" maxlength="100" @change="change"
:placeholder="$t('api_test.key')"/>
</el-col>
<el-col>
<el-input v-model="item.value" placeholder="Value" size="small" maxlength="100" @change="change"/>
<el-input v-model="item.value" size="small" maxlength="100" @change="change"
:placeholder="$t('api_test.value')"/>
</el-col>
<el-col class="kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"

View File

@ -39,8 +39,8 @@
<script>
import MsApiCollapseItem from "./ApiCollapseItem";
import MsApiCollapse from "./ApiCollapse";
import MsApiCollapseItem from "./collapse/ApiCollapseItem";
import MsApiCollapse from "./collapse/ApiCollapse";
import MsApiRequestConfig from "./ApiRequestConfig";
import MsApiRequestForm from "./ApiRequestForm";
import MsApiScenarioForm from "./ApiScenarioForm";

View File

@ -8,24 +8,25 @@
<!-- <el-input :placeholder="$t('api_test.scenario.base_url_description')" v-model="scenario.url" maxlength="100"/>-->
<!-- </el-form-item>-->
<!-- <el-tabs v-model="activeName">-->
<!-- <el-tab-pane :label="$t('api_test.scenario.parameters')" name="parameters">-->
<!-- <ms-api-key-value :items="scenario.parameters" :description="$t('api_test.scenario.kv_description')"/>-->
<!-- </el-tab-pane>-->
<!-- <el-tab-pane :label="$t('api_test.scenario.headers')" name="headers">-->
<!-- <ms-api-key-value :items="scenario.headers" :description="$t('api_test.scenario.kv_description')"/>-->
<!-- </el-tab-pane>-->
<!-- </el-tabs>-->
<el-tabs v-model="activeName">
<el-tab-pane :label="$t('api_test.scenario.variables')" name="parameters">
<ms-api-scenario-variables :items="scenario.variables" :description="$t('api_test.scenario.kv_description')"/>
</el-tab-pane>
<el-tab-pane :label="$t('api_test.scenario.headers')" name="headers">
<ms-api-key-value :items="scenario.headers" :description="$t('api_test.scenario.kv_description')"/>
</el-tab-pane>
</el-tabs>
</el-form>
</template>
<script>
import MsApiKeyValue from "./ApiKeyValue";
import {Scenario} from "../model/ScenarioModel";
import MsApiScenarioVariables from "./ApiScenarioVariables";
export default {
name: "MsApiScenarioForm",
components: {MsApiKeyValue},
components: {MsApiScenarioVariables, MsApiKeyValue},
props: {
scenario: Scenario
},

View File

@ -0,0 +1,86 @@
<template>
<div>
<span class="kv-description" v-if="description">
{{description}}
</span>
<div class="kv-row" v-for="(item, index) in items" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col>
<ms-api-variable-input v-model="item.name" size="small" maxlength="100" @change="change"
:placeholder="$t('api_test.variable_name')"/>
</el-col>
<el-col>
<el-input v-model="item.value" size="small" maxlength="100" @change="change"
:placeholder="$t('api_test.value')"/>
</el-col>
<el-col class="kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
:disabled="isDisable(index)"/>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import {KeyValue} from "../model/ScenarioModel";
import MsApiVariableInput from "./ApiVariableInput";
export default {
name: "MsApiScenarioVariables",
components: {MsApiVariableInput},
props: {
description: String,
items: Array
},
methods: {
remove: function (index) {
this.items.splice(index, 1);
this.$emit('change', this.items);
},
change: function () {
let isNeedCreate = true;
let removeIndex = -1;
this.items.forEach((item, index) => {
if (!item.name && !item.value) {
//
if (index !== this.items.length - 1) {
removeIndex = index;
}
//
isNeedCreate = false;
}
});
if (isNeedCreate) {
this.items.push(new KeyValue());
}
this.$emit('change', this.items);
// TODO key
},
isDisable: function (index) {
return this.items.length - 1 === index;
}
},
created() {
if (this.items.length === 0) {
this.items.push(new KeyValue());
}
}
}
</script>
<style scoped>
.kv-description {
font-size: 13px;
}
.kv-row {
margin-top: 10px;
}
.kv-delete {
width: 60px;
}
</style>

View File

@ -0,0 +1,89 @@
<template>
<div class="variable-input">
<el-input :value="value" v-bind="$attrs" :size="size" @change="change" @input="input"/>
<div class="variable-combine" v-if="value">
<div class="variable">{{variable}}</div>
<el-tooltip :content="$t('api_test.copied')" manual v-model="visible" placement="top" :visible-arrow="false">
<i class="el-icon-copy-document copy" @click="copy"/>
</el-tooltip>
</div>
</div>
</template>
<script>
export default {
name: "MsApiVariableInput",
props: ['value', 'size'],
data() {
return {
visible: false
}
},
methods: {
copy() {
let input = document.createElement("input");
document.body.appendChild(input);
input.value = this.variable;
input.select();
if (input.setSelectionRange) {
input.setSelectionRange(0, input.value.length);
}
document.execCommand("copy");
document.body.removeChild(input);
this.visible = true;
setTimeout(() => {
this.visible = false;
}, 1000);
},
change(value) {
this.$emit('change', value);
},
input(value) {
this.$emit('input', value);
}
},
computed: {
variable() {
return "${" + this.value + "}";
}
}
}
</script>
<style scoped>
.variable-input {
position: relative;
}
.variable-combine {
color: #7F7F7F;
max-width: 80px;
line-height: 32px;
position: absolute;
top: 0;
right: 25px;
margin-right: -20px;
display: flex;
align-items: center;
}
.variable-combine .variable {
display: inline-block;
max-width: 60px;
margin-right: 10px;
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.variable-combine .copy {
font-size: 14px;
cursor: pointer;
color: #1E90FF;
}
</style>

View File

@ -2,17 +2,8 @@
<div>
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
<el-col :span="10">
<div class="variable">
<el-input v-model="common.variable" maxlength="60" size="small" @input="change"
:placeholder="$t('api_test.request.extract.variable_name')"/>
<div class="variable-combine" v-if="common.variable && edit">
<div class="value">{{common.value}}</div>
<el-tooltip :content="$t('api_test.request.extract.copied')" manual v-model="visible" placement="top"
:visible-arrow="false">
<i class="el-icon-copy-document copy" @click="copy"></i>
</el-tooltip>
</div>
</div>
<ms-api-variable-input v-model="common.variable" size="small" maxlength="60" @change="change"
:placeholder="$t('api_test.variable_name')"/>
</el-col>
<el-col>
<el-input v-model="common.expression" maxlength="255" size="small" :placeholder="expression"/>
@ -27,10 +18,11 @@
<script>
import {EXTRACT_TYPE, ExtractCommon} from "../../model/ScenarioModel";
import MsApiVariableInput from "../ApiVariableInput";
export default {
name: "MsApiExtractCommon",
components: {MsApiVariableInput},
props: {
extractType: {
type: String,

View File

@ -371,10 +371,10 @@ export class Arguments extends DefaultTestElement {
let collectionProp = this.collectionProp('Arguments.arguments');
this.args.forEach(arg => {
let elementProp = collectionProp.elementProp(arg.name, 'HTTPArgument');
elementProp.boolProp('HTTPArgument.always_encode', arg.encode || true);
let elementProp = collectionProp.elementProp(arg.name, 'Argument');
elementProp.stringProp('Argument.name', arg.name);
elementProp.stringProp('Argument.value', arg.value);
elementProp.stringProp('Argument.desc', arg.desc);
elementProp.stringProp('Argument.metadata', arg.metadata || "=");
});
}

View File

@ -12,7 +12,7 @@ import {
ResponseCodeAssertion,
ResponseDataAssertion,
ResponseHeadersAssertion,
BackendListener, RegexExtractor, JSONPostProcessor, XPath2Extractor
BackendListener, RegexExtractor, JSONPostProcessor, XPath2Extractor, Arguments
} from "./JMX";
export const uuid = function () {
@ -124,12 +124,12 @@ export class Scenario extends BaseConfig {
this.id = uuid();
this.name = null;
this.url = null;
this.parameters = [];
this.variables = [];
this.headers = [];
this.requests = [];
this.set(options);
this.sets({parameters: KeyValue, headers: KeyValue, requests: Request}, options);
this.sets({variables: KeyValue, headers: KeyValue, requests: Request}, options);
}
initOptions(options) {
@ -397,6 +397,10 @@ class JMXGenerator {
test.scenarioDefinition.forEach(scenario => {
let threadGroup = new ThreadGroup(scenario.name + SPLIT + scenario.id);
this.addScenarioVariables(threadGroup, scenario);
this.addScenarioHeaders(threadGroup, scenario);
scenario.requests.forEach(request => {
if (!request.isValid()) return;
@ -434,6 +438,22 @@ class JMXGenerator {
this.jmeterTestPlan.put(testPlan);
}
addScenarioVariables(threadGroup, scenario) {
let args = scenario.variables.filter(this.filter)
if (args.length > 0) {
let name = scenario.name + " Variables"
threadGroup.put(new Arguments(name, args));
}
}
addScenarioHeaders(threadGroup, scenario) {
let headers = scenario.headers.filter(this.filter)
if (headers.length > 0) {
let name = scenario.name + " Headers"
threadGroup.put(new HeaderManager(name, headers));
}
}
addRequestHeader(httpSamplerProxy, request) {
let name = request.name + " Headers";
let headers = request.headers.filter(this.filter);

View File

@ -209,15 +209,19 @@ export default {
reset: "Rest",
input_name: "Please enter the test name",
select_project: "Select project",
variable_name: "Variable name",
copied: "copied",
key: "Key",
value: "Value",
scenario: {
config: "Scenario Config",
input_name: "Please enter the scenario name",
name: "Scenario Name",
base_url: "Base URL",
base_url_description: "Base URL as URL prefix for all requests",
parameters: "Parameters",
variables: "Variables",
headers: "Headers",
kv_description: "Will be used for requests where the item is not set",
kv_description: "Variables are available for all requests",
},
request: {
input_name: "Please enter the request name",
@ -225,7 +229,7 @@ export default {
method: "Method",
url: "URL",
url_description: "etc: https://fit2cloud.com",
parameters: "Parameters",
parameters: "Query parameters",
parameters_desc: "Parameters will be appended to the URL e.g. https://fit2cloud.com?Name=Value&Name2=Value2",
headers: "Headers",
body: "Body",
@ -246,18 +250,16 @@ export default {
end_with: "End With",
value: "Value",
expression: "Expression",
response_in_time: "Response Time",
response_in_time: "Response in time",
},
extract: {
label: "Extract from response",
select_type: "Choose type",
description: "Extract data from the response and store it in variables. Use the variables in subsequent requests.",
regex: "Regex",
variable_name: "Variable name",
regex_expression: "Regular expression",
json_path_expression: "JSONPath expression",
xpath_expression: "XPath expression",
copied: "Copied"
}
}
},

View File

@ -209,15 +209,19 @@ export default {
reset: "重置",
input_name: "请输入测试名称",
select_project: "请选择项目",
variable_name: "变量名",
copied: "已拷贝",
key: "键",
value: "值",
scenario: {
config: "场景配置",
input_name: "请输入场景名称",
name: "场景名称",
base_url: "基础URL",
base_url_description: "基础URL作为所有请求的URL前缀",
parameters: "请求变量",
variables: "自定义变量",
headers: "请求头",
kv_description: "将用于未设置该项的请求",
kv_description: "所有请求可以使用自定义变量",
},
request: {
input_name: "请输入请求名称",
@ -253,11 +257,9 @@ export default {
select_type: "请选择类型",
description: "从响应结果中提取数据并将其存储在变量中,在后续请求中使用变量。",
regex: "正则",
variable_name: "变量名",
regex_expression: "Perl型正则表达式",
json_path_expression: "JSONPath表达式",
xpath_expression: "XPath表达式",
copied: "已拷贝"
}
}
},