api测试界面,未完待续

This commit is contained in:
q4speed 2020-04-20 18:40:02 +08:00
parent 22be52a59c
commit 98a5ede3f6
16 changed files with 302 additions and 203 deletions

View File

@ -1,174 +0,0 @@
<template>
<div class="container">
<div class="main-content">
<el-card>
<el-container class="scenario-container">
<el-header>
<span class="scenario-title">场景配置</span>
</el-header>
<el-container>
<el-aside class="scenario-aside">
<div class="scenario-list">
<ms-api-collapse v-model="activeName" @change="handleChange" accordion>
<ms-api-collapse-item v-for="(scenario, index) in scenarios" :key="index"
:title="scenario.name" :name="index">
<template slot="title">
<div class="scenario-name">{{scenario.name}}</div>
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link el-icon-more scenario-btn"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'delete', index:index}">删除场景</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<ms-api-request :requests="scenario.requests" :open="select"/>
</ms-api-collapse-item>
</ms-api-collapse>
</div>
<el-button class="scenario-create" type="primary" size="mini" icon="el-icon-plus" plain
@click="createScenario"/>
</el-aside>
<el-main class="scenario-main">
<div class="scenario-form">
<ms-api-scenario-form :scenario="selected" v-if="isScenario"></ms-api-scenario-form>
<ms-api-request-form :request="selected" v-if="isRequest"></ms-api-request-form>
</div>
</el-main>
</el-container>
</el-container>
</el-card>
</div>
</div>
</template>
<script>
import MsApiCollapseItem from "./components/ApiCollapseItem";
import MsApiCollapse from "./components/ApiCollapse";
import MsApiRequest from "./components/ApiRequest";
import MsApiRequestForm from "./components/ApiRequestForm";
import MsApiScenarioForm from "./components/ApiScenarioForm";
import {Scenario, Request} from "./model/APIModel";
export default {
name: "MsApiScenarioConfig",
components: {MsApiScenarioForm, MsApiRequestForm, MsApiRequest, MsApiCollapse, MsApiCollapseItem},
data() {
return {
activeName: 0,
scenarios: [],
selected: Object
}
},
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) {
this.select(this.scenarios[index]);
},
handleCommand: function (command) {
switch (command.type) {
case "delete":
this.deleteScenario(command.index);
break;
}
},
select: function (obj) {
this.selected = obj;
}
},
computed: {
isScenario() {
return this.selected instanceof Scenario;
},
isRequest() {
return this.selected instanceof Request;
}
},
created() {
if (this.scenarios.length === 0) {
this.createScenario();
this.select(this.scenarios[0]);
}
}
}
</script>
<style scoped>
.scenario-container {
height: calc(100vh - 150px);
min-height: 600px;
}
.scenario-title {
font-size: 16px;
margin-left: -20px;
}
.scenario-aside {
position: relative;
border-radius: 4px;
border: 1px solid #EBEEF5;
box-sizing: border-box;
}
.scenario-list {
overflow-y: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 28px;
}
.scenario-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 14px;
width: 100%;
}
.scenario-btn {
text-align: center;
padding: 13px;
}
.scenario-create {
position: absolute;
bottom: 0;
width: 100%;
}
.scenario-main {
position: relative;
margin-left: 20px;
border: 1px solid #EBEEF5;
}
.scenario-form {
padding: 20px;
overflow-y: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>

View File

@ -0,0 +1,94 @@
<template>
<div class="container">
<div class="main-content">
<el-card>
<el-container class="test-container" v-loading="result.loading">
<el-header>
<el-row type="flex" align="middle">
<el-input class="test-name" v-model="test.name" maxlength="64" :placeholder="$t('api_test.input_name')">
<el-select class="test-project" v-model="test.projectId" slot="prepend"
:placeholder="$t('api_test.select_project')">
<el-option v-for="item in projects" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</el-input>
<el-button type="primary" plain :disabled="isDisabled" @click="saveTest">保存</el-button>
</el-row>
</el-header>
<ms-api-scenario-config :scenarios="test.scenario_definition"/>
</el-container>
</el-card>
</div>
</div>
</template>
<script>
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
export default {
name: "MsApiTestConfig",
components: {MsApiScenarioConfig},
data() {
return {
result: {},
projects: [],
change: false,
test: {
projectId: null,
name: null,
scenario_definition: []
}
}
},
watch: {
test: {
handler: function () {
this.change = true;
},
deep: true
}
},
methods: {
saveTest: function () {
this.change = false;
this.$message({
message: this.$t('commons.save_success'),
type: 'success'
});
}
},
computed: {
isDisabled() {
return !(this.test.projectId && this.test.name && this.change)
}
},
created() {
this.result = this.$get("/project/listAll", response => {
this.projects = response.data;
})
}
}
</script>
<style scoped>
.test-container {
height: calc(100vh - 150px);
min-height: 600px;
}
.test-name {
width: 600px;
margin-left: -20px;
margin-right: 20px;
}
.test-project {
min-width: 150px;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div>
<el-row :gutter="10" type="flex" align="middle">
<el-col :span="4">
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
<el-col class="assertion-select">
<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>
@ -9,11 +9,11 @@
<el-option label="Body" value="BODY"></el-option>
</el-select>
</el-col>
<el-col :span="19">
<el-col>
<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-col 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>
@ -22,7 +22,7 @@
</template>
<script>
import {Regex} from "../model/APIModel";
import {Regex} from "../model/ScenarioModel";
export default {
name: "MsApiAssertionRegex",
@ -54,11 +54,16 @@
</script>
<style scoped>
.assertion-select {
width: 250px;
}
.assertion-item {
width: 100%;
}
.assertion-btn {
text-align: center;
width: 60px;
}
</style>

View File

@ -1,11 +1,11 @@
<template>
<div>
<el-row :gutter="10" align="middle">
<el-col :span="23">
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
<el-col>
<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-col 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>
@ -14,7 +14,7 @@
</template>
<script>
import {ResponseTime} from "../model/APIModel";
import {ResponseTime} from "../model/ScenarioModel";
export default {
name: "MsApiAssertionResponseTime",
@ -47,5 +47,6 @@
<style scoped>
.assertion-btn {
text-align: center;
width: 60px;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div>
<el-row :gutter="10">
<el-col :span="4">
<el-row :gutter="10" type="flex" justify="space-between" align="middle">
<el-col class="assertion-select">
<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>
@ -9,7 +9,7 @@
<el-option label="Body" value="BODY"></el-option>
</el-select>
</el-col>
<el-col :span="4">
<el-col class="assertion-select">
<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>
@ -19,11 +19,11 @@
<el-option :label="$t('api_test.request.assertions.end_with')" value="END_WITH"></el-option>
</el-select>
</el-col>
<el-col :span="15">
<el-col>
<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-col class="assertion-btn">
<el-button type="primary" size="small" icon="el-icon-plus" plain @click="add"/>
</el-col>
</el-row>
@ -31,7 +31,7 @@
</template>
<script>
import {Regex} from "../model/APIModel";
import {Regex} from "../model/ScenarioModel";
export default {
name: "MsApiAssertionText",
@ -89,7 +89,15 @@
</script>
<style scoped>
.assertion-select {
width: 250px;
}
.assertion-item {
width: 100%;
}
.assertion-btn {
width: 60px;
}
</style>

View File

@ -24,7 +24,7 @@
import MsApiAssertionText from "./ApiAssertionText";
import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionResponseTime from "./ApiAssertionResponseTime";
import {ASSERTION_TYPE, Assertions, Regex} from "../model/APIModel";
import {ASSERTION_TYPE, Assertions, Regex} from "../model/ScenarioModel";
import MsApiAssertionsEdit from "./ApiAssertionsEdit";
export default {

View File

@ -22,7 +22,7 @@
<script>
import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionResponseTime from "./ApiAssertionResponseTime";
import {Assertions} from "../model/APIModel";
import {Assertions} from "../model/ScenarioModel";
export default {
name: "MsApiAssertionsEdit",

View File

@ -18,7 +18,7 @@
<script>
import MsApiKeyValue from "./ApiKeyValue";
import {Body, BODY_TYPE} from "../model/APIModel";
import {Body, BODY_TYPE} from "../model/ScenarioModel";
export default {
name: "MsApiBody",

View File

@ -5,13 +5,13 @@
</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 :span="11">
<el-col>
<el-input v-model="item.key" placeholder="Key" size="small" maxlength="100" @change="check"/>
</el-col>
<el-col :span="11">
<el-col>
<el-input v-model="item.value" placeholder="Value" size="small" maxlength="100" @change="check"/>
</el-col>
<el-col :span="1">
<el-col class="kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
:disabled="isDisable(index)"/>
</el-col>
@ -21,7 +21,7 @@
</template>
<script>
import {KeyValue} from "../model/APIModel";
import {KeyValue} from "../model/ScenarioModel";
export default {
name: "MsApiKeyValue",
@ -83,4 +83,8 @@
.kv-row {
margin-top: 10px;
}
.kv-delete {
width: 60px;
}
</style>

View File

@ -25,10 +25,10 @@
</template>
<script>
import {Request} from "../model/APIModel";
import {Request} from "../model/ScenarioModel";
export default {
name: "MsApiRequest",
name: "MsApiRequestConfig",
props: {
requests: Array,
open: Function

View File

@ -56,7 +56,6 @@
activeName: "parameters",
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: [

View File

@ -0,0 +1,161 @@
<template>
<el-container>
<el-aside class="scenario-aside">
<div class="scenario-list">
<ms-api-collapse v-model="activeName" @change="handleChange" accordion>
<ms-api-collapse-item v-for="(scenario, index) in scenarios" :key="index"
:title="scenario.name" :name="index">
<template slot="title">
<div class="scenario-name">{{scenario.name}}</div>
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link el-icon-more scenario-btn"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'delete', index:index}">删除场景</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<ms-api-request-config :requests="scenario.requests" :open="select"/>
</ms-api-collapse-item>
</ms-api-collapse>
</div>
<el-button class="scenario-create" type="primary" size="mini" icon="el-icon-plus" plain
@click="createScenario"/>
</el-aside>
<el-main class="scenario-main">
<div class="scenario-form">
<ms-api-scenario-form :scenario="selected" v-if="isScenario"></ms-api-scenario-form>
<ms-api-request-form :request="selected" v-if="isRequest"></ms-api-request-form>
</div>
</el-main>
</el-container>
</template>
<script>
import MsApiCollapseItem from "./ApiCollapseItem";
import MsApiCollapse from "./ApiCollapse";
import MsApiRequestConfig from "./ApiRequestConfig";
import MsApiRequestForm from "./ApiRequestForm";
import MsApiScenarioForm from "./ApiScenarioForm";
import {Scenario, Request} from "../model/ScenarioModel";
export default {
name: "MsApiScenarioConfig",
components: {
MsApiRequestConfig,
MsApiScenarioForm,
MsApiRequestForm,
MsApiCollapse,
MsApiCollapseItem
},
props: {
scenarios: Array
},
data() {
return {
activeName: 0,
selected: Object
}
},
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) {
this.select(this.scenarios[index]);
},
handleCommand: function (command) {
switch (command.type) {
case "delete":
this.deleteScenario(command.index);
break;
}
},
select: function (obj) {
this.selected = obj;
}
},
computed: {
isScenario() {
return this.selected instanceof Scenario;
},
isRequest() {
return this.selected instanceof Request;
}
},
created() {
if (this.scenarios.length === 0) {
this.createScenario();
this.select(this.scenarios[0]);
}
}
}
</script>
<style scoped>
.scenario-aside {
position: relative;
border-radius: 4px;
border: 1px solid #EBEEF5;
box-sizing: border-box;
}
.scenario-list {
overflow-y: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 28px;
}
.scenario-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 14px;
width: 100%;
}
.scenario-btn {
text-align: center;
padding: 13px;
}
.scenario-create {
position: absolute;
bottom: 0;
width: 100%;
}
.scenario-main {
position: relative;
margin-left: 20px;
border: 1px solid #EBEEF5;
}
.scenario-form {
padding: 20px;
overflow-y: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>

View File

@ -34,7 +34,6 @@
activeName: "variables",
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: [

View File

@ -18,7 +18,7 @@ import PerformanceTestReport from "../../performance/report/PerformanceTestRepor
import ApiTestReport from "../../api/report/ApiTestReport";
import ApiTest from "../../api/ApiTest";
import PerformanceTest from "../../performance/PerformanceTest";
import ApiScenarioConfig from "../../api/test/ApiScenarioConfig";
import ApiTestConfig from "../../api/test/ApiTestConfig";
import PerformanceTestHome from "../../performance/home/PerformanceTestHome";
import ApiTestList from "../../api/test/ApiTestList";
import ApiTestHome from "../../api/home/ApiTestHome";
@ -97,12 +97,12 @@ const router = new VueRouter({
{
path: 'test/create',
name: "createAPITest",
component: ApiScenarioConfig,
component: ApiTestConfig,
},
{
path: "test/edit/:testId",
name: "editAPITest",
component: ApiScenarioConfig,
component: ApiTestConfig,
props: {
content: (route) => {
return {

View File

@ -169,6 +169,8 @@ export default {
'resource_pool_is_null': '资源池为空',
},
api_test: {
input_name: "请输入测试名称",
select_project: "请选择项目",
scenario: {
input_name: "请输入场景名称",
name: "场景名称",