api界面,未完待续
This commit is contained in:
parent
30f6745b90
commit
f7a11e9405
|
@ -26,13 +26,14 @@
|
||||||
</ms-api-collapse-item>
|
</ms-api-collapse-item>
|
||||||
</ms-api-collapse>
|
</ms-api-collapse>
|
||||||
</div>
|
</div>
|
||||||
<el-button class="scenario-create" type="primary" size="mini" icon="el-icon-plus" plain @click="create"/>
|
<el-button class="scenario-create" type="primary" size="mini" icon="el-icon-plus" plain
|
||||||
|
@click="createScenario"/>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
|
|
||||||
<el-main class="scenario-main">
|
<el-main class="scenario-main">
|
||||||
<div class="scenario-form">
|
<div class="scenario-form">
|
||||||
<ms-api-scenario-form :scenario="selected"></ms-api-scenario-form>
|
<ms-api-scenario-form :scenario="selected" v-if="isScenario"></ms-api-scenario-form>
|
||||||
<ms-api-request-form :request="selected"></ms-api-request-form>
|
<ms-api-request-form :request="selected" v-if="isRequest"></ms-api-request-form>
|
||||||
</div>
|
</div>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
|
@ -49,6 +50,7 @@
|
||||||
import MsApiRequest from "./components/ApiRequest";
|
import MsApiRequest from "./components/ApiRequest";
|
||||||
import MsApiRequestForm from "./components/ApiRequestForm";
|
import MsApiRequestForm from "./components/ApiRequestForm";
|
||||||
import MsApiScenarioForm from "./components/ApiScenarioForm";
|
import MsApiScenarioForm from "./components/ApiScenarioForm";
|
||||||
|
import {Scenario, Request} from "./model/APIModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiScenarioConfig",
|
name: "MsApiScenarioConfig",
|
||||||
|
@ -64,6 +66,17 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
createScenario: function () {
|
||||||
|
let scenario = new Scenario({name: "Scenario"});
|
||||||
|
this.scenarios.push(scenario);
|
||||||
|
},
|
||||||
|
deleteScenario: function (index) {
|
||||||
|
this.scenarios.splice(index, 1);
|
||||||
|
if (this.scenarios.length === 0) {
|
||||||
|
this.createScenario();
|
||||||
|
this.select(this.scenarios[0]);
|
||||||
|
}
|
||||||
|
},
|
||||||
handleChange: function (index) {
|
handleChange: function (index) {
|
||||||
this.select(this.scenarios[index]);
|
this.select(this.scenarios[index]);
|
||||||
},
|
},
|
||||||
|
@ -74,35 +87,23 @@
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createScenario: function () {
|
|
||||||
return {
|
|
||||||
type: "Scenario",
|
|
||||||
name: "Scenario",
|
|
||||||
address: "",
|
|
||||||
file: "",
|
|
||||||
variables: [],
|
|
||||||
headers: [],
|
|
||||||
requests: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deleteScenario: function (index) {
|
|
||||||
this.scenarios.splice(index, 1);
|
|
||||||
if (this.scenarios.length === 0) {
|
|
||||||
this.create();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
create: function () {
|
|
||||||
let scenario = this.createScenario();
|
|
||||||
this.scenarios.push(scenario);
|
|
||||||
},
|
|
||||||
select: function (obj) {
|
select: function (obj) {
|
||||||
this.selected = obj;
|
this.selected = obj;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isScenario() {
|
||||||
|
return this.selected instanceof Scenario;
|
||||||
|
},
|
||||||
|
isRequest() {
|
||||||
|
return this.selected instanceof Request;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.scenarios.length === 0) {
|
if (this.scenarios.length === 0) {
|
||||||
this.create();
|
this.createScenario();
|
||||||
this.select(this.scenarios[0]);
|
this.select(this.scenarios[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,6 +138,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.scenario-name {
|
.scenario-name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-row :gutter="10" type="flex" align="middle">
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-select class="assertion-item" v-model="regex.subject" size="small"
|
||||||
|
:placeholder="$t('api_test.request.assertions.select_subject')">
|
||||||
|
<el-option label="Http-Code" value="HTTP-CODE"></el-option>
|
||||||
|
<el-option label="Header" value="HEADER"></el-option>
|
||||||
|
<el-option label="Body" value="BODY"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="19">
|
||||||
|
<el-input v-model="regex.expression" maxlength="255" size="small" show-word-limit
|
||||||
|
:placeholder="$t('api_test.request.assertions.expression')"/>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1" class="assertion-btn">
|
||||||
|
<el-button type="danger" size="mini" icon="el-icon-delete" circle @click="remove" v-if="edit"/>
|
||||||
|
<el-button type="primary" size="small" icon="el-icon-plus" plain @click="add" v-else/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {Regex} from "../model/APIModel";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiAssertionRegex",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
regex: {
|
||||||
|
type: Regex,
|
||||||
|
default: () => {
|
||||||
|
return new Regex();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
index: Number,
|
||||||
|
list: Array
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.list.push(new Regex(this.regex));
|
||||||
|
},
|
||||||
|
remove: function () {
|
||||||
|
this.list.splice(this.index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.assertion-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assertion-btn {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-row :gutter="10" align="middle">
|
||||||
|
<el-col :span="23">
|
||||||
|
<el-input v-model="time" step="100" size="small" type="number"
|
||||||
|
:placeholder="$t('api_test.request.assertions.response_in_time')"/>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1" class="assertion-btn">
|
||||||
|
<el-button type="danger" size="mini" icon="el-icon-delete" circle @click="remove" v-if="edit"/>
|
||||||
|
<el-button type="primary" size="small" icon="el-icon-plus" plain @click="add" v-else/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {ResponseTime} from "../model/APIModel";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiAssertionResponseTime",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
edit: Boolean,
|
||||||
|
responseTime: ResponseTime
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
time: this.responseTime.responseInTime
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.remove();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.responseTime.responseInTime = this.time;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
remove: function () {
|
||||||
|
this.responseTime.responseInTime = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.assertion-btn {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,95 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-select class="assertion-item" v-model="subject" size="small"
|
||||||
|
:placeholder="$t('api_test.request.assertions.select_subject')">
|
||||||
|
<el-option label="Http-Code" value="HTTP-CODE"></el-option>
|
||||||
|
<el-option label="Header" value="HEADER"></el-option>
|
||||||
|
<el-option label="Body" value="BODY"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-select class="assertion-item" v-model="condition" size="small"
|
||||||
|
:placeholder="$t('api_test.request.assertions.select_contains')">
|
||||||
|
<el-option :label="$t('api_test.request.assertions.contains')" value="CONTAINS"></el-option>
|
||||||
|
<el-option :label="$t('api_test.request.assertions.not_contains')" value="NOT_CONTAINS"></el-option>
|
||||||
|
<el-option :label="$t('api_test.request.assertions.equals')" value="EQUALS"></el-option>
|
||||||
|
<el-option :label="$t('api_test.request.assertions.start_with')" value="START_WITH"></el-option>
|
||||||
|
<el-option :label="$t('api_test.request.assertions.end_with')" value="END_WITH"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="15">
|
||||||
|
<el-input v-model="value" maxlength="255" size="small" show-word-limit
|
||||||
|
:placeholder="$t('api_test.request.assertions.value')"/>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1">
|
||||||
|
<el-button type="primary" size="small" icon="el-icon-plus" plain @click="add"/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {Regex} from "../model/APIModel";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiAssertionText",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
list: Array
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
subject: "",
|
||||||
|
condition: "",
|
||||||
|
value: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
add: function () {
|
||||||
|
this.list.push(this.toRegex());
|
||||||
|
},
|
||||||
|
toRegex: function () {
|
||||||
|
let expression = "";
|
||||||
|
let description = "";
|
||||||
|
switch (this.condition) {
|
||||||
|
case "CONTAINS":
|
||||||
|
expression = ".*" + this.value + ".*";
|
||||||
|
description = "contains: " + this.value;
|
||||||
|
break;
|
||||||
|
case "NOT_CONTAINS":
|
||||||
|
expression = "^((?!" + this.value + ").)*$";
|
||||||
|
description = "not contains: " + this.value;
|
||||||
|
break;
|
||||||
|
case "EQUALS":
|
||||||
|
expression = "^" + this.value + "$";
|
||||||
|
description = "equals: " + this.value;
|
||||||
|
break;
|
||||||
|
case "START_WITH":
|
||||||
|
expression = "^" + this.value;
|
||||||
|
description = "start with: " + this.value;
|
||||||
|
break;
|
||||||
|
case "END_WITH":
|
||||||
|
expression = this.value + "$";
|
||||||
|
description = "end with: " + this.value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return new Regex({
|
||||||
|
subject: this.subject,
|
||||||
|
expression: expression,
|
||||||
|
description: description
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.assertion-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,59 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-select 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.response_time')" :value="options.RESPONSE_TIME"/>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="20">
|
||||||
|
<ms-api-assertion-text :list="assertions.regex" v-if="type === options.TEXT"/>
|
||||||
|
<ms-api-assertion-regex :list="assertions.regex" v-if="type === options.REGEX"/>
|
||||||
|
<ms-api-assertion-response-time :response-time="assertions.responseTime" v-if="type === options.RESPONSE_TIME"/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<ms-api-assertions-edit :assertions="assertions"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsApiAssertionText from "./ApiAssertionText";
|
||||||
|
import MsApiAssertionRegex from "./ApiAssertionRegex";
|
||||||
|
import MsApiAssertionResponseTime from "./ApiAssertionResponseTime";
|
||||||
|
import {ASSERTION_TYPE, Assertions, Regex} from "../model/APIModel";
|
||||||
|
import MsApiAssertionsEdit from "./ApiAssertionsEdit";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiAssertions",
|
||||||
|
|
||||||
|
components: {MsApiAssertionsEdit, MsApiAssertionResponseTime, MsApiAssertionRegex, MsApiAssertionText},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
assertions: Assertions
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
options: ASSERTION_TYPE,
|
||||||
|
type: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
createRegex: function () {
|
||||||
|
return new Regex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.assertion-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,57 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="assertion-item-editing regex" v-if="assertions.regex.length > 0">
|
||||||
|
<div>
|
||||||
|
{{$t("api_test.request.assertions.regex")}}
|
||||||
|
</div>
|
||||||
|
<div class="regex-item" v-for="(regex, index) in assertions.regex" :key="index">
|
||||||
|
<ms-api-assertion-regex :list="assertions.regex" :regex="regex" :edit="true" :index="index"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="assertion-item-editing response-time" v-if="assertions.responseTime.isValid()">
|
||||||
|
<div>
|
||||||
|
{{$t("api_test.request.assertions.response_time")}}
|
||||||
|
</div>
|
||||||
|
<ms-api-assertion-response-time :response-time="assertions.responseTime" :edit="true"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsApiAssertionRegex from "./ApiAssertionRegex";
|
||||||
|
import MsApiAssertionResponseTime from "./ApiAssertionResponseTime";
|
||||||
|
import {Assertions} from "../model/APIModel";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MsApiAssertionsEdit",
|
||||||
|
|
||||||
|
components: {MsApiAssertionResponseTime, MsApiAssertionRegex},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
assertions: Assertions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.assertion-item-editing {
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assertion-item-editing.regex {
|
||||||
|
border-left: 2px solid #7B0274;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assertion-item-editing.response-time {
|
||||||
|
border-left: 2px solid #DD0240;
|
||||||
|
}
|
||||||
|
|
||||||
|
.regex-item {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,15 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-radio-group v-model="body.type" size="mini">
|
<el-radio-group v-model="body.type" size="mini">
|
||||||
<el-radio-button label="kv">
|
<el-radio-button :label="type.KV">
|
||||||
{{$t('api_test.request.body_kv')}}
|
{{$t('api_test.request.body_kv')}}
|
||||||
</el-radio-button>
|
</el-radio-button>
|
||||||
<el-radio-button label="text">
|
<el-radio-button :label="type.TEXT">
|
||||||
{{$t('api_test.request.body_text')}}
|
{{$t('api_test.request.body_text')}}
|
||||||
</el-radio-button>
|
</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
|
|
||||||
<ms-api-key-value :items="body.kvs" v-if="isKV"/>
|
<ms-api-key-value :items="body.kvs" v-if="body.isKV()"/>
|
||||||
|
|
||||||
<el-input class="textarea" type="textarea" v-model="body.text" :autosize="{ minRows: 10, maxRows: 25}" resize="none"
|
<el-input class="textarea" type="textarea" v-model="body.text" :autosize="{ minRows: 10, maxRows: 25}" resize="none"
|
||||||
v-else/>
|
v-else/>
|
||||||
|
@ -18,23 +18,26 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MsApiKeyValue from "./ApiKeyValue";
|
import MsApiKeyValue from "./ApiKeyValue";
|
||||||
|
import {Body, BODY_TYPE} from "../model/APIModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiBody",
|
name: "MsApiBody",
|
||||||
components: {MsApiKeyValue},
|
components: {MsApiKeyValue},
|
||||||
props: {
|
props: {
|
||||||
body: Object
|
body: Body
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {
|
||||||
|
type: BODY_TYPE
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {},
|
methods: {},
|
||||||
|
|
||||||
computed: {
|
created() {
|
||||||
isKV() {
|
if (this.body.type === null) {
|
||||||
return this.body.type === "kv";
|
this.body.type = BODY_TYPE.KV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
<el-input v-model="item.value" placeholder="Value" size="small" maxlength="100" @change="check"/>
|
<el-input v-model="item.value" placeholder="Value" size="small" maxlength="100" @change="check"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1">
|
<el-col :span="1">
|
||||||
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"/>
|
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
|
||||||
|
:disabled="isDisable(index)"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,6 +21,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import {KeyValue} from "../model/APIModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiKeyValue",
|
name: "MsApiKeyValue",
|
||||||
|
|
||||||
|
@ -29,23 +32,20 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
create: function () {
|
add: function () {
|
||||||
return {
|
this.items.push(new KeyValue());
|
||||||
key: "",
|
|
||||||
value: ""
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
this.items.splice(index, 1);
|
this.items.splice(index, 1);
|
||||||
if (this.items.length === 0) {
|
if (this.items.length === 0) {
|
||||||
this.items.push(this.create());
|
this.add();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
check: function () {
|
check: function () {
|
||||||
let isNeedCreate = true;
|
let isNeedCreate = true;
|
||||||
let removeIndex = -1;
|
let removeIndex = -1;
|
||||||
this.items.forEach((item, index) => {
|
this.items.forEach((item, index) => {
|
||||||
if (item.key === "" && item.value === "") {
|
if (!item.key && !item.value) {
|
||||||
// 多余的空行
|
// 多余的空行
|
||||||
if (index !== this.items.length - 1) {
|
if (index !== this.items.length - 1) {
|
||||||
removeIndex = index;
|
removeIndex = index;
|
||||||
|
@ -55,18 +55,21 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (isNeedCreate) {
|
if (isNeedCreate) {
|
||||||
this.items.push(this.create());
|
this.add();
|
||||||
}
|
}
|
||||||
if (removeIndex !== -1) {
|
if (removeIndex !== -1) {
|
||||||
this.remove(removeIndex);
|
this.remove(removeIndex);
|
||||||
}
|
}
|
||||||
// TODO 检查key重复
|
// TODO 检查key重复
|
||||||
|
},
|
||||||
|
isDisable: function (index) {
|
||||||
|
return this.items.length - 1 === index;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.items.length === 0) {
|
if (this.items.length === 0) {
|
||||||
this.items.push(this.create());
|
this.add();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,28 +2,30 @@
|
||||||
<div class="request-container">
|
<div class="request-container">
|
||||||
<div class="request-item" v-for="(request, index) in requests" :key="index" @click="select(request)"
|
<div class="request-item" v-for="(request, index) in requests" :key="index" @click="select(request)"
|
||||||
:class="{'selected': isSelected(request)}">
|
:class="{'selected': isSelected(request)}">
|
||||||
<span class="request-method">
|
<el-row type="flex">
|
||||||
{{request.method}}
|
<div class="request-method">
|
||||||
</span>
|
{{request.method}}
|
||||||
<span class="request-name">
|
</div>
|
||||||
{{request.name}}
|
<div class="request-name">
|
||||||
</span>
|
{{request.name}}
|
||||||
<span class="request-btn">
|
</div>
|
||||||
<el-dropdown trigger="click" @command="handleCommand">
|
<div class="request-btn">
|
||||||
<span class="el-dropdown-link el-icon-more"></span>
|
<el-dropdown trigger="click" @command="handleCommand">
|
||||||
<el-dropdown-menu slot="dropdown">
|
<span class="el-dropdown-link el-icon-more"></span>
|
||||||
<el-dropdown-item :command="{type: 'copy', index: index}">复制请求</el-dropdown-item>
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item :command="{type: 'delete', index: index}">删除请求</el-dropdown-item>
|
<el-dropdown-item :command="{type: 'copy', index: index}">复制请求</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
<el-dropdown-item :command="{type: 'delete', index: index}">删除请求</el-dropdown-item>
|
||||||
</el-dropdown>
|
</el-dropdown-menu>
|
||||||
</span>
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<el-button class="request-create" type="primary" size="mini" icon="el-icon-plus" plain @click="create"/>
|
<el-button class="request-create" type="primary" size="mini" icon="el-icon-plus" plain @click="createRequest"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {generateId} from 'element-ui/src/utils/util';
|
import {Request} from "../model/APIModel";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiRequest",
|
name: "MsApiRequest",
|
||||||
|
@ -34,7 +36,7 @@
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selected: 0
|
selected: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -47,10 +49,20 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
create: function () {
|
createRequest: function () {
|
||||||
let request = this.createRequest();
|
let request = new Request({method: "GET"});
|
||||||
this.requests.push(request);
|
this.requests.push(request);
|
||||||
},
|
},
|
||||||
|
copyRequest: function (index) {
|
||||||
|
let request = this.requests[index];
|
||||||
|
this.requests.push(JSON.parse(JSON.stringify(request)));
|
||||||
|
},
|
||||||
|
deleteRequest: function (index) {
|
||||||
|
this.requests.splice(index, 1);
|
||||||
|
if (this.requests.length === 0) {
|
||||||
|
this.createRequest();
|
||||||
|
}
|
||||||
|
},
|
||||||
handleCommand: function (command) {
|
handleCommand: function (command) {
|
||||||
switch (command.type) {
|
switch (command.type) {
|
||||||
case "copy":
|
case "copy":
|
||||||
|
@ -61,33 +73,6 @@
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
copyRequest: function (index) {
|
|
||||||
let request = this.requests[index];
|
|
||||||
this.requests.push(JSON.parse(JSON.stringify(request)));
|
|
||||||
},
|
|
||||||
deleteRequest: function (index) {
|
|
||||||
this.requests.splice(index, 1);
|
|
||||||
if (this.requests.length === 0) {
|
|
||||||
this.create();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
createRequest: function () {
|
|
||||||
return {
|
|
||||||
randomId: generateId(),
|
|
||||||
type: "Request",
|
|
||||||
method: "GET",
|
|
||||||
name: "",
|
|
||||||
parameters: [],
|
|
||||||
headers: [],
|
|
||||||
body: {
|
|
||||||
type: "kv",
|
|
||||||
kvs: [],
|
|
||||||
text: ""
|
|
||||||
},
|
|
||||||
assertions: [],
|
|
||||||
extract: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
select: function (request) {
|
select: function (request) {
|
||||||
this.selected = request;
|
this.selected = request;
|
||||||
this.open(request);
|
this.open(request);
|
||||||
|
@ -96,7 +81,7 @@
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.requests.length === 0) {
|
if (this.requests.length === 0) {
|
||||||
this.create();
|
this.createRequest();
|
||||||
this.select(this.requests[0]);
|
this.select(this.requests[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,11 +111,13 @@
|
||||||
|
|
||||||
.request-method {
|
.request-method {
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
width: 60px;
|
|
||||||
color: #1E90FF;
|
color: #1E90FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.request-name {
|
.request-name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form :model="request" :rules="rules" ref="request" label-width="100px" label-position="left" v-if="isRequest">
|
<el-form :model="request" :rules="rules" ref="request" label-width="100px">
|
||||||
<el-form-item :label="$t('api_test.request.name')" prop="name">
|
<el-form-item :label="$t('api_test.request.name')" prop="name">
|
||||||
<el-input v-model="request.name"></el-input>
|
<el-input v-model="request.name" maxlength="100"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="$t('api_test.request.url')" prop="url">
|
<el-form-item :label="$t('api_test.request.url')" prop="url">
|
||||||
<el-input v-model="request.url" :placeholder="$t('api_test.request.url_describe')">
|
<el-input v-model="request.url" maxlength="100" :placeholder="$t('api_test.request.url_description')">
|
||||||
<el-select v-model="request.method" slot="prepend" class="request-method-select">
|
<el-select v-model="request.method" slot="prepend" class="request-method-select">
|
||||||
<el-option label="GET" value="GET"></el-option>
|
<el-option label="GET" value="GET"></el-option>
|
||||||
<el-option label="POST" value="POST"></el-option>
|
<el-option label="POST" value="POST"></el-option>
|
||||||
|
@ -29,8 +29,8 @@
|
||||||
<el-tab-pane :label="$t('api_test.request.body')" name="body" v-if="isNotGet">
|
<el-tab-pane :label="$t('api_test.request.body')" name="body" v-if="isNotGet">
|
||||||
<ms-api-body :body="request.body"/>
|
<ms-api-body :body="request.body"/>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.request.assertions')" name="assertions" v-if="false">
|
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
|
||||||
TODO
|
<ms-api-assertions :assertions="request.assertions"></ms-api-assertions>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('api_test.request.extract')" name="extract" v-if="false">
|
<el-tab-pane :label="$t('api_test.request.extract')" name="extract" v-if="false">
|
||||||
TODO
|
TODO
|
||||||
|
@ -42,10 +42,11 @@
|
||||||
<script>
|
<script>
|
||||||
import MsApiKeyValue from "./ApiKeyValue";
|
import MsApiKeyValue from "./ApiKeyValue";
|
||||||
import MsApiBody from "./ApiBody";
|
import MsApiBody from "./ApiBody";
|
||||||
|
import MsApiAssertions from "./ApiAssertions";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiRequestForm",
|
name: "MsApiRequestForm",
|
||||||
components: {MsApiBody, MsApiKeyValue},
|
components: {MsApiAssertions, MsApiBody, MsApiKeyValue},
|
||||||
props: {
|
props: {
|
||||||
request: Object
|
request: Object
|
||||||
},
|
},
|
||||||
|
@ -53,14 +54,19 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeName: "parameters",
|
activeName: "parameters",
|
||||||
rules: {}
|
rules: {
|
||||||
|
name: [
|
||||||
|
{required: true, message: this.$t('api_test.scenario.input_name'), trigger: 'blur'},
|
||||||
|
{max: 100, message: this.$t('commons.input_limit', [0, 100]), trigger: 'blur'}
|
||||||
|
],
|
||||||
|
url: [
|
||||||
|
{max: 100, message: this.$t('commons.input_limit', [0, 100]), trigger: 'blur'}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
isRequest() {
|
|
||||||
return this.request.type === "Request";
|
|
||||||
},
|
|
||||||
isNotGet() {
|
isNotGet() {
|
||||||
return this.request.method !== "GET";
|
return this.request.method !== "GET";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form :model="scenario" :rules="rules" ref="scenario" label-width="100px" label-position="left" v-if="isScenario">
|
<el-form :model="scenario" :rules="rules" ref="scenario" label-width="100px">
|
||||||
<el-form-item :label="$t('api_test.scenario.name')" prop="name">
|
<el-form-item :label="$t('api_test.scenario.name')" prop="name">
|
||||||
<el-input v-model="scenario.name"></el-input>
|
<el-input v-model="scenario.name" maxlength="100"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="$t('api_test.scenario.base_url')" prop="url">
|
<el-form-item :label="$t('api_test.scenario.base_url')" prop="url">
|
||||||
<el-input :placeholder="$t('api_test.scenario.base_url_describe')" v-model="scenario.url"></el-input>
|
<el-input :placeholder="$t('api_test.scenario.base_url_description')" v-model="scenario.url" maxlength="100"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-tabs v-model="activeName">
|
<el-tabs v-model="activeName">
|
||||||
|
@ -32,15 +32,17 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeName: "variables",
|
activeName: "variables",
|
||||||
rules: {}
|
rules: {
|
||||||
|
name: [
|
||||||
|
{required: true, message: this.$t('api_test.scenario.input_name'), trigger: 'blur'},
|
||||||
|
{max: 100, message: this.$t('commons.input_limit', [0, 100]), trigger: 'blur'}
|
||||||
|
],
|
||||||
|
url: [
|
||||||
|
{max: 100, message: this.$t('commons.input_limit', [0, 100]), trigger: 'blur'}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
computed: {
|
|
||||||
isScenario() {
|
|
||||||
return this.scenario.type === "Scenario";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
import {generateId} from "element-ui/src/utils/util";
|
||||||
|
|
||||||
|
const assign = function (obj, options) {
|
||||||
|
for (let name in options) {
|
||||||
|
if (options.hasOwnProperty(name)) {
|
||||||
|
obj[name] = options[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BODY_TYPE = {
|
||||||
|
KV: "KV",
|
||||||
|
TEXT: "TEXT"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ASSERTION_TYPE = {
|
||||||
|
TEXT: "TEXT",
|
||||||
|
REGEX: "REGEX",
|
||||||
|
RESPONSE_TIME: "RESPONSE_TIME"
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Scenario {
|
||||||
|
constructor(options) {
|
||||||
|
this.name = null;
|
||||||
|
this.url = null;
|
||||||
|
this.variables = [];
|
||||||
|
this.headers = [];
|
||||||
|
this.requests = [];
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Request {
|
||||||
|
constructor(options) {
|
||||||
|
this.randomId = generateId();
|
||||||
|
this.name = null;
|
||||||
|
this.url = null;
|
||||||
|
this.method = null;
|
||||||
|
this.parameters = [];
|
||||||
|
this.headers = [];
|
||||||
|
this.body = new Body();
|
||||||
|
this.assertions = new Assertions();
|
||||||
|
this.extract = [];
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Body {
|
||||||
|
constructor(options) {
|
||||||
|
this.type = null;
|
||||||
|
this.text = null;
|
||||||
|
this.kvs = [];
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
isKV() {
|
||||||
|
return this.type === BODY_TYPE.KV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KeyValue {
|
||||||
|
constructor(options) {
|
||||||
|
this.key = null;
|
||||||
|
this.value = null;
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Assertions {
|
||||||
|
constructor(options) {
|
||||||
|
this.text = [];
|
||||||
|
this.regex = [];
|
||||||
|
this.responseTime = new ResponseTime();
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssertionType {
|
||||||
|
constructor(type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Text extends AssertionType {
|
||||||
|
constructor(options) {
|
||||||
|
super(ASSERTION_TYPE.TEXT);
|
||||||
|
this.subject = null;
|
||||||
|
this.condition = null;
|
||||||
|
this.value = null;
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Regex extends AssertionType {
|
||||||
|
constructor(options) {
|
||||||
|
super(ASSERTION_TYPE.REGEX);
|
||||||
|
this.subject = null;
|
||||||
|
this.expression = null;
|
||||||
|
this.description = null;
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResponseTime extends AssertionType {
|
||||||
|
constructor(options) {
|
||||||
|
super(ASSERTION_TYPE.RESPONSE_TIME);
|
||||||
|
this.responseInTime = null;
|
||||||
|
|
||||||
|
assign(this, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return this.responseInTime !== null && this.responseInTime > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ export default {
|
||||||
'refresh': '刷新',
|
'refresh': '刷新',
|
||||||
'remark': '备注',
|
'remark': '备注',
|
||||||
'delete': '删除',
|
'delete': '删除',
|
||||||
'not_filled': '未填写'
|
'not_filled': '未填写',
|
||||||
|
'please_select': '请选择',
|
||||||
},
|
},
|
||||||
workspace: {
|
workspace: {
|
||||||
'create': '创建工作空间',
|
'create': '创建工作空间',
|
||||||
|
@ -169,25 +170,43 @@ export default {
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
scenario: {
|
scenario: {
|
||||||
|
input_name: "请输入场景名称",
|
||||||
name: "场景名称",
|
name: "场景名称",
|
||||||
base_url: "基础URL",
|
base_url: "基础URL",
|
||||||
base_url_describe: "基础URL作为所有请求的URL前缀",
|
base_url_description: "基础URL作为所有请求的URL前缀",
|
||||||
variables: "变量",
|
variables: "变量",
|
||||||
headers: "请求头"
|
headers: "请求头"
|
||||||
},
|
},
|
||||||
request: {
|
request: {
|
||||||
|
input_name: "请输入请求名称",
|
||||||
name: "请求名称",
|
name: "请求名称",
|
||||||
method: "请求方法",
|
method: "请求方法",
|
||||||
url: "请求URL",
|
url: "请求URL",
|
||||||
url_describe: "例如: https://fit2cloud.com",
|
url_description: "例如: https://fit2cloud.com",
|
||||||
parameters: "请求参数",
|
parameters: "请求参数",
|
||||||
parameters_desc: "参数追加到URL,例如https://fit2cloud.com/entries?key1=Value1&Key2=Value2",
|
parameters_desc: "参数追加到URL,例如https://fit2cloud.com/entries?key1=Value1&Key2=Value2",
|
||||||
headers: "请求头",
|
headers: "请求头",
|
||||||
body: "请求内容",
|
body: "请求内容",
|
||||||
body_kv: "键值对",
|
body_kv: "键值对",
|
||||||
body_text: "文本",
|
body_text: "文本",
|
||||||
assertions: "断言",
|
assertions: {
|
||||||
extract: "提取"
|
label: "断言",
|
||||||
|
text: "文本",
|
||||||
|
regex: "正则",
|
||||||
|
response_time: "响应时间",
|
||||||
|
select_type: "请选择类型",
|
||||||
|
select_subject: "请选择对象",
|
||||||
|
select_contains: "请选择条件",
|
||||||
|
contains: "包含",
|
||||||
|
not_contains: "不包含",
|
||||||
|
equals: "等于",
|
||||||
|
start_with: "以...开始",
|
||||||
|
end_with: "以...结束",
|
||||||
|
value: "值",
|
||||||
|
expression: "正则表达式",
|
||||||
|
response_in_time: "响应时间在...毫秒以内",
|
||||||
|
},
|
||||||
|
extract: "提取",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
test_track: {
|
test_track: {
|
||||||
|
|
Loading…
Reference in New Issue