feat(接口自动化): 获取实时执行步骤结果

This commit is contained in:
fit2-zhao 2021-06-25 19:06:06 +08:00 committed by fit2-zhao
parent fe677b0b40
commit 6743dac777
11 changed files with 820 additions and 577 deletions

View File

@ -62,4 +62,9 @@ public class APIScenarioReportController {
return resultService.getResult(reportId); return resultService.getResult(reportId);
} }
@GetMapping("/remove/real/{reportId}")
public void removeRealReport(@PathVariable String reportId) {
resultService.delete(reportId);
}
} }

View File

@ -39,7 +39,9 @@ public class MsResultService {
testResult = new TestResult(); testResult = new TestResult();
} }
if (result.getResponseCode().equals(MsResultCollector.TEST_END)) { if (result.getResponseCode().equals(MsResultCollector.TEST_END)) {
testResult.setEnd(true);
this.cache.put(key, testResult);
return;
} }
testResult.setTestId(key); testResult.setTestId(key);
testResult.setConsole(getJmeterLogger(key, false)); testResult.setConsole(getJmeterLogger(key, false));
@ -50,7 +52,7 @@ public class MsResultService {
testResult.getScenarios().addAll(scenarios.values()); testResult.getScenarios().addAll(scenarios.values());
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId)); testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
System.out.println(key + "=======" + result.getURL());
this.cache.put(key, testResult); this.cache.put(key, testResult);
} }

View File

