feat(接口自动化): 场景自动化基本画面完成

This commit is contained in:
fit2-zhao 2020-12-02 15:34:00 +08:00
parent 4e12976dfd
commit c90789e48c
7 changed files with 193 additions and 60 deletions

View File

@ -2,30 +2,30 @@
<div v-loading="loading">
<el-card>
<el-row>
<div class="el-step__icon is-text ms-api-col" v-if="data.referenced">
<div class="el-step__icon-inner">{{data.$treeNodeId}}</div>
<div class="el-step__icon is-text ms-api-col" v-if="request.referenced">
<div class="el-step__icon-inner">{{request.$treeNodeId}}</div>
</div>
<div class="el-step__icon is-text ms-api-col-create" v-else>
<div class="el-step__icon-inner">{{data.$treeNodeId}}</div>
<div class="el-step__icon-inner">{{request.$treeNodeId}}</div>
</div>
<i class="icon el-icon-arrow-right" :class="{'is-active': data.active}"
@click="active(data)"/>
<span>{{data.type!= 'create' ? data.name:''}} </span>
<i class="icon el-icon-arrow-right" :class="{'is-active': request.active}"
@click="active(request)"/>
<span>{{request.type!= 'create' ? request.name:''}} </span>
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="remove" style="margin-right: 20px; float: right"/>
</el-row>
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="data.active">
<div v-if="request.active">
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :headers="data.request.hashTree[0].headers " :request="data.request" v-if="data.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="data.request" :currentProject="currentProject" v-if="data.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="data.request" :currentProject="currentProject" v-if="data.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="data.request" :currentProject="currentProject" v-if="data.protocol==='DUBBO'"/>
<ms-api-request-form :headers="request.headers " :request="request" v-if="request.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="request" :currentProject="currentProject" v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)" v-if="!data.referenced">
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)" v-if="!request.referenced">
{{$t('commons.save')}}
</el-button>
</div>
@ -43,7 +43,7 @@
export default {
name: "MsApiComponent",
props: {
data: {},
request: {},
node: {},
currentProject: {},
},
@ -53,7 +53,7 @@
},
methods: {
remove() {
this.$emit('remove', this.data, this.node);
this.$emit('remove', this.request, this.node);
},
active(item) {
item.active = !item.active;

View File

@ -0,0 +1,76 @@
<template>
<div>
<el-card>
<el-form :model="request" :rules="rules" label-width="auto" ref="request">
<el-form-item :label="$t('api_test.request.assertions.script_name')" prop="name">
<el-input v-model="request.name" maxlength="200" show-word-limit size="small"/>
</el-form-item>
<el-form-item :label="$t('api_test.definition.api_type')" prop="protocol">
<el-radio v-model="request.protocol" label="HTTP">HTTP</el-radio>
<el-radio v-model="request.protocol" label="DUBBO">DUBBO</el-radio>
<el-radio v-model="request.protocol" label="SQL">SQL</el-radio>
<el-radio v-model="request.protocol" label="TCP">TCP</el-radio>
</el-form-item>
</el-form>
<!--不同协议请求-->
<ms-debug-http-page :current-api="request" @saveAs="editApi" :currentProtocol="request.protocol" v-if="request.protocol==='HTTP'"/>
<ms-debug-jdbc-page :currentProtocol="request.protocol" @saveAs="editApi" :currentProject="currentProject" v-if="request.protocol==='SQL'"/>
<ms-debug-tcp-page :currentProtocol="request.protocol" @saveAs="editApi" :currentProject="currentProject" v-if="request.protocol==='TCP'"/>
<ms-debug-dubbo-page :currentProtocol="request.protocol" @saveAs="editApi" :currentProject="currentProject" v-if="request.protocol==='DUBBO'"/>
</el-card>
</div>
</template>
<script>
import MsDebugHttpPage from "../../definition/components/debug/DebugHttpPage";
import MsDebugJdbcPage from "../../definition/components/debug/DebugJdbcPage";
import MsDebugTcpPage from "../../definition/components/debug/DebugTcpPage";
import MsDebugDubboPage from "../../definition/components/debug/DebugDubboPage";
import {getUUID} from "@/common/js/utils";
export default {
name: "ApiCustomize",
props: {
node: {},
currentProject: {},
request: {},
},
components: {MsDebugHttpPage, MsDebugJdbcPage, MsDebugTcpPage, MsDebugDubboPage},
data() {
return {
loading: false,
rules: {
name: [{required: true, message: this.$t('commons.input_name'), trigger: 'blur'}],
protocol: [{required: true, message: this.$t('commons.please_select'), trigger: 'blur'}],
}
}
},
methods: {
remove() {
this.$emit('remove', this.request, this.node);
},
active(item) {
item.active = !item.active;
this.reload();
},
editApi(row) {
let name = this.request.name;
Object.assign(this.request, JSON.parse(row.request));
this.request.name = name;
this.request.resourceId = getUUID();
this.$emit('addCustomizeApi', this.request);
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
}
}
</script>
<style scoped>
</style>

View File

@ -146,8 +146,13 @@
</el-row>
</div>
<!-- 场景步骤内容 -->
<div style="margin-top: 10px">
<el-tree node-key="id" :data="scenarioDefinition" :allow-drop="allowDrop" @node-drag-end="allowDrag" @node-click="nodeClick" draggable v-loading="isReloadData">
<div style="margin-top: 10px" v-loading="isReloadData">
<el-tree node-key="resourceId" :props="props" :data="scenarioDefinition"
:default-expanded-keys="expandedNode"
:expand-on-click-node="false"
@node-expand="nodeExpand"
@node-collapse="nodeCollapse"
:allow-drop="allowDrop" @node-drag-end="allowDrag" @node-click="nodeClick" v-if="!isReloadData" draggable>
<span class="custom-tree-node father" slot-scope="{ node, data}" style="width: 96%">
<template>
<!-- 场景 -->
@ -177,7 +182,7 @@
<!--提取规则-->
<ms-api-extract @remove="remove" v-if="data.type==='Extract'" customizeStyle="margin-top: 0px" :extract="data" :node="node"/>
<!--API 导入 -->
<ms-api-component :data="data" @remove="remove" current-project="currentProject" v-if="data.type==='API' || data.type==='CASE'" :node="node"/>
<ms-api-component :request="data" @remove="remove" current-project="currentProject" v-if="data.type==='HTTPSamplerProxy'||'DubboSampler'||'JDBCSampler'||'TCPSampler'" :node="node"/>
</template>
</span>
</el-tree>
@ -188,7 +193,7 @@
<el-col :span="3" class="ms-left-cell">
<el-button type="primary" icon="el-icon-refresh" size="small" @click="showAll">{{$t('commons.show_all')}}</el-button>
<br/>
<div v-if="operatingElements.indexOf('API')>0 || operatingElements.indexOf('CASE')>0">
<div v-if="operatingElements.indexOf('HTTPSamplerProxy')>0 || operatingElements.indexOf('DubboSampler')>0 || operatingElements.indexOf('JDBCSampler')>0 || operatingElements.indexOf('TCPSampler')>0 ">
<el-button class="ms-right-buttion" size="small" style="color: #F56C6C;background-color: #FCF1F1" @click="apiListImport">+{{$t('api_test.automation.api_list_import')}}</el-button>
</div>
<div v-if="operatingElements.indexOf('OT_IMPORT')>0">
@ -227,10 +232,16 @@
</div>
<!--接口列表-->
<el-drawer :visible.sync="apiListVisible" direction="ltr" :with-header="false" :modal="false" size="90%">
<el-drawer :visible.sync="apiListVisible" :destroy-on-close="true" direction="ltr" :title="$t('api_test.automation.api_list_import')" :modal="false" size="90%">
<ms-api-definition :visible="true" :currentRow="currentRow"/>
<el-button style="float: right;margin: 20px" @click="addReferenceApi">{{$t('api_test.scenario.reference')}}</el-button>
</el-drawer>
<!--自定义接口-->
<el-drawer :visible.sync="customizeVisible" :destroy-on-close="true" direction="ltr" :title="$t('api_test.automation.customize_req')" style="overflow: auto" :modal="false" size="90%">
<ms-api-customize :request="customizeRequest" @addCustomizeApi="addCustomizeApi" :current-project="currentProject"/>
<!--<el-button style="float: right;margin: 20px" @click="addCustomizeApi">{{$t('commons.save')}}</el-button>-->
</el-drawer>
</div>
</el-card>
</template>
@ -249,7 +260,8 @@
import MsApiDefinition from "../../definition/ApiDefinition";
import MsApiComponent from "./ApiComponent";
import {ELEMENTS, ELEMENT_TYPE} from "./Setting";
import MsApiCustomize from "./ApiCustomize";
import {getUUID} from "@/common/js/utils";
export default {
name: "EditApiScenario",
@ -257,9 +269,13 @@
moduleOptions: Array,
currentProject: {}
},
components: {MsJsr233Processor, MsConstantTimer, MsIfController, MsApiAssertions, MsApiExtract, MsApiDefinition, MsApiComponent},
components: {MsJsr233Processor, MsConstantTimer, MsIfController, MsApiAssertions, MsApiExtract, MsApiDefinition, MsApiComponent, MsApiCustomize},
data() {
return {
props: {
label: "label",
children: "hashTree"
},
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
@ -277,10 +293,13 @@
scenario: {},
isReloadData: false,
apiListVisible: false,
customizeVisible: false,
customizeRequest: {protocol: "HTTP", type: "API", hashTree: [], referenced: false, active: false},
operatingElements: [],
currentRow: {cases: [], apis: []},
selectedTreeNode: undefined,
scenarioDefinition: [{index: 1, id: "xx", type: "scenario", name: "test", children: []}, {index: 2, id: "2", type: "ConstantTimer", children: []}]
expandedNode: [],
scenarioDefinition: []
}
},
created() {
@ -290,9 +309,9 @@
watch: {},
methods: {
nodeClick(e) {
console.log(e)
this.operatingElements = ELEMENTS.get(e.type);
this.selectedTreeNode = e;
this.reload();
},
showAll() {
this.operatingElements = ELEMENTS.get("ALL");
@ -305,37 +324,51 @@
addComponent(type) {
switch (type) {
case ELEMENT_TYPE.IfController:
this.selectedTreeNode != undefined ? this.selectedTreeNode.children.push(new IfController()) :
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new IfController()) :
this.scenarioDefinition.push(new IfController());
break;
case ELEMENT_TYPE.ConstantTimer:
this.selectedTreeNode != undefined ? this.selectedTreeNode.children.push(new ConstantTimer()) :
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new ConstantTimer()) :
this.scenarioDefinition.push(new ConstantTimer());
break;
case ELEMENT_TYPE.JSR223Processor:
this.selectedTreeNode != undefined ? this.selectedTreeNode.children.push(new JSR223Processor()) :
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new JSR223Processor()) :
this.scenarioDefinition.push(new JSR223Processor());
break;
case ELEMENT_TYPE.JSR223PreProcessor:
this.selectedTreeNode != undefined ? this.selectedTreeNode.children.push(new JSR223Processor({type: "JSR223PreProcessor"})) :
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PreProcessor"})) :
this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PreProcessor"}));
break;
case ELEMENT_TYPE.JSR223PostProcessor:
this.selectedTreeNode != undefined ? this.selectedTreeNode.children.push(new JSR223Processor({type: "JSR223PostProcessor"})) :
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new JSR223Processor({type: "JSR223PostProcessor"})) :
this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PostProcessor"}));
break;
case ELEMENT_TYPE.Assertions:
this.selectedTreeNode != undefined ? this.selectedTreeNode.children.push(new Assertions()) :
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new Assertions()) :
this.scenarioDefinition.push(new Assertions());
break;
case ELEMENT_TYPE.Extract:
this.selectedTreeNode != undefined ? this.selectedTreeNode.children.push(new Extract()) :
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new Extract()) :
this.scenarioDefinition.push(new Extract());
break;
case ELEMENT_TYPE.CustomizeReq:
this.customizeRequest = {protocol: "HTTP", type: "API", hashTree: [], referenced: false, active: false};
this.customizeVisible = true;
break;
default:
break;
}
this.reload();
},
addCustomizeApi(request) {
this.customizeVisible = false;
if (this.selectedTreeNode != undefined) {
this.selectedTreeNode.hashTree.push(request);
} else {
this.scenarioDefinition.push(request);
}
this.customizeRequest = {};
this.reload();
},
addReferenceApi() {
if (this.currentRow.cases.length === 0 && this.currentRow.apis.length === 0) {
@ -343,22 +376,37 @@
return;
}
this.currentRow.cases.forEach(item => {
item.referenced = true;
item.active = false;
if (this.selectedTreeNode != undefined) {
this.selectedTreeNode.children.push(item);
let request = {};
if (Object.prototype.toString.call(item.request).indexOf("String") > 0) {
request = JSON.parse(item.request);
} else {
this.scenarioDefinition.push(item);
request = item.request;
}
request.referenced = true;
request.active = false;
request.resourceId = getUUID();
if (this.selectedTreeNode != undefined) {
this.selectedTreeNode.hashTree.push(request);
} else {
this.scenarioDefinition.push(request);
}
})
this.currentRow.apis.forEach(item => {
item.referenced = true;
item.active = false;
item.request = JSON.parse(item.request);
if (this.selectedTreeNode != undefined) {
this.selectedTreeNode.children.push(item);
let request = {};
if (Object.prototype.toString.call(item.request).indexOf("String") > 0) {
request = JSON.parse(item.request);
} else {
this.scenarioDefinition.push(item);
request = item.request;
}
request.referenced = true;
request.active = false;
request.resourceId = getUUID();
if (this.selectedTreeNode != undefined) {
this.selectedTreeNode.hashTree.push(request);
} else {
this.scenarioDefinition.push(request);
}
})
this.apiListVisible = false;
@ -405,9 +453,9 @@
},
remove(row, node) {
const parent = node.parent
const children = parent.data.children || parent.data;
const index = children.findIndex(d => d.id != undefined && row.id != undefined && d.id === row.id)
children.splice(index, 1);
const hashTree = parent.data.hashTree || parent.data;
const index = hashTree.findIndex(d => d.id != undefined && row.id != undefined && d.id === row.id)
hashTree.splice(index, 1);
this.reload();
},
reload() {
@ -471,6 +519,16 @@
allowDrag() {
},
nodeExpand(data) {
if (data.resourceId) {
this.expandedNode.push(data.resourceId);
}
},
nodeCollapse(data) {
if (data.resourceId) {
this.expandedNode.splice(this.expandedNode.indexOf(data.resourceId), 1);
}
},
}
}
</script>
@ -517,4 +575,8 @@
padding: 15px;
}
/deep/ .el-drawer__body {
overflow: auto;
}
</style>

