feat(接口自动化): 完善步骤实时结果

This commit is contained in:
fit2-zhao 2021-06-28 11:30:24 +08:00 committed by fit2-zhao
parent 74e8c81457
commit f4ac3e1860
14 changed files with 548 additions and 599 deletions

View File

@ -137,13 +137,13 @@
<el-checkbox v-model="onSampleError">{{ $t('commons.failure_continues') }}</el-checkbox>
</el-col>
<el-col :span="8">
<div style=" float: right">
<div style="float: right;width: 300px">
<env-popover :disabled="scenarioDefinition.length < 1" :env-map="projectEnvMap"
:project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap" :result="envResult"
:show-config-button-with-out-permission="showConfigButtonWithOutPermission"
:isReadOnly="scenarioDefinition.length < 1" @showPopover="showPopover"
:project-list="projectList" ref="envPopover" style="margin-right: 10px"/>
<el-dropdown split-button type="primary" @click="runDebug" style="margin-right: 10px" size="mini" @command="handleCommand" v-if="!debugLoading">
:project-list="projectList" ref="envPopover" class="ms-message-right"/>
<el-dropdown split-button type="primary" @click="runDebug" class="ms-message-right" size="mini" @command="handleCommand" v-if="!debugLoading">
{{ $t('api_test.request.debug') }}
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>{{ $t('test_track.case.steps') }}</el-dropdown-item>
@ -177,7 +177,10 @@
<font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" v-prevent-re-click @click="disableAll"/>
</el-tooltip>
<div class="ms-debug-result" v-if="debug">
{{ reqTotalTime }} ms 请求 {{ reqTotal }} 成功 {{ reqSuccess }} 失败 {{ reqError }}
<span class="ms-message-right"> {{ reqTotalTime }} ms </span>
<span class="ms-message-right">{{$t('api_test.automation.request_total')}} {{ reqTotal }}</span>
<span class="ms-message-right">{{$t('api_test.automation.request_success')}} {{ reqSuccess }}</span>
<span class="ms-message-right"> {{$t('api_test.automation.request_error')}} {{ reqError }}</span>
</div>
<el-tree node-key="resourceId" :props="props" :data="scenarioDefinition" class="ms-tree"
:default-expanded-keys="expandedNode"
@ -837,8 +840,6 @@ export default {
if (this.scenarioDefinition.length < 1) {
return;
}
this.debug = true;
this.debugLoading = true;
this.stopDebug = "";
this.clearDebug();
/*触发执行操作*/
@ -867,6 +868,8 @@ export default {
onSampleError: this.onSampleError,
};
this.reportId = getUUID().substring(0, 8);
this.debug = true;
this.debugLoading = true;
})
})
}
@ -1405,4 +1408,8 @@ export default {
.ms-open-btn-left {
margin-left: 35px;
}
.ms-message-right {
margin-right: 10px;
}
</style>

View File

@ -21,11 +21,9 @@
<span class="ms-tag">{{ getProjectName(request.projectId) }}</span>
</template>
<template v-slot:debugStepCode>
<el-tooltip :content="request.requestResult.responseResult.responseCode" v-if="request.debug && request.requestResult && request.requestResult.responseResult">
<span class="ms-step-debug-code" :class="request.requestResult.success?'ms-req-success':'ms-req-error'">
{{ request.requestResult.responseResult.responseCode }}
</span>
</el-tooltip>
<span class="ms-step-debug-code" :class="request.requestResult.success?'ms-req-success':'ms-req-error'" v-if="request.debug && request.requestResult && request.requestResult.responseResult">
{{ request.requestResult.success ? 'success' : 'error' }}
</span>
</template>
<template v-slot:button>
<el-tooltip :content="$t('api_test.run')" placement="top">
@ -83,7 +81,7 @@
:show-options-button="false" :show-header="true" :result="request.requestResult"/>
</div>
<div v-else>
<api-response-component :currentProtocol="request.protocol" :result="request.requestResult"/>
<api-response-component :currentProtocol="request.protocol" :apiActive="apiActive" :result="request.requestResult"/>
</div>
<!-- 保存操作 -->
<el-button type="primary" size="small" class="ms-btn-flot" @click="saveTestCase(item)" v-if="!request.referenced">
@ -154,6 +152,7 @@ export default {
showXpackCompnent: false,
environment: {},
result: {},
apiActive: false,
}
},
created() {
@ -372,18 +371,19 @@ export default {
this.expandedNode.splice(this.expandedNode.indexOf(this.request.resourceId), 1);
}
}
this.apiActive = this.request.active;
this.reload();
},
run() {
if (this.isApiImport || this.request.isRefEnvironment) {
if (this.request.type && (this.request.type === "HTTPSamplerProxy" || this.request.type === "JDBCSampler" || this.request.type === "TCPSampler")) {
if (!this.envMap || this.envMap.size === 0) {
this.$warning("请在环境配置中为该步骤所属项目选择运行环境!");
this.$warning(this.$t('api_test.automation.env_message'));
return false;
} else if (this.envMap && this.envMap.size > 0) {
const env = this.envMap.get(this.request.projectId);
if (!env) {
this.$warning("请在环境配置中为该步骤所属项目选择运行环境!");
this.$warning(this.$t('api_test.automation.env_message'));
return false;
}
}
@ -480,7 +480,7 @@ export default {
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 100px;
width: 60px;
}
.ms-req-error {

View File

@ -24,7 +24,7 @@ import MsRequestMetric from "../../../definition/components/response/RequestMetr
export default {
name: "ApiResponseComponent",
components: {ElCollapseTransition, MsRequestResultTail, ApiBaseComponent, MsRequestMetric},
props: {apiItem: {}, result: {}, currentProtocol: String},
props: {apiItem: {}, result: {}, currentProtocol: String, apiActive:{type:Boolean,default:false}},
data() {
return {
isActive: false,
@ -41,6 +41,9 @@ export default {
this.response = this.result;
// this.isActive = true;
}
if(this.apiActive){
this.isActive = true
}
},
watch: {
result() {

View File

@ -23,11 +23,9 @@
<span class="ms-tag">{{ getProjectName(scenario.projectId) }}</span>
</template>
<template v-slot:debugStepCode>
<el-tooltip :content="getCode()" v-if="node.data.debug">
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'">
{{ getCode() }}
</span>
</el-tooltip>
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'" v-if="node.data.debug">
{{ getCode() }}
</span>
</template>
</api-base-component>
@ -206,4 +204,15 @@ export default {
.ms-req-success {
color: #67C23A;
}
.ms-step-debug-code {
display: inline-block;
margin: 0 5px;
overflow-x: hidden;
padding-bottom: 0;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 60px;
}
</style>

View File

@ -24,11 +24,9 @@
</template>
<template v-slot:debugStepCode>
<el-tooltip :content="getCode()" v-if="node.data.debug">
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'">
{{ getCode() }}
</span>
</el-tooltip>
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'" v-if="node.data.debug">
{{ getCode() }}
</span>
</template>
</api-base-component>
</template>
@ -143,4 +141,14 @@
.ms-req-success {
color: #67C23A;
}
.ms-step-debug-code {
display: inline-block;
margin: 0 5px;
overflow-x: hidden;
padding-bottom: 0;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 100px;
}
</style>

View File

@ -13,6 +13,13 @@
<div style="height: 300px;width: 100%">
<ms-code-edit mode="xml" :data.sync="request.jmeterElement" theme="eclipse" ref="codeEdit"/>
</div>
<template v-slot:debugStepCode>
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'" v-if="node.data.debug">
{{ getCode() }}
</span>
</template>
</api-base-component>
</template>
@ -53,6 +60,16 @@
node: {},
},
methods: {
getCode() {
if (this.node && this.node.data.debug) {
if (this.node.data.code && this.node.data.code === 'error') {
return 'error';
} else {
return 'success';
}
}
return '';
},
remove() {
this.$emit('remove', this.request, this.node);
},
@ -73,4 +90,21 @@
/deep/ .el-divider {
margin-bottom: 10px;
}
.ms-req-error {
color: #F56C6C;
}
.ms-req-success {
color: #67C23A;
}
.ms-step-debug-code {
display: inline-block;
margin: 0 5px;
overflow-x: hidden;
padding-bottom: 0;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 100px;
}
</style>

View File

@ -5,9 +5,9 @@
<template v-slot:headerLeft>
<i class="icon el-icon-arrow-right" :class="{'is-active': controller.active}" style="margin-right: 10px" v-if="!isMax"/>
<el-radio @change="changeRadio" class="ms-radio ms-radio-margin" v-model="controller.loopType" label="LOOP_COUNT">{{$t('loop.loops_title')}}</el-radio>
<el-radio @change="changeRadio" class="ms-radio ms-radio-margin" v-model="controller.loopType" label="FOREACH">{{$t('loop.foreach')}}</el-radio>
<el-radio @change="changeRadio" class="ms-radio ms-radio-margin" v-model="controller.loopType" label="WHILE">{{$t('loop.while')}}</el-radio>
<el-radio @change="changeRadio" class="ms-radio ms-radio-margin" v-model="controller.loopType" label="LOOP_COUNT">{{ $t('loop.loops_title') }}</el-radio>
<el-radio @change="changeRadio" class="ms-radio ms-radio-margin" v-model="controller.loopType" label="FOREACH">{{ $t('loop.foreach') }}</el-radio>
<el-radio @change="changeRadio" class="ms-radio ms-radio-margin" v-model="controller.loopType" label="WHILE">{{ $t('loop.while') }}</el-radio>
</template>
<template v-slot:message>
@ -22,17 +22,17 @@
<div v-if="controller.loopType==='LOOP_COUNT'" draggable>
<el-row>
<el-col :span="8">
<span class="ms-span ms-radio">{{$t('loop.loops')}}</span>
<span class="ms-span ms-radio">{{ $t('loop.loops') }}</span>
<el-input-number size="small" v-model="controller.countController.loops" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0"/>
<span class="ms-span ms-radio"></span>
</el-col>
<el-col :span="8">
<span class="ms-span ms-radio">{{$t('loop.interval')}}</span>
<span class="ms-span ms-radio">{{ $t('loop.interval') }}</span>
<el-input-number size="small" v-model="controller.countController.interval" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</el-col>
<el-col :span="8">
<span class="ms-span ms-radio">{{$t('loop.proceed')}}</span>
<span class="ms-span ms-radio">{{ $t('loop.proceed') }}</span>
<el-tooltip class="item" effect="dark" :content="$t('api_test.automation.loop_content')" placement="top">>
<el-switch v-model="controller.countController.proceed" @change="switchChange"/>
@ -53,7 +53,7 @@
<el-input :placeholder="$t('api_test.automation.loop_input_val')" v-model="controller.forEachController.inputVal" size="small"/>
</el-col>
<el-col :span="7">
<span class="ms-span ms-radio">{{$t('loop.interval')}}</span>
<span class="ms-span ms-radio">{{ $t('loop.interval') }}</span>
<el-input-number size="small" v-model="controller.forEachController.interval" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</el-col>
@ -65,17 +65,15 @@
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value"/>
</el-select>
<el-input size="small" v-model="controller.whileController.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" style="width: 20%;margin-left: 20px"/>
<span class="ms-span ms-radio">{{$t('loop.timeout')}}</span>
<span class="ms-span ms-radio">{{ $t('loop.timeout') }}</span>
<el-input-number size="small" v-model="controller.whileController.timeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="3000" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</div>
<template v-slot:debugStepCode>
<el-tooltip :content="getCode()" v-if="node.data.debug">
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'">
{{ getCode() }}
</span>
</el-tooltip>
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'" v-if="node.data.debug">
{{ getCode() }}
</span>
</template>
</api-base-component>
@ -83,313 +81,325 @@
</template>
<script>
import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent";
import MsRun from "../DebugRun";
import {getUUID} from "@/common/js/utils";
import {ELEMENT_TYPE, ELEMENTS} from "../Setting";
import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent";
import MsRun from "../DebugRun";
import {getUUID} from "@/common/js/utils";
import {ELEMENT_TYPE, ELEMENTS} from "../Setting";
export default {
name: "MsLoopController",
components: {ApiBaseComponent, ApiResponseComponent, MsRun},
props: {
controller: {},
currentEnvironmentId: String,
currentScenario: {},
node: {},
isMax: {
type: Boolean,
default: false,
},
showBtn: {
type: Boolean,
default: true,
},
index: Object,
draggable: {
type: Boolean,
default: false,
},
envMap: Map,
export default {
name: "MsLoopController",
components: {ApiBaseComponent, ApiResponseComponent, MsRun},
props: {
controller: {},
currentEnvironmentId: String,
currentScenario: {},
node: {},
isMax: {
type: Boolean,
default: false,
},
data() {
return {
loading: false,
activeName: "first",
requestResult: {responseResult: {}},
success: 0,
error: 0,
debugData: {},
report: [],
reportId: "",
operators: {
EQ: {
label: "commons.adv_search.operators.equals",
value: "==",
},
NE: {
label: "commons.adv_search.operators.not_equals",
value: "!=",
},
LIKE: {
label: "commons.adv_search.operators.like",
value: "=~",
},
NOT_LIKE: {
label: "commons.adv_search.operators.not_like",
value: "!~",
},
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",
},
showBtn: {
type: Boolean,
default: true,
},
index: Object,
draggable: {
type: Boolean,
default: false,
},
envMap: Map,
},
data() {
return {
loading: false,
activeName: "first",
requestResult: {responseResult: {}},
success: 0,
error: 0,
debugData: {},
report: [],
reportId: "",
operators: {
EQ: {
label: "commons.adv_search.operators.equals",
value: "==",
},
};
NE: {
label: "commons.adv_search.operators.not_equals",
value: "!=",
},
LIKE: {
label: "commons.adv_search.operators.like",
value: "=~",
},
NOT_LIKE: {
label: "commons.adv_search.operators.not_like",
value: "!~",
},
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",
},
},
};
},
methods: {
getCode() {
if (this.node && this.node.data.debug) {
if (this.node.data.code && this.node.data.code === 'error') {
return 'error';
} else {
return 'success';
}
}
return '';
},
methods: {
getCode() {
if (this.node && this.node.data.debug) {
if (this.node.data.code && this.node.data.code === 'error') {
return 'error';
} else {
return 'success';
}
initResult() {
if (this.controller) {
switch (this.controller.loopType) {
case "LOOP_COUNT":
this.requestResult = this.controller.countController && this.controller.countController.requestResult ? this.controller.countController.requestResult : {};
break;
case "FOREACH":
this.requestResult = this.controller.forEachController && this.controller.forEachController.requestResult ? this.controller.forEachController.requestResult : {};
break;
case "WHILE":
this.requestResult = this.controller.whileController && this.controller.whileController.requestResult ? this.controller.whileController.requestResult : {};
break;
default:
break;
}
return '';
},
initResult() {
if (this.controller) {
switch (this.controller.loopType) {
case "LOOP_COUNT":
this.requestResult = this.controller.countController && this.controller.countController.requestResult ? this.controller.countController.requestResult : {};
break;
case "FOREACH":
this.requestResult = this.controller.forEachController && this.controller.forEachController.requestResult ? this.controller.forEachController.requestResult : {};
break;
case "WHILE":
this.requestResult = this.controller.whileController && this.controller.whileController.requestResult ? this.controller.whileController.requestResult : {};
break;
default:
break;
}
this.getFails();
this.activeName = this.requestResult && this.requestResult.scenarios && this.requestResult.scenarios.length > 0 ? this.requestResult.scenarios[0].name : "";
},
switchChange() {
if (this.controller.hashTree && this.controller.hashTree.length > 1) {
this.$warning(this.$t('api_test.automation.loop_message'));
this.controller.countController.proceed = true;
return;
}
//
if (this.controller.hashTree && this.controller.hashTree.length === 1 && this.controller.hashTree[0].hashTree && this.controller.hashTree[0].hashTree.length > 0) {
let count = 0;
this.controller.hashTree[0].hashTree.forEach((item) => {
if (ELEMENTS.get("AllSamplerProxy").indexOf(item.type) !== -1) {
count++;
}
}
this.getFails();
this.activeName = this.requestResult && this.requestResult.scenarios && this.requestResult.scenarios.length > 0 ? this.requestResult.scenarios[0].name : "";
},
switchChange() {
if (this.controller.hashTree && this.controller.hashTree.length > 1) {
if (item.hashTree && item.hashTree.length > 0) {
this.recursive(item.hashTree, count);
}
});
if (count > 1) {
this.$warning(this.$t('api_test.automation.loop_message'));
this.controller.countController.proceed = true;
return;
}
//
if (this.controller.hashTree && this.controller.hashTree.length === 1 && this.controller.hashTree[0].hashTree && this.controller.hashTree[0].hashTree.length > 0) {
let count = 0;
this.controller.hashTree[0].hashTree.forEach((item) => {
if (ELEMENTS.get("AllSamplerProxy").indexOf(item.type) !== -1) {
count++;
}
if (item.hashTree && item.hashTree.length > 0) {
this.recursive(item.hashTree, count);
}
});
}
},
recursive(arr, count) {
for (let i in arr) {
if (ELEMENTS.get("AllSamplerProxy").indexOf(arr[i].type) !== -1) {
count++;
}
if (arr[i].hashTree && arr[i].hashTree.length > 0) {
this.recursive(arr[i].hashTree, count);
}
}
},
if (count > 1) {
this.$warning(this.$t('api_test.automation.loop_message'));
this.controller.countController.proceed = true;
return;
}
}
},
recursive(arr, count) {
for (let i in arr) {
if (ELEMENTS.get("AllSamplerProxy").indexOf(arr[i].type) !== -1) {
count++;
}
if (arr[i].hashTree && arr[i].hashTree.length > 0) {
this.recursive(arr[i].hashTree, count);
}
}
},
runDebug() {
if (!this.controller.hashTree || this.controller.hashTree.length < 1) {
this.$warning("当前循环下没有请求,不能执行");
return;
}
this.loading = true;
this.debugData = {
id: this.currentScenario.id,
name: this.currentScenario.name,
type: "scenario",
variables: this.currentScenario.variables,
headers: this.currentScenario.headers,
referenced: "Created",
enableCookieShare: this.enableCookieShare,
environmentId: this.currentEnvironmentId,
hashTree: [this.controller],
};
this.reportId = getUUID().substring(0, 8);
},
runDebug() {
if (!this.controller.hashTree || this.controller.hashTree.length < 1) {
this.$warning("当前循环下没有请求,不能执行");
return;
}
this.loading = true;
this.debugData = {
id: this.currentScenario.id,
name: this.currentScenario.name,
type: "scenario",
variables: this.currentScenario.variables,
headers: this.currentScenario.headers,
referenced: "Created",
enableCookieShare: this.enableCookieShare,
environmentId: this.currentEnvironmentId,
hashTree: [this.controller],
};
this.reportId = getUUID().substring(0, 8);
},
remove() {
this.$emit("remove", this.controller, this.node);
},
copyRow() {
this.$emit("copyRow", this.controller, this.node);
},
active(item) {
item.active = !item.active;
if (this.node) {
this.node.expanded = item.active;
}
this.reload();
},
changeRadio() {
this.controller.active = true;
this.reload();
},
change(value) {
if (value.indexOf("empty") > 0 && !!this.controller.value) {
this.controller.value = "";
}
},
reload() {
this.loading = true;
this.$nextTick(() => {
this.loading = false;
});
},
runRefresh() {
this.getReport();
},
getFails() {
this.error = 0;
this.success = 0;
if (this.requestResult.scenarios && this.requestResult.scenarios !== null) {
this.requestResult.scenarios.forEach((scenario) => {
if (scenario.requestResults) {
scenario.requestResults.forEach((item) => {
if (item.error > 0) {
this.error++;
return;
}
});
}
});
this.success = this.requestResult.scenarios && this.requestResult.scenarios !== null ? this.requestResult.scenarios.length - this.error : 0;
}
},
setResult(hashTree) {
if (hashTree) {
hashTree.forEach((item) => {
if (item.type === "HTTPSamplerProxy" || item.type === "DubboSampler" || item.type === "JDBCSampler" || item.type === "TCPSampler") {
item.result = this.requestResult;
item.activeName = this.activeName;
item.active = true;
item.requestResult = undefined;
}
if (item.hashTree && item.hashTree.length > 0) {
this.setResult(item.hashTree);
}
});
}
},
getReport() {
if (this.reportId) {
let url = "/api/scenario/report/get/" + this.reportId;
this.$get(url, (response) => {
this.report = response.data || {};
if (response.data) {
if (this.isNotRunning) {
try {
this.requestResult = JSON.parse(this.report.content);
if (!this.requestResult) {
this.requestResult = {scenarios: []};
}
this.controller.requestResult = this.requestResult;
switch (this.controller.loopType) {
case "LOOP_COUNT":
this.controller.countController.requestResult = this.requestResult;
break;
case "FOREACH":
this.controller.forEachController.requestResult = this.requestResult;
break;
case "WHILE":
this.controller.whileController.requestResult = this.requestResult;
break;
default:
break;
}
this.getFails();
this.activeName = this.requestResult && this.requestResult.scenarios && this.requestResult.scenarios !== null && this.requestResult.scenarios.length > 0 ? this.requestResult.scenarios[0].name : "";
//
this.setResult(this.controller.hashTree);
this.$emit("refReload", this.node);
} catch (e) {
throw e;
}
this.loading = false;
this.node.expanded = true;
this.reload();
} else {
setTimeout(this.getReport, 2000);
remove() {
this.$emit("remove", this.controller, this.node);
},
copyRow() {
this.$emit("copyRow", this.controller, this.node);
},
active(item) {
item.active = !item.active;
if (this.node) {
this.node.expanded = item.active;
}
this.reload();
},
changeRadio() {
this.controller.active = true;
this.reload();
},
change(value) {
if (value.indexOf("empty") > 0 && !!this.controller.value) {
this.controller.value = "";
}
},
reload() {
this.loading = true;
this.$nextTick(() => {
this.loading = false;
});
},
runRefresh() {
this.getReport();
},
getFails() {
this.error = 0;
this.success = 0;
if (this.requestResult.scenarios && this.requestResult.scenarios !== null) {
this.requestResult.scenarios.forEach((scenario) => {
if (scenario.requestResults) {
scenario.requestResults.forEach((item) => {
if (item.error > 0) {
this.error++;
return;
}
});
}
});
this.success = this.requestResult.scenarios && this.requestResult.scenarios !== null ? this.requestResult.scenarios.length - this.error : 0;
}
},
setResult(hashTree) {
if (hashTree) {
hashTree.forEach((item) => {
if (item.type === "HTTPSamplerProxy" || item.type === "DubboSampler" || item.type === "JDBCSampler" || item.type === "TCPSampler") {
item.result = this.requestResult;
item.activeName = this.activeName;
item.active = true;
item.requestResult = undefined;
}
if (item.hashTree && item.hashTree.length > 0) {
this.setResult(item.hashTree);
}
});
}
},
getReport() {
if (this.reportId) {
let url = "/api/scenario/report/get/" + this.reportId;
this.$get(url, (response) => {
this.report = response.data || {};
if (response.data) {
if (this.isNotRunning) {
try {
this.requestResult = JSON.parse(this.report.content);
if (!this.requestResult) {
this.requestResult = {scenarios: []};
}
this.controller.requestResult = this.requestResult;
switch (this.controller.loopType) {
case "LOOP_COUNT":
this.controller.countController.requestResult = this.requestResult;
break;
case "FOREACH":
this.controller.forEachController.requestResult = this.requestResult;
break;
case "WHILE":
this.controller.whileController.requestResult = this.requestResult;
break;
default:
break;
}
this.getFails();
this.activeName = this.requestResult && this.requestResult.scenarios && this.requestResult.scenarios !== null && this.requestResult.scenarios.length > 0 ? this.requestResult.scenarios[0].name : "";
//
this.setResult(this.controller.hashTree);
this.$emit("refReload", this.node);
} catch (e) {
throw e;
}
} else {
this.loading = false;
this.$error(this.$t("api_report.not_exist"));
this.node.expanded = true;
this.reload();
} else {
setTimeout(this.getReport, 2000);
}
});
}
},
} else {
this.loading = false;
this.$error(this.$t("api_report.not_exist"));
}
});
}
},
computed: {
hasEmptyOperator() {
return !!this.controller.operator && this.controller.operator.indexOf("empty") > 0;
},
isNotRunning() {
return "Running" !== this.report.status;
},
},
computed: {
hasEmptyOperator() {
return !!this.controller.operator && this.controller.operator.indexOf("empty") > 0;
},
};
isNotRunning() {
return "Running" !== this.report.status;
},
},
};
</script>
<style scoped>
.ms-span {
margin: 10px;
}
.ms-span {
margin: 10px;
}
.ms-radio {
color: #606266;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
font-weight: normal;
}
.ms-radio {
color: #606266;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
font-weight: normal;
}
.icon.is-active {
transform: rotate(90deg);
}
.ms-req-error {
color: #F56C6C;
}
.icon.is-active {
transform: rotate(90deg);
}
.ms-req-success {
color: #67C23A;
}
.ms-req-error {
color: #F56C6C;
}
/deep/ .el-radio {
margin-right: 5px;
}
.ms-req-success {
color: #67C23A;
}
/deep/ .el-radio {
margin-right: 5px;
}
.ms-step-debug-code {
display: inline-block;
margin: 0 5px;
overflow-x: hidden;
padding-bottom: 0;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 60px;
}
</style>

View File

@ -10,9 +10,13 @@
color="#6D317C"
background-color="#FCF6EE"
:title="$t('api_test.automation.transcation_controller')">
<template v-slot:debugStepCode>
<span class="ms-step-debug-code" :class="node.data.code ==='error'?'ms-req-error':'ms-req-success'" v-if="node.data.debug">
{{ getCode() }}
</span>
</template>
<template v-slot:headerLeft>
<el-input draggable size="mini" v-model="controller.name" style="width: 20%" :placeholder="$t('api_test.automation.transcation_controller')"/>
<el-checkbox v-model="controller.generateParentSample" style="margin-left: 20px" @change="changeGenerateParantSample">Generate Parent Sample</el-checkbox>
<el-checkbox v-model="controller.includeTimers" @change="changeIncludeTimers">Include Timers</el-checkbox>
@ -22,111 +26,132 @@
</template>
<script>
import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiBaseComponent from "../common/ApiBaseComponent";
export default {
name: "MsTransactionController",
components: {ApiBaseComponent},
props: {
controller: {},
node: {},
isMax: {
type: Boolean,
default: false,
},
showBtn: {
type: Boolean,
default: true,
},
index: Object,
draggable: {
type: Boolean,
default: false,
},
export default {
name: "MsTransactionController",
components: {ApiBaseComponent},
props: {
controller: {},
node: {},
isMax: {
type: Boolean,
default: false,
},
created() {
if(this.controller.generateParentSample == null){
this.controller.generateParentSample = true;
}
if(this.controller.includeTimers == null){
this.controller.includeTimers = true;
}
showBtn: {
type: Boolean,
default: true,
},
data() {
return {
operators: {
EQ: {
label: "commons.adv_search.operators.equals",
value: "=="
},
NE: {
label: "commons.adv_search.operators.not_equals",
value: "!="
},
LIKE: {
label: "commons.adv_search.operators.like",
value: "=~"
},
NOT_LIKE: {
label: "commons.adv_search.operators.not_like",
value: "!~"
},
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"
}
index: Object,
draggable: {
type: Boolean,
default: false,
},
},
created() {
if (this.controller.generateParentSample == null) {
this.controller.generateParentSample = true;
}
if (this.controller.includeTimers == null) {
this.controller.includeTimers = true;
}
},
data() {
return {
operators: {
EQ: {
label: "commons.adv_search.operators.equals",
value: "=="
},
NE: {
label: "commons.adv_search.operators.not_equals",
value: "!="
},
LIKE: {
label: "commons.adv_search.operators.like",
value: "=~"
},
NOT_LIKE: {
label: "commons.adv_search.operators.not_like",
value: "!~"
},
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"
}
}
},
methods: {
remove() {
this.$emit('remove', this.controller, this.node);
},
copyRow() {
this.$emit('copyRow', this.controller, this.node);
},
change(value) {
if (value.indexOf("empty") > 0 && !!this.controller.value) {
this.controller.value = "";
}
},
changeGenerateParantSample(value){
this.controller.generateParentSample = value;
this.$emit('refReload', this.controller, this.controller);
},
changeIncludeTimers(value){
this.controller.includeTimers = value;
this.$emit('refReload', this.controller, this.controller);
},
},
computed: {
hasEmptyOperator() {
return !!this.controller.operator && this.controller.operator.indexOf("empty") > 0;
}
}
},
methods: {
getCode() {
if (this.node && this.node.data.debug) {
if (this.node.data.code && this.node.data.code === 'error') {
return 'error';
} else {
return 'success';
}
}
return '';
},
remove() {
this.$emit('remove', this.controller, this.node);
},
copyRow() {
this.$emit('copyRow', this.controller, this.node);
},
change(value) {
if (value.indexOf("empty") > 0 && !!this.controller.value) {
this.controller.value = "";
}
},
changeGenerateParantSample(value) {
this.controller.generateParentSample = value;
this.$emit('refReload', this.controller, this.controller);
},
changeIncludeTimers(value) {
this.controller.includeTimers = value;
this.$emit('refReload', this.controller, this.controller);
},
},
computed: {
hasEmptyOperator() {
return !!this.controller.operator && this.controller.operator.indexOf("empty") > 0;
}
}
}
</script>
<style scoped>
.ms-btn {
width: 20%;
margin-left: 5px;
}
.ms-btn {
width: 20%;
margin-left: 5px;
}
.ms-select {
width: 15%;
margin-left: 5px;
}
.ms-select {
width: 15%;
margin-left: 5px;
}
.ms-step-debug-code {
display: inline-block;
margin: 0 5px;
overflow-x: hidden;
padding-bottom: 0;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
width: 100px;
}
</style>

View File

@ -18,9 +18,13 @@
<font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" @click="disableAll"/>
</el-tooltip>
<span class="ms-debug-result" v-if="debug">
{{ reqTotalTime }} ms 请求 {{ reqTotal }} 成功 {{ reqSuccess }} 失败 {{ reqError }}
<div class="ms-debug-result" v-if="debug">
<span class="ms-message-right"> {{ reqTotalTime }} ms </span>
<span class="ms-message-right">{{ $t('api_test.automation.request_total') }} {{ reqTotal }}</span>
<span class="ms-message-right">{{ $t('api_test.automation.request_success') }} {{ reqSuccess }}</span>
<span class="ms-message-right"> {{ $t('api_test.automation.request_error') }} {{ reqError }}</span>
</div>
</span>
<el-tree node-key="resourceId"
:props="props"
:data="scenarioDefinition"
@ -141,15 +145,6 @@
<script>
import {API_STATUS, PRIORITY} from "../../../definition/model/JsonData";
import {WORKSPACE_ID} from '@/common/js/constants';
import {
Assertions,
ConstantTimer,
Extract,
IfController,
JSR223Processor,
LoopController
} from "../../../definition/model/ApiTestModel";
import {parseEnvironment} from "../../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "../Setting";
import MsApiCustomize from "../ApiCustomize";
@ -171,6 +166,7 @@ import MsContainer from "../../../../common/components/MsContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import MsAsideContainer from "./MsLeftContainer";
import {saveScenario} from "@/business/components/api/automation/api-automation";
import {buttons, setComponent} from '../menu/Menu';
let jsonPath = require('jsonpath');
export default {
@ -273,119 +269,7 @@ export default {
},
directives: {OutsideClick},
computed: {
buttons() {
let buttons = [
{
title: this.$t('api_test.definition.request.extract_param'),
show: this.showButton("Extract"),
titleColor: "#015478",
titleBgColor: "#E6EEF2",
icon: "colorize",
click: () => {
this.addComponent('Extract')
}
},
{
title: this.$t('api_test.definition.request.post_script'),
show: this.showButton("JSR223PostProcessor"),
titleColor: "#783887",
titleBgColor: "#F2ECF3",
icon: "skip_next",
click: () => {
this.addComponent('JSR223PostProcessor')
}
},
{
title: this.$t('api_test.definition.request.pre_script'),
show: this.showButton("JSR223PreProcessor"),
titleColor: "#B8741A",
titleBgColor: "#F9F1EA",
icon: "skip_previous",
click: () => {
this.addComponent('JSR223PreProcessor')
}
},
{
title: this.$t('api_test.automation.customize_script'),
show: this.showButton("JSR223Processor"),
titleColor: "#7B4D12",
titleBgColor: "#F1EEE9",
icon: "code",
click: () => {
this.addComponent('JSR223Processor')
}
},
{
title: this.$t('api_test.automation.if_controller'),
show: this.showButton("IfController"),
titleColor: "#E6A23C",
titleBgColor: "#FCF6EE",
icon: "alt_route",
click: () => {
this.addComponent('IfController')
}
},
{
title: this.$t('api_test.automation.loop_controller'),
show: this.showButton("LoopController"),
titleColor: "#02A7F0",
titleBgColor: "#F4F4F5",
icon: "next_plan",
click: () => {
this.addComponent('LoopController')
}
},
{
title: this.$t('api_test.automation.wait_controller'),
show: this.showButton("ConstantTimer"),
titleColor: "#67C23A",
titleBgColor: "#F2F9EE",
icon: "access_time",
click: () => {
this.addComponent('ConstantTimer')
}
},
{
title: this.$t('api_test.definition.request.assertions_rule'),
show: this.showButton("Assertions"),
titleColor: "#A30014",
titleBgColor: "#F7E6E9",
icon: "next_plan",
click: () => {
this.addComponent('Assertions')
}
},
{
title: this.$t('api_test.automation.customize_req'),
show: this.showButton("CustomizeReq"),
titleColor: "#008080",
titleBgColor: "#EBF2F2",
icon: "tune",
click: () => {
this.addComponent('CustomizeReq')
}
},
{
title: this.$t('api_test.automation.scenario_import'),
show: this.showButton("scenario"),
titleColor: "#606266",
titleBgColor: "#F4F4F5",
icon: "movie",
click: () => {
this.addComponent('scenario')
}
},
{
title: this.$t('api_test.automation.api_list_import'),
show: this.showButton("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler"),
titleColor: "#F56C6C",
titleBgColor: "#FCF1F1",
icon: "api",
click: this.apiListImport
}
];
return buttons.filter(btn => btn.show);
},
buttons,
projectId() {
return getCurrentProjectID();
},
@ -438,54 +322,7 @@ export default {
return false;
},
addComponent(type) {
switch (type) {
case ELEMENT_TYPE.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.hashTree.push(new ConstantTimer()) :
this.scenarioDefinition.push(new ConstantTimer());
break;
case ELEMENT_TYPE.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.hashTree.push(new JSR223Processor({type: "JSR223PreProcessor"})) :
this.scenarioDefinition.push(new JSR223Processor({type: "JSR223PreProcessor"}));
break;
case ELEMENT_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.hashTree.push(new Assertions()) :
this.scenarioDefinition.push(new Assertions());
break;
case ELEMENT_TYPE.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: 'Created', active: false};
this.customizeVisible = true;
break;
case ELEMENT_TYPE.LoopController:
this.selectedTreeNode != undefined ? this.selectedTreeNode.hashTree.push(new LoopController()) :
this.scenarioDefinition.push(new LoopController());
break;
case ELEMENT_TYPE.scenario:
this.$refs.scenarioRelevance.open();
break;
default:
this.$refs.apiImport.open();
break;
}
if (this.selectedNode) {
this.selectedNode.expanded = true;
}
this.sort();
setComponent(type, this);
},
nodeClick(data, node) {
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled) {
@ -1218,4 +1055,9 @@ export default {
margin-right: 30px;
margin-top: 3px;
}
.ms-message-right {
margin-right: 10px;
}
</style>

View File

@ -34,7 +34,7 @@
.ms-aside-container {
border: 1px solid #E6E6E6;
padding: 10px;
min-width: 650px;
min-width: 690px;
border-radius: 2px;
box-sizing: border-box;
background-color: #FFF;

View File

@ -33,7 +33,6 @@
</el-dropdown>
<el-button icon="el-icon-loading" size="mini" type="primary" :disabled="debug" v-else>执行中</el-button>
<font-awesome-icon class="ms-alt-ico" :icon="['fa', 'compress-alt']" size="lg" @click="unFullScreen"/>
<!-- <i class="el-icon-close alt-ico-close" @click="close"/>-->
</div>
</div>
</template>
@ -191,7 +190,7 @@ export default {
.ms-header-right {
float: right;
width: 540px;
width: 520px;
margin-top: 4px;
z-index: 1;
}

View File

@ -918,6 +918,10 @@ export default {
loop_return_val: "Define variable name",
loop_input_val: "Variable prefix",
loop_message: "There is more than one request in the current cycle and cannot be closed",
env_message: "Please select the operating environment for the project to which this step belongs in the environment configuration",
request_total: "request",
request_success: "success",
request_error: "error",
},
environment: {
create: 'Create environment',

View File

@ -917,6 +917,10 @@ export default {
loop_return_val: "定义变量名称",
loop_input_val: "变量前缀",
loop_message: "当前循环下超过一个请求,不能关闭状态",
env_message: "请在环境配置中为该步骤所属项目选择运行环境",
request_total: "请求",
request_success: "成功",
request_error: "失败",
},
environment: {
create: '创建环境',

View File

@ -778,8 +778,8 @@ export default {
batch_delete: "批量刪除",
delete_confirm: "確認刪除接口",
batch_to_performance_confirm: "確認批量創建性能測試",
batch_copy_confirm:"確認要進行批量複製嗎",
batch_copy_end:"批量複製完成",
batch_copy_confirm: "確認要進行批量複製嗎",
batch_copy_end: "批量複製完成",
delete_case_confirm: "確認刪除用例",
delete_confirm_step: "確認刪除步驟",
assertions_rule: "斷言規則",
@ -871,7 +871,7 @@ export default {
wait_controller: "等待控制器",
if_controller: "條件控制器",
loop_controller: "循環控制器",
transcation_controller:"事務控制器",
transcation_controller: "事務控制器",
scenario_import: "場景導入",
customize_script: "自定義腳本",
customize_req: "自定義請求",
@ -918,6 +918,10 @@ export default {
loop_return_val: "定義變量名稱",
loop_input_val: "變量前綴",
loop_message: "當前循環下超過一個請求,不能關閉狀態",
env_message: "請在環境配置中為該步驟所屬項目選擇運行環境",
request_total: "請求",
request_success: "成功",
request_error: "失敗",
},
environment: {
create: '創建環境',