@ -136,24 +136,21 @@
<el-col :span="3" class="ms-col-one ms-font"> <el-col :span="3" class="ms-col-one ms-font">
<el-checkbox v-model="onSampleError">{{ $t('commons.failure_continues') }}</el-checkbox> <el-checkbox v-model="onSampleError">{{ $t('commons.failure_continues') }}</el-checkbox>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="8">
<div style=" float: right">
<env-popover :disabled="scenarioDefinition.length < 1" :env-map="projectEnvMap" <env-popover :disabled="scenarioDefinition.length < 1" :env-map="projectEnvMap"
:project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap" :result="envResult" :project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap" :result="envResult"
:show-config-button-with-out-permission="showConfigButtonWithOutPermission" :show-config-button-with-out-permission="showConfigButtonWithOutPermission"
:isReadOnly="scenarioDefinition.length < 1" @showPopover="showPopover" :isReadOnly="scenarioDefinition.length < 1" @showPopover="showPopover"
:project-list="projectList" ref="envPopover"/> :project-list="projectList" ref="envPopover" style="margin-right: 10px"/>
</el-col> <el-dropdown split-button type="primary" @click="runDebug" style="margin-right: 10px" size="mini" @command="handleCommand" v-if="!debugLoading">
<el-col :span="4"> {{ $t('api_test.request.debug') }}
<!-- <el-dropdown split-button type="primary" @click="runDebug" style="margin-right: 10px" size="mini" @command="handleCommand">--> <el-dropdown-menu slot="dropdown">
<!-- {{ $t('api_test.request.debug') }}--> <el-dropdown-item>{{ $t('test_track.case.steps') }}</el-dropdown-item>
<!-- <el-dropdown-menu slot="dropdown">--> </el-dropdown-menu>
<!-- <el-dropdown-item>{{ $t('api_test.run') }}</el-dropdown-item>--> </el-dropdown>
<!-- </el-dropdown-menu>--> <el-button icon="el-icon-loading" size="mini" type="primary" :disabled="debug" v-else>执行中</el-button>
<!-- </el-dropdown>--> <el-tooltip class="item" effect="dark" :content="$t('commons.refresh')" placement="top-start">
<el-button :disabled="scenarioDefinition.length < 1" size="mini" type="primary" v-prevent-re-click
@click="runDebug">{{ $t('api_test.request.debug') }}
</el-button>
<el-tooltip class="item" effect="dark" :content="$t('commons.refresh')" placement="right-start">
<el-button :disabled="scenarioDefinition.length < 1" size="mini" icon="el-icon-refresh" <el-button :disabled="scenarioDefinition.length < 1" size="mini" icon="el-icon-refresh"
v-prevent-re-click @click="getApiScenario"></el-button> v-prevent-re-click @click="getApiScenario"></el-button>
</el-tooltip> </el-tooltip>
@ -161,6 +158,7 @@
placement="top-start"> placement="top-start">
<font-awesome-icon class="alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/> <font-awesome-icon class="alt-ico" :icon="['fa', 'expand-alt']" size="lg" @click="fullScreen"/>
</el-tooltip> </el-tooltip>
</div>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
@ -179,7 +177,7 @@
<font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" v-prevent-re-click @click="disableAll"/> <font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" v-prevent-re-click @click="disableAll"/>
</el-tooltip> </el-tooltip>
<div class="ms-debug-result" v-if="debug"> <div class="ms-debug-result" v-if="debug">
354 ms 请求 10 成功 8 失败 2 {{ reqTotalTime }} ms 请求 {{ reqTotal }} 成功 {{ reqSuccess }} 失败 {{ reqError }}
</div> </div>
<el-tree node-key="resourceId" :props="props" :data="scenarioDefinition" class="ms-tree" <el-tree node-key="resourceId" :props="props" :data="scenarioDefinition" class="ms-tree"
:default-expanded-keys="expandedNode" :default-expanded-keys="expandedNode"
@ -256,15 +254,17 @@
:projectIds.sync="projectIds" :projectList="projectList" :projectIds.sync="projectIds" :projectList="projectList"
:scenarioDefinition="scenarioDefinition" :enableCookieShare="enableCookieShare" :scenarioDefinition="scenarioDefinition" :enableCookieShare="enableCookieShare"
:onSampleError="onSampleError" :onSampleError="onSampleError"
:execDebug="stopDebug"
:isFullUrl.sync="isFullUrl" @closePage="close" @unFullScreen="unFullScreen" :isFullUrl.sync="isFullUrl" @closePage="close" @unFullScreen="unFullScreen"
@showAllBtn="showAllBtn" @runDebug="runDebug" @setProjectEnvMap="setProjectEnvMap" @showAllBtn="showAllBtn" @runDebug="runDebug" @handleCommand="handleCommand" @setProjectEnvMap="setProjectEnvMap"
@showScenarioParameters="showScenarioParameters" @showScenarioParameters="showScenarioParameters"
@setCookieShare="setCookieShare" @setSampleError="setSampleError" @setCookieShare="setCookieShare" @setSampleError="setSampleError"
ref="maximizeHeader"/> ref="maximizeHeader"/>
</template> </template>
<maximize-scenario :scenario-definition="scenarioDefinition" :envMap="projectEnvMap" :moduleOptions="moduleOptions" <maximize-scenario :scenario-definition="scenarioDefinition" :envMap="projectEnvMap" :moduleOptions="moduleOptions"
:currentScenario="currentScenario" :type="type" :stepReEnable="stepEnable" ref="maximizeScenario" @openScenario="openScenario"/> :req-error="reqError" :req-success="reqSuccess" :req-total="reqTotal" :req-total-time="reqTotalTime"
:currentScenario="currentScenario" :type="type" :debug="debug" :reloadDebug="reloadDebug" :stepReEnable="stepEnable" ref="maximizeScenario" @openScenario="openScenario"/>
</ms-drawer> </ms-drawer>
<ms-change-history ref="changeHistory"/> <ms-change-history ref="changeHistory"/>
@ -274,16 +274,7 @@
<script> <script>
import {API_STATUS, PRIORITY} from "../../definition/model/JsonData"; import {API_STATUS, PRIORITY} from "../../definition/model/JsonData";
import {WORKSPACE_ID} from '@/common/js/constants'; import {buttons, setComponent} from './menu/Menu';
import {
Assertions,
ConstantTimer,
Extract,
IfController,
JSR223Processor,
LoopController,
TransactionController
} from "../../definition/model/ApiTestModel";
import {parseEnvironment} from "../../definition/model/EnvironmentModel"; import {parseEnvironment} from "../../definition/model/EnvironmentModel";
import {ELEMENT_TYPE, ELEMENTS} from "./Setting"; import {ELEMENT_TYPE, ELEMENTS} from "./Setting";
import MsApiCustomize from "./ApiCustomize"; import MsApiCustomize from "./ApiCustomize";
@ -402,12 +393,21 @@ export default {
loading: false loading: false
}, },
debug: false, debug: false,
debugLoading: false,
reqTotal: 0,
reqSuccess: 0,
reqError: 0,
reqTotalTime: 0,
reloadDebug: "",
stopDebug: "",
} }
}, },
created() { created() {
if (!this.currentScenario.apiScenarioModuleId) { if (!this.currentScenario.apiScenarioModuleId) {
this.currentScenario.apiScenarioModuleId = ""; this.currentScenario.apiScenarioModuleId = "";
} }
this.debug = false;
this.debugLoading = false;
this.operatingElements = ELEMENTS.get("ALL"); this.operatingElements = ELEMENTS.get("ALL");
this.getWsProjects(); this.getWsProjects();
this.getMaintainerOptions(); this.getMaintainerOptions();
@ -417,147 +417,106 @@ export default {
}, },
directives: {OutsideClick}, directives: {OutsideClick},
computed: { computed: {
buttons() { 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.transcation_controller'),
show: this.showButton("TransactionController"),
titleColor: "#6D317C",
titleBgColor: "#F4F4F5",
icon: "alt_route",
click: () => {
this.addComponent('TransactionController')
}
},
{
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);
},
projectId() { projectId() {
return getCurrentProjectID(); return getCurrentProjectID();
}, },
}, },
methods: { methods: {
clearDebug() {
this.reqError = 0;
this.reqTotalTime = 0;
this.reqTotal = 0;
this.reqSuccess = 0;
},
editParent(node, status) {
if (!status) {
node.data.code = "error";
}
node.data.debug = true;
if (node.parent && node.parent.data && node.parent.data.id) {
this.editParent(node.parent, status);
}
},
findNodeChild(arr, name, index, status) {
arr.forEach(item => {
if (item.data.name === name && item.data.index === index) {
this.editParent(item.parent, status);
}
if (item.childNodes && item.childNodes.length > 0) {
this.findNodeChild(item.childNodes, name, index, status);
}
})
},
findNode(name, index, status) {
if (this.$refs.stepTree && this.$refs.stepTree.root) {
this.$refs.stepTree.root.childNodes.forEach(item => {
if (item.childNodes && item.childNodes.length > 0) {
this.findNodeChild(item.childNodes, name, index, status);
}
})
}
},
getReport() { getReport() {
if (this.debug) { if (this.debug) {
let url = "/api/scenario/report/get/real/" + this.reportId; let url = "/api/scenario/report/get/real/" + this.reportId;
this.$get(url, response => { this.$get(url, response => {
// if (response.data && response.data.end) { if (response.data) {
// console.log(response.data); this.formatResult(response.data);
// } else { if (response.data.end) {
// setTimeout(this.getReport, 2000) this.removeReport();
// } this.debugLoading = false;
this.stopDebug = "stop";
} else {
setTimeout(this.getReport, 2000)
}
} else {
setTimeout(this.getReport, 2000)
}
}); });
} }
}, },
formatResult(res) {
let resMap = new Map;
let startTime = 99991611737506593;
let endTime = 0;
this.clearDebug();
if (res && res.scenarios) {
res.scenarios.forEach(item => {
this.reqTotal += item.requestResults.length;
if (item && item.requestResults) {
item.requestResults.forEach(req => {
req.responseResult.console = res.console;
let name = req.name.split('<->')[0];
resMap.set(req.id + name, req);
if (req.success) {
this.reqSuccess++;
} else {
this.reqError++;
}
if (req.startTime && Number(req.startTime) < startTime) {
startTime = req.startTime;
}
if (req.endTime && Number(req.endTime) > endTime) {
endTime = req.endTime;
}
})
}
})
}
if (startTime < endTime) {
this.reqTotalTime = endTime - startTime + 100;
}
this.debugResult = resMap;
this.sort();
this.reload();
this.reloadDebug = getUUID();
},
removeReport() {
let url = "/api/scenario/report/remove/real/" + this.reportId;
this.$get(url, response => {
});
},
handleCommand() { handleCommand() {
this.debug = false; this.debug = false;
/*触发执行操作*/ /*触发执行操作*/
@ -591,7 +550,6 @@ export default {
} }
}) })
}, },
openHis() { openHis() {
this.$refs.changeHistory.open(this.currentScenario.id); this.$refs.changeHistory.open(this.currentScenario.id);
}, },
@ -658,59 +616,7 @@ export default {
} }
}, },
addComponent(type) { addComponent(type) {
switch (type) { setComponent(type, this);
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.TransactionController:
this.selectedTreeNode !== undefined ? this.selectedTreeNode.hashTree.push(new TransactionController()) :
this.scenarioDefinition.push(new TransactionController());
break;
case ELEMENT_TYPE.scenario:
this.isBtnHide = true;
this.$refs.scenarioRelevance.open();
break;
default:
this.$refs.apiImport.open();
break;
}
if (this.selectedNode) {
this.selectedNode.expanded = true;
}
this.sort();
}, },
nodeClick(data, node) { nodeClick(data, node) {
if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled) { if (data.referenced != 'REF' && data.referenced != 'Deleted' && !data.disabled) {
@ -763,6 +669,8 @@ export default {
// debug // debug
if (this.debugResult && this.debugResult.get(arr[i].id + arr[i].name)) { if (this.debugResult && this.debugResult.get(arr[i].id + arr[i].name)) {
arr[i].requestResult = this.debugResult.get(arr[i].id + arr[i].name); arr[i].requestResult = this.debugResult.get(arr[i].id + arr[i].name);
arr[i].debug = this.debug;
this.findNode(arr[i].name, arr[i].index, arr[i].requestResult.success);
} }
} }
}, },
@ -794,6 +702,7 @@ export default {
// debug // debug
if (this.debugResult && this.debugResult.get(this.scenarioDefinition[i].id + this.scenarioDefinition[i].name)) { if (this.debugResult && this.debugResult.get(this.scenarioDefinition[i].id + this.scenarioDefinition[i].name)) {
this.scenarioDefinition[i].requestResult = this.debugResult.get(this.scenarioDefinition[i].id + this.scenarioDefinition[i].name); this.scenarioDefinition[i].requestResult = this.debugResult.get(this.scenarioDefinition[i].id + this.scenarioDefinition[i].name);
this.scenarioDefinition[i].debug = this.debug;
} }
} }
}, },
@ -928,7 +837,10 @@ export default {
if (this.scenarioDefinition.length < 1) { if (this.scenarioDefinition.length < 1) {
return; return;
} }
// this.debug = true; this.debug = true;
this.debugLoading = true;
this.stopDebug = "";
this.clearDebug();
/*触发执行操作*/ /*触发执行操作*/
this.$refs['currentScenario'].validate((valid) => { this.$refs['currentScenario'].validate((valid) => {
if (valid) { if (valid) {
@ -955,11 +867,7 @@ export default {
onSampleError: this.onSampleError, onSampleError: this.onSampleError,
}; };
this.reportId = getUUID().substring(0, 8); this.reportId = getUUID().substring(0, 8);
// this.editScenario().then(() => {
//
// })
}) })
}) })
} }
}) })
@ -1463,7 +1371,6 @@ export default {
.alt-ico:hover { .alt-ico:hover {
color: black; color: black;
cursor: pointer; cursor: pointer;
font-size: 18px;
} }
.scenario-name { .scenario-name {

View File

@ -8,6 +8,7 @@
<el-tag class="ms-left-btn" size="small" :style="{'color': color, 'background-color': backgroundColor}">{{title}}</el-tag> <el-tag class="ms-left-btn" size="small" :style="{'color': color, 'background-color': backgroundColor}">{{title}}</el-tag>
<el-tag size="mini" v-if="data.method">{{getMethod()}}</el-tag> <el-tag size="mini" v-if="data.method">{{getMethod()}}</el-tag>
</slot> </slot>
<slot name="behindHeaderLeft" v-if="!isMax"></slot>
<span> <span>
<slot name="headerLeft"> <slot name="headerLeft">
@ -25,11 +26,11 @@
</el-tooltip> </el-tooltip>
</span> </span>
</slot> </slot>
<slot name="behindHeaderLeft" v-if="!isMax"></slot>
</span> </span>
<div class="header-right" @click.stop> <div class="header-right" @click.stop>
<slot name="message"></slot> <slot name="message"></slot>
<slot name="debugStepCode"></slot>
<el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top" v-if="showBtn"> <el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top" v-if="showBtn">
<el-switch v-model="data.enable" class="enable-switch" size="mini" :disabled="data.disabled && !data.root" style="width: 30px"/> <el-switch v-model="data.enable" class="enable-switch" size="mini" :disabled="data.disabled && !data.root" style="width: 30px"/>
</el-tooltip> </el-tooltip>
@ -202,7 +203,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
vertical-align: middle; vertical-align: middle;
white-space: nowrap; white-space: nowrap;
width: 180px; width: 140px;
} }
.scenario-name { .scenario-name {
@ -214,7 +215,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
vertical-align: middle; vertical-align: middle;
white-space: nowrap; white-space: nowrap;
width: calc(100% - 30rem); width: calc(100% - 35rem);
} }
/deep/ .el-step__icon { /deep/ .el-step__icon {
@ -240,4 +241,5 @@
white-space: nowrap; white-space: nowrap;
width: 400px; width: 400px;
} }
</style> </style>

View File

@ -20,7 +20,13 @@
<el-tag size="mini" class="ms-tag" v-if="request.referenced ==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag> <el-tag size="mini" class="ms-tag" v-if="request.referenced ==='REF'">{{ $t('api_test.scenario.reference') }}</el-tag>
<span class="ms-tag">{{ getProjectName(request.projectId) }}</span> <span class="ms-tag">{{ getProjectName(request.projectId) }}</span>
</template> </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>
</template>
<template v-slot:button> <template v-slot:button>
<el-tooltip :content="$t('api_test.run')" placement="top"> <el-tooltip :content="$t('api_test.run')" placement="top">
<el-button :disabled="!request.enable" @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/> <el-button :disabled="!request.enable" @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/>
@ -38,23 +44,22 @@
:headers="request.headers " :headers="request.headers "
:is-read-only="isCompReadOnly" :is-read-only="isCompReadOnly"
:request="request"/> :request="request"/>
<esb-definition v-if="showXpackCompnent&&request.esbDataStruct!=null" <esb-definition v-if="showXpackCompnent&&request.esbDataStruct!=null"
v-xpack v-xpack
:request="request" :request="request"
:showScript="false" :showScript="false"
:is-read-only="isCompReadOnly" :is-read-only="isCompReadOnly" ref="esbDefinition"/>
ref="esbDefinition"/>
<!-- <ms-tcp-basis-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "-->
<!-- :request="request"-->
<!-- :is-read-only="isCompReadOnly"-->
<!-- :showScript="false"/>-->
<ms-tcp-format-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null " <ms-tcp-format-parameters v-if="(request.protocol==='TCP'|| request.type==='TCPSampler')&& request.esbDataStruct==null "
:is-read-only="isCompReadOnly" :is-read-only="isCompReadOnly"
:show-script="false" :request="request"/> :show-script="false" :request="request"/>
<ms-sql-basis-parameters v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'" <ms-sql-basis-parameters v-if="request.protocol==='SQL'|| request.type==='JDBCSampler'"
:request="request" :request="request"
:is-read-only="isCompReadOnly" :is-read-only="isCompReadOnly"
:showScript="false"/> :showScript="false"/>
<ms-dubbo-basis-parameters v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'" <ms-dubbo-basis-parameters v-if="request.protocol==='DUBBO' || request.protocol==='dubbo://'|| request.type==='DubboSampler'"
:request="request" :request="request"
:is-read-only="isCompReadOnly" :is-read-only="isCompReadOnly"
@ -94,7 +99,6 @@
<script> <script>
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters"; import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
// import MsTcpBasisParameters from "../../../definition/components/request/tcp/TcpBasisParameters";
import MsTcpFormatParameters from "../../../definition/components/request/tcp/TcpFormatParameters"; import MsTcpFormatParameters from "../../../definition/components/request/tcp/TcpFormatParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters"; import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm"; import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
@ -104,6 +108,7 @@ import {getUUID, getCurrentProjectID} from "@/common/js/utils";
import ApiBaseComponent from "../common/ApiBaseComponent"; import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent"; import ApiResponseComponent from "./ApiResponseComponent";
import CustomizeReqInfo from "@/business/components/api/automation/scenario/common/CustomizeReqInfo"; import CustomizeReqInfo from "@/business/components/api/automation/scenario/common/CustomizeReqInfo";
import TemplateComponent from "@/business/components/track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const esbDefinition = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinition.vue") : {}; const esbDefinition = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinition.vue") : {};
@ -133,6 +138,7 @@ export default {
envMap: Map envMap: Map
}, },
components: { components: {
TemplateComponent,
CustomizeReqInfo, CustomizeReqInfo,
ApiBaseComponent, ApiResponseComponent, ApiBaseComponent, ApiResponseComponent,
MsSqlBasisParameters, MsTcpFormatParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun, MsSqlBasisParameters, MsTcpFormatParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun,
@ -147,6 +153,7 @@ export default {
isShowInput: false, isShowInput: false,
showXpackCompnent: false, showXpackCompnent: false,
environment: {}, environment: {},
result: {},
} }
}, },
created() { created() {
@ -462,6 +469,25 @@ export default {
} }
.ms-tag { .ms-tag {
margin-left: 20px; margin-left: 10px;
}
.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;
}
.ms-req-error {
color: #F56C6C;
}
.ms-req-success {
color: #67C23A;
} }
</style> </style>