View File

@ -3,13 +3,13 @@
<el-row>
<div>
<el-button class="ms-left-buttion" size="small" :style="styleType" style="color: #B8741A;background-color: #F9F1EA">{{title}}</el-button>
<i class="icon el-icon-arrow-right" :class="{'is-active': active}" @click="changeActive" style="margin-left: 20px"/>
<i class="icon el-icon-arrow-right" :class="{'is-active': this.jsr223ProcessorData.active}" @click="changeActive" style="margin-left: 20px"/>
<el-input size="small" v-model="jsr223ProcessorData.name" class="ms-api-header-select" style="width: 380px"/>
<el-button size="small" style="float: right" @click="remove">移除</el-button>
</div>
</el-row>
<el-collapse-transition>
<div v-if="active">
<div v-if="jsr223ProcessorData.active">
<el-row style="margin:0px 10px 10px">
<el-col>
<div class="document-url">
@ -51,7 +51,6 @@
components: {MsDropdown, MsInstructionsIcon, MsCodeEdit},
data() {
return {
active: false,
jsr223ProcessorData: {},
codeTemplates: [
{
@ -135,7 +134,7 @@
this.reload();
},
remove() {
this.$emit('remove', this.jsr223ProcessorData,this.node);
this.$emit('remove', this.jsr223ProcessorData, this.node);
},
reload() {
this.isCodeEditAlive = false;
@ -145,7 +144,7 @@
this.jsr223ProcessorData.language = language;
},
changeActive() {
this.active = !this.active;
this.jsr223ProcessorData.active = !this.jsr223ProcessorData.active;
},
}
}

View File

@ -1,8 +1,10 @@
export const ELEMENTS = new Map([
['ALL', ["scenario", "API", "CASE", "OT_IMPORT", "IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract", "CustomizeReq"]],
['ALL', ["scenario", "HTTPSamplerProxy", "DubboSampler","JDBCSampler","TCPSampler","OT_IMPORT", "IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract", "CustomizeReq"]],
['scenario', ["API", "CASE", "OT_IMPORT", "IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract", "CustomizeReq"]],
['API', ["IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['CASE', ["IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['HTTPSamplerProxy', ["IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['DubboSampler', ["IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['JDBCSampler', ["IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['TCPSampler', ["IfController", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract"]],
['OT_IMPORT', []],
['IfController', ["API", "CASE", "OT_IMPORT", "ConstantTimer", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract", "CustomizeReq"]],
['ConstantTimer', ["API", "CASE", "OT_IMPORT", "IfController", "JSR223Processor", "JSR223PreProcessor", "JSR223PostProcessor", "Assertions", "Extract", "CustomizeReq"]],
@ -16,8 +18,7 @@ export const ELEMENTS = new Map([
export const ELEMENT_TYPE = {
scenario: "scenario",
API: "API",
CASE: "CASE",
HTTPSamplerProxy: "HTTPSamplerProxy",
OT_IMPORT: "OT_IMPORT",
IfController: "IfController",
ConstantTimer: "ConstantTimer",

View File

@ -461,7 +461,6 @@
},
caseChecked(row) {
row.type = "CASE";
row.protocol = this.api.protocol;
row.hashTree = [];
if (this.checkedCases.has(row)) {

View File

@ -197,7 +197,6 @@
});
},
handleSelect(selection, row) {
row.type = "API";
row.hashTree = [];
if (this.selectRows.has(row)) {
this.$set(row, "showMore", false);
@ -206,7 +205,6 @@
this.$set(row, "showMore", true);
this.selectRows.add(row);
}
let arr = Array.from(this.selectRows);
if (this.currentRow) {
this.currentRow.apis = arr;
@ -223,12 +221,10 @@
handleSelectAll(selection) {
if (selection.length > 0) {
if (selection.length === 1) {
selection.type = "API";
selection.hashTree = [];
this.selectRows.add(selection[0]);
} else {
this.tableData.forEach(item => {
item.type = "API";
item.hashTree = [];
this.$set(item, "showMore", true);
this.selectRows.add(item);