View File

@ -22,6 +22,13 @@
<span class="ms-tag">{{ getProjectName(scenario.projectId) }}</span> <span class="ms-tag">{{ getProjectName(scenario.projectId) }}</span>
</template> </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>
</template>
</api-base-component> </api-base-component>
</template> </template>
@ -107,6 +114,16 @@
}, },
}, },
methods: { 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() { remove() {
this.$emit('remove', this.scenario, this.node); this.$emit('remove', this.scenario, this.node);
}, },
@ -179,6 +196,14 @@
} }
.ms-tag { .ms-tag {
margin-left: 20px; margin-left: 0px;
}
.ms-req-error {
color: #F56C6C;
}
.ms-req-success {
color: #67C23A;
} }
</style> </style>

View File

@ -23,6 +23,13 @@
<el-input draggable size="mini" v-model="controller.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" class="ms-btn"/> <el-input draggable size="mini" v-model="controller.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" class="ms-btn"/>
</template> </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>
</template>
</api-base-component> </api-base-component>
</template> </template>
@ -88,6 +95,16 @@
} }
}, },
methods: { 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() { remove() {
this.$emit('remove', this.controller, this.node); this.$emit('remove', this.controller, this.node);
}, },
@ -118,4 +135,12 @@
width: 15%; width: 15%;
margin-left: 5px; margin-left: 5px;
} }
.ms-req-error {
color: #F56C6C;
}
.ms-req-success {
color: #67C23A;
}
</style> </style>

View File

@ -69,6 +69,14 @@
<el-input-number size="small" v-model="controller.whileController.timeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="3000" :step="1000"/> <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> <span class="ms-span ms-radio">ms</span>
</div> </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>
</template>
</api-base-component> </api-base-component>
</div> </div>
@ -151,6 +159,16 @@
}; };
}, },
methods: { 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 '';
},
initResult() { initResult() {
if (this.controller) { if (this.controller) {
switch (this.controller.loopType) { switch (this.controller.loopType) {
@ -363,6 +381,13 @@
.icon.is-active { .icon.is-active {
transform: rotate(90deg); transform: rotate(90deg);
} }
.ms-req-error {
color: #F56C6C;
}
.ms-req-success {
color: #67C23A;
}
/deep/ .el-radio { /deep/ .el-radio {
margin-right: 5px; margin-right: 5px;

View File

@ -17,6 +17,10 @@
<el-tooltip :content="$t('api_test.scenario.enable')" placement="top" effect="light" v-else> <el-tooltip :content="$t('api_test.scenario.enable')" placement="top" effect="light" v-else>
<font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" @click="disableAll"/> <font-awesome-icon class="ms-open-btn" :icon="['fas', 'toggle-on']" @click="disableAll"/>
</el-tooltip> </el-tooltip>
<span class="ms-debug-result" v-if="debug">
{{ reqTotalTime }} ms 请求 {{ reqTotal }} 成功 {{ reqSuccess }} 失败 {{ reqError }}
</span>
<el-tree node-key="resourceId" <el-tree node-key="resourceId"
:props="props" :props="props"
:data="scenarioDefinition" :data="scenarioDefinition"
@ -175,9 +179,15 @@ export default {
moduleOptions: Array, moduleOptions: Array,
currentScenario: {}, currentScenario: {},
type: String, type: String,
debug: Boolean,
reloadDebug: String,
stepReEnable: Boolean, stepReEnable: Boolean,
scenarioDefinition: Array, scenarioDefinition: Array,
envMap: Map, envMap: Map,
reqTotal: Number,
reqSuccess: Number,
reqError: Number,
reqTotalTime: Number,
}, },
components: { components: {
MsVariableList, MsVariableList,
@ -242,6 +252,7 @@ export default {
debugResult: new Map, debugResult: new Map,
expandedStatus: false, expandedStatus: false,
stepEnable: true, stepEnable: true,
debugLoading: false,
} }
}, },
created() { created() {
@ -255,6 +266,9 @@ export default {
watch: { watch: {
envMap() { envMap() {
this.projectEnvMap = this.envMap; this.projectEnvMap = this.envMap;
},
reloadDebug() {
this.reload();
} }
}, },
directives: {OutsideClick}, directives: {OutsideClick},
@ -1198,4 +1212,10 @@ export default {
.ms-open-btn-left { .ms-open-btn-left {
margin-left: 30px; margin-left: 30px;
} }
.ms-debug-result {
float: right;
margin-right: 30px;
margin-top: 3px;
}
</style> </style>

View File

@ -25,10 +25,13 @@
@showPopover="showPopover" :project-list="projectList" ref="envPopover" class="ms-right" @showPopover="showPopover" :project-list="projectList" ref="envPopover" class="ms-right"
:result="envResult"/> :result="envResult"/>
<el-button :disabled="scenarioDefinition.length < 1" size="mini" type="primary" v-prevent-re-click <el-dropdown split-button type="primary" @click="runDebug" style="margin-right: 10px" size="mini" @command="handleCommand" v-if="!debug">
@click="runDebug">{{ $t('api_test.request.debug') }} {{ $t('api_test.request.debug') }}
</el-button> <el-dropdown-menu slot="dropdown">
<el-dropdown-item>{{ $t('test_track.case.steps') }}</el-dropdown-item>
</el-dropdown-menu>
</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"/> <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"/>--> <!-- <i class="el-icon-close alt-ico-close" @click="close"/>-->
</div> </div>
@ -48,7 +51,8 @@ import html2canvas from 'html2canvas';
projectEnvMap: Map, projectEnvMap: Map,
projectIds: Set, projectIds: Set,
projectList: Array, projectList: Array,
isFullUrl: Boolean isFullUrl: Boolean,
execDebug: String,
}, },
data() { data() {
return { return {
@ -59,12 +63,23 @@ import html2canvas from 'html2canvas';
sampleError: true, sampleError: true,
envResult: { envResult: {
loading: false loading: false
} },
debugLoading: false,
reqTotal: 0,
reqSuccess: 0,
reqError: 0,
reqTotalTime: 0,
debug: false,
} }
}, },
computed: { computed: {
projectId() { projectId() {
return getCurrentProjectID(); return getCurrentProjectID();
},
},
watch:{
execDebug(){
this.debug = false;
} }
}, },
mounted() { mounted() {
@ -96,8 +111,15 @@ import html2canvas from 'html2canvas';
this.$emit('unFullScreen'); this.$emit('unFullScreen');
}, },
runDebug() { runDebug() {
this.debug = true;
this.debugLoading = true;
this.$emit('runDebug'); this.$emit('runDebug');
}, },
handleCommand() {
this.debug = false;
this.debugLoading = false;
this.$emit('handleCommand');
},
setCookieShare() { setCookieShare() {
this.$emit('setCookieShare', this.cookieShare); this.$emit('setCookieShare', this.cookieShare);
}, },
@ -169,7 +191,7 @@ import html2canvas from 'html2canvas';
.ms-header-right { .ms-header-right {
float: right; float: right;
width: 500px; width: 540px;
margin-top: 4px; margin-top: 4px;
z-index: 1; z-index: 1;
} }
@ -209,6 +231,7 @@ import html2canvas from 'html2canvas';
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif; font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px; font-size: 13px;
} }
.ms-scenario-name { .ms-scenario-name {
display: inline-block; display: inline-block;
margin: 0 5px; margin: 0 5px;
@ -219,4 +242,5 @@ import html2canvas from 'html2canvas';
white-space: nowrap; white-space: nowrap;
width: 200px; width: 200px;
} }
</style> </style>

View File

@ -0,0 +1,182 @@
import {ELEMENT_TYPE} from "@/business/components/api/automation/scenario/Setting";
import {Assertions, ConstantTimer, Extract, IfController, JSR223Processor, LoopController, TransactionController} from "@/business/components/api/definition/model/ApiTestModel";
export function 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.transcation_controller'),
show: this.showButton("TransactionController"),
titleColor: "#6D317C",
titleBgColor: "#F4F4F5",
icon: "alt_route",
click: () => {
this.addComponent('TransactionController')
}
},
{
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);
}
export function setComponent(type, _this) {
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.TransactionController:
_this.selectedTreeNode !== undefined ? _this.selectedTreeNode.hashTree.push(new TransactionController()) :
_this.scenarioDefinition.push(new TransactionController());
break;
case ELEMENT_TYPE.scenario:
_this.isBtnHide = true;
_this.$refs.scenarioRelevance.open();
break;
default:
_this.$refs.apiImport.open();
break;
}
if (_this.selectedNode) {
_this.selectedNode.expanded = true;
}
_this.sort();
}