feat(接口测试):增加接口测试一键运行功能
This commit is contained in:
parent
3fff716881
commit
66b6c179e8
|
@ -80,6 +80,7 @@ public class APITestController {
|
|||
return apiTestService.get(testId);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody DeleteAPITestRequest request) {
|
||||
apiTestService.delete(request.getId());
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
<style scoped>
|
||||
|
||||
.el-table {
|
||||
cursor:pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -9,18 +9,43 @@
|
|||
<span class="time">{{ report.createTime | timestampFormatDate }}</span>
|
||||
</header>
|
||||
<main v-if="this.isNotRunning">
|
||||
<ms-metric-chart :content="content"/>
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('api_report.total')" name="total">
|
||||
<ms-scenario-results :scenarios="content.scenarios"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="fail">
|
||||
<template slot="label">
|
||||
<span class="fail">{{ $t('api_report.fail') }}</span>
|
||||
</template>
|
||||
<ms-scenario-results :scenarios="fails"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
||||
<!--<el-container>
|
||||
<el-aside width="900px">
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('api_report.total')" name="total">
|
||||
<ms-scenario-results :scenarios="content.scenarios"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="fail">
|
||||
<template slot="label">
|
||||
<span class="fail">{{ $t('api_report.fail') }}</span>
|
||||
</template>
|
||||
<ms-scenario-results :scenarios="fails"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-aside>
|
||||
<el-main style="margin-top: 20px">
|
||||
|
||||
</el-main>
|
||||
</el-container>-->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('api_report.total')" name="total">
|
||||
<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="fail">
|
||||
<template slot="label">
|
||||
<span class="fail">{{ $t('api_report.fail') }}</span>
|
||||
</template>
|
||||
<ms-scenario-results v-on:requestResult="requestResult" :scenarios="fails"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
<el-col :span="16" style="margin-top: 40px;">
|
||||
<ms-request-result-tail v-if="isRequestResult" :request="request" :scenario-name="scenarioName"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</main>
|
||||
</section>
|
||||
</el-card>
|
||||
|
@ -30,131 +55,142 @@
|
|||
|
||||
<script>
|
||||
|
||||
import MsRequestResult from "./components/RequestResult";
|
||||
import MsScenarioResult from "./components/ScenarioResult";
|
||||
import MsMetricChart from "./components/MetricChart";
|
||||
import MsScenarioResults from "./components/ScenarioResults";
|
||||
import MsRequestResult from "./components/RequestResult";
|
||||
import MsRequestResultTail from "./components/RequestResultTail";
|
||||
import MsScenarioResult from "./components/ScenarioResult";
|
||||
import MsMetricChart from "./components/MetricChart";
|
||||
import MsScenarioResults from "./components/ScenarioResults";
|
||||
|
||||
export default {
|
||||
name: "MsApiReportView",
|
||||
components: {MsScenarioResults, MsMetricChart, MsScenarioResult, MsRequestResult},
|
||||
data() {
|
||||
return {
|
||||
activeName: "total",
|
||||
content: {},
|
||||
report: {},
|
||||
loading: true,
|
||||
fails: []
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
this.loading = true;
|
||||
this.report = {};
|
||||
this.content = {};
|
||||
this.fails = [];
|
||||
},
|
||||
getReport() {
|
||||
this.init();
|
||||
|
||||
if (this.reportId) {
|
||||
let url = "/api/report/get/" + this.reportId;
|
||||
this.$get(url, response => {
|
||||
this.report = response.data || {};
|
||||
if (response.data) {
|
||||
if (this.isNotRunning) {
|
||||
try {
|
||||
this.content = JSON.parse(this.report.content);
|
||||
} catch (e) {
|
||||
console.log(this.report.content)
|
||||
throw e;
|
||||
}
|
||||
this.getFails();
|
||||
this.loading = false;
|
||||
} else {
|
||||
setTimeout(this.getReport, 2000)
|
||||
}
|
||||
} else {
|
||||
this.loading = false;
|
||||
this.$error(this.$t('api_report.not_exist'));
|
||||
}
|
||||
});
|
||||
export default {
|
||||
name: "MsApiReportView",
|
||||
components: {MsScenarioResults, MsRequestResultTail, MsMetricChart, MsScenarioResult, MsRequestResult},
|
||||
data() {
|
||||
return {
|
||||
activeName: "total",
|
||||
content: {},
|
||||
report: {},
|
||||
loading: true,
|
||||
fails: [],
|
||||
totalTime: "",
|
||||
isRequestResult: false,
|
||||
request: {},
|
||||
scenarioName: null,
|
||||
}
|
||||
},
|
||||
getFails() {
|
||||
if (this.isNotRunning) {
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
this.loading = true;
|
||||
this.report = {};
|
||||
this.content = {};
|
||||
this.fails = [];
|
||||
this.content.scenarios.forEach((scenario) => {
|
||||
let failScenario = Object.assign({}, scenario);
|
||||
if (scenario.error > 0) {
|
||||
this.fails.push(failScenario);
|
||||
failScenario.requestResults = [];
|
||||
scenario.requestResults.forEach((request) => {
|
||||
if (!request.success) {
|
||||
let failRequest = Object.assign({}, request);
|
||||
failScenario.requestResults.push(failRequest);
|
||||
},
|
||||
getReport() {
|
||||
this.init();
|
||||
|
||||
if (this.reportId) {
|
||||
let url = "/api/report/get/" + this.reportId;
|
||||
this.$get(url, response => {
|
||||
this.report = response.data || {};
|
||||
if (response.data) {
|
||||
if (this.isNotRunning) {
|
||||
try {
|
||||
this.content = JSON.parse(this.report.content);
|
||||
} catch (e) {
|
||||
console.log(this.report.content)
|
||||
throw e;
|
||||
}
|
||||
this.getFails();
|
||||
this.loading = false;
|
||||
} else {
|
||||
setTimeout(this.getReport, 2000)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.loading = false;
|
||||
this.$error(this.$t('api_report.not_exist'));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
getFails() {
|
||||
if (this.isNotRunning) {
|
||||
this.fails = [];
|
||||
this.content.scenarios.forEach((scenario) => {
|
||||
this.totalTime = scenario.responseTime + scenario.responseTime
|
||||
let failScenario = Object.assign({}, scenario);
|
||||
if (scenario.error > 0) {
|
||||
this.fails.push(failScenario);
|
||||
failScenario.requestResults = [];
|
||||
scenario.requestResults.forEach((request) => {
|
||||
if (!request.success) {
|
||||
let failRequest = Object.assign({}, request);
|
||||
failScenario.requestResults.push(failRequest);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
requestResult(requestResult) {
|
||||
this.isRequestResult = true;
|
||||
this.request = requestResult.request;
|
||||
this.scenarioName = requestResult.scenarioName;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route': 'getReport',
|
||||
},
|
||||
|
||||
created() {
|
||||
this.getReport();
|
||||
},
|
||||
|
||||
computed: {
|
||||
reportId: function () {
|
||||
return this.$route.params.reportId;
|
||||
},
|
||||
path() {
|
||||
return "/api/test/edit?id=" + this.report.testId;
|
||||
|
||||
watch: {
|
||||
'$route': 'getReport',
|
||||
},
|
||||
isNotRunning() {
|
||||
return "Running" !== this.report.status;
|
||||
|
||||
created() {
|
||||
this.getReport();
|
||||
},
|
||||
|
||||
computed: {
|
||||
reportId: function () {
|
||||
return this.$route.params.reportId;
|
||||
},
|
||||
path() {
|
||||
return "/api/test/edit?id=" + this.report.testId;
|
||||
},
|
||||
isNotRunning() {
|
||||
return "Running" !== this.report.status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.report-container .el-tabs__header {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
.report-container .el-tabs__header {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.report-container {
|
||||
height: calc(100vh - 150px);
|
||||
min-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.report-container {
|
||||
height: calc(100vh - 150px);
|
||||
min-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
font-size: 15px;
|
||||
}
|
||||
.report-header {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.report-header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.report-header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.report-header .time {
|
||||
color: #909399;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.report-header .time {
|
||||
color: #909399;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.report-container .fail {
|
||||
color: #F56C6C;
|
||||
}
|
||||
.report-container .fail {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.report-container .is-active .fail {
|
||||
color: inherit;
|
||||
}
|
||||
.report-container .is-active .fail {
|
||||
color: inherit;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
<el-row type="flex" align="middle">
|
||||
<div style="width: 50%">
|
||||
<el-row type="flex" justify="center" align="middle">
|
||||
<div class="metric-time">
|
||||
<div class="value" style="margin-left: -150px">{{this.minutes}}min{{this.seconds}}s</div>
|
||||
</div>
|
||||
<chart id="chart" ref="chart" :options="options" :autoresize="true"></chart>
|
||||
<el-row type="flex" justify="center" align="middle">
|
||||
<i class="circle success"/>
|
||||
|
@ -48,9 +51,15 @@
|
|||
name: "MsMetricChart",
|
||||
|
||||
props: {
|
||||
content: Object
|
||||
content: Object,
|
||||
totalTime: Number
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
minutes: Math.floor(this.totalTime / 60),
|
||||
seconds: this.totalTime % 60,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
options() {
|
||||
return {
|
||||
|
@ -160,6 +169,12 @@
|
|||
letter-spacing: -.5px;
|
||||
}
|
||||
|
||||
.metric-time .value {
|
||||
font-size: 25px;
|
||||
font-weight: 400;
|
||||
letter-spacing: -.5px;
|
||||
}
|
||||
|
||||
.metric-box .name {
|
||||
font-size: 16px;
|
||||
letter-spacing: -.2px;
|
||||
|
|
|
@ -7,55 +7,14 @@
|
|||
{{request.method}}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col :span="20">
|
||||
<div class="name">{{request.name}}</div>
|
||||
<el-tooltip effect="dark" :content="request.url" placement="bottom" :open-delay="800">
|
||||
<div class="url">{{request.url}}</div>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<div class="time">
|
||||
{{request.responseResult.responseTime}}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{request.error}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{assertion}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-tag size="mini" type="success" v-if="request.success">
|
||||
{{$t('api_report.success')}}
|
||||
</el-tag>
|
||||
<el-tag size="mini" type="danger" v-else>
|
||||
{{$t('api_report.fail')}}
|
||||
</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div v-show="isActive">
|
||||
<el-tabs v-model="activeName" v-show="isActive" v-if="hasSub">
|
||||
<el-tab-pane :label="$t('api_report.sub_result')" name="sub">
|
||||
<ms-request-result class="sub-result" v-for="(sub, index) in request.subRequestResults"
|
||||
:key="index" :request="sub"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('api_report.request_result')" name="result">
|
||||
<ms-request-metric :request="request"/>
|
||||
<ms-request-text :request="request"/>
|
||||
<br>
|
||||
<ms-response-text :response="request.responseResult"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div v-else>
|
||||
<ms-request-metric :request="request"/>
|
||||
<ms-request-text :request="request"/>
|
||||
<br>
|
||||
<ms-response-text :response="request.responseResult"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -69,19 +28,17 @@
|
|||
name: "MsRequestResult",
|
||||
components: {MsResponseText, MsRequestText, MsAssertionResults, MsRequestMetric},
|
||||
props: {
|
||||
request: Object
|
||||
request: Object,
|
||||
scenarioName: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isActive: false,
|
||||
activeName: "sub",
|
||||
}
|
||||
return {}
|
||||
},
|
||||
|
||||
methods: {
|
||||
active() {
|
||||
this.isActive = !this.isActive;
|
||||
this.$emit("requestResult", {request: this.request, scenarioName: this.scenarioName});
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
<template>
|
||||
<div class="request-result">
|
||||
<div @click="active">
|
||||
<el-row :gutter="10" type="flex" align="middle" class="info">
|
||||
<el-col :span="16">
|
||||
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
|
||||
{{scenarioName}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.response_time')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.error')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.assertions')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.result')}}
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="10" type="flex" align="middle" class="info">
|
||||
<el-col :span="4">
|
||||
<div class="method">
|
||||
{{request.method}}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="name">{{request.name}}</div>
|
||||
<el-tooltip effect="dark" :content="request.url" placement="bottom" :open-delay="800">
|
||||
<div class="url">{{request.url}}</div>
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<div class="time">
|
||||
{{request.responseResult.responseTime}}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{request.error}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{assertion}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-tag size="mini" type="success" v-if="request.success">
|
||||
{{$t('api_report.success')}}
|
||||
</el-tag>
|
||||
<el-tag size="mini" type="danger" v-else>
|
||||
{{$t('api_report.fail')}}
|
||||
</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div v-show="isActive">
|
||||
<el-tabs v-model="activeName" v-show="isActive" v-if="hasSub">
|
||||
<el-tab-pane :label="$t('api_report.sub_result')" name="sub">
|
||||
<ms-request-result class="sub-result" v-for="(sub, index) in request.subRequestResults"
|
||||
:key="index" :request="sub"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('api_report.request_result')" name="result">
|
||||
<ms-request-metric :request="request"/>
|
||||
<ms-request-text :request="request"/>
|
||||
<br>
|
||||
<ms-response-text :response="request.responseResult"/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div v-else>
|
||||
<ms-request-metric :request="request"/>
|
||||
<ms-request-text :request="request"/>
|
||||
<br>
|
||||
<ms-response-text :response="request.responseResult"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsRequestMetric from "./RequestMetric";
|
||||
import MsAssertionResults from "./AssertionResults";
|
||||
import MsRequestText from "./RequestText";
|
||||
import MsResponseText from "./ResponseText";
|
||||
import MsRequestResult from "./RequestResult";
|
||||
|
||||
export default {
|
||||
name: "MsRequestResultTail",
|
||||
components: {MsResponseText, MsRequestText, MsAssertionResults, MsRequestMetric, MsRequestResult},
|
||||
props: {
|
||||
request: Object,
|
||||
scenarioName: String
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isActive: false,
|
||||
activeName: "sub",
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
active() {
|
||||
this.isActive = !this.isActive;
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
assertion() {
|
||||
return this.request.passAssertions + " / " + this.request.totalAssertions;
|
||||
},
|
||||
hasSub() {
|
||||
return this.request.subRequestResults.length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.request-result {
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.request-result .info {
|
||||
background-color: #F9F9F9;
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.request-result .method {
|
||||
color: #1E90FF;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.request-result .url {
|
||||
color: #7f7f7f;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
margin-top: 4px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.request-result .tab .el-tabs__header {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.request-result .text {
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sub-result .info {
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.sub-result .method {
|
||||
border-left: 5px solid #1E90FF;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.sub-result:last-child {
|
||||
border-bottom: 1px solid #EBEEF5;
|
||||
}
|
||||
|
||||
.request-result .icon.is-active {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
</style>
|
|
@ -6,28 +6,13 @@
|
|||
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
|
||||
{{scenario.name}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{scenario.responseTime}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{scenario.error}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{assertion}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-tag size="mini" type="success" v-if="success">
|
||||
{{$t('api_report.success')}}
|
||||
</el-tag>
|
||||
<el-tag size="mini" type="danger" v-else>
|
||||
{{$t('api_report.fail')}}
|
||||
</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div v-show="isActive">
|
||||
<ms-request-result v-for="(request, index) in scenario.requestResults" :key="index" :request="request"/>
|
||||
<ms-request-result v-for="(request, index) in scenario.requestResults" :key="index" :request="request"
|
||||
v-on:requestResult="requestResult"
|
||||
:scenarioName="scenario.name"/>
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</div>
|
||||
|
@ -54,6 +39,9 @@
|
|||
methods: {
|
||||
active() {
|
||||
this.isActive = !this.isActive;
|
||||
},
|
||||
requestResult(requestResult) {
|
||||
this.$emit("requestResult", requestResult);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -1,25 +1,15 @@
|
|||
<template>
|
||||
|
||||
<el-card>
|
||||
<div class="scenario-header">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="16">
|
||||
{{$t('api_report.scenario_name')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.response_time')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.error')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.assertions')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.result')}}
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<ms-scenario-result v-for="(scenario, index) in scenarios" :key="index" :scenario="scenario"/>
|
||||
<ms-scenario-result v-for="(scenario, index) in scenarios" :key="index" :scenario="scenario"
|
||||
v-on:requestResult="requestResult"/>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
|
@ -33,8 +23,12 @@
|
|||
|
||||
props: {
|
||||
scenarios: Array
|
||||
},
|
||||
methods: {
|
||||
requestResult(requestResult) {
|
||||
this.$emit("requestResult", requestResult);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -5,10 +5,20 @@
|
|||
<template v-slot:header>
|
||||
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search"
|
||||
:title="$t('commons.test')"
|
||||
@create="create" :createTip="$t('load_test.create')"/>
|
||||
@create="create" :createTip="$t('load_test.create')" :runTip="$t('load_test.run')"
|
||||
:show-run="true"
|
||||
@runTest="runTest"/>
|
||||
|
||||
</template>
|
||||
<el-table border :data="tableData" class="adjust-table table-content" @sort-change="sort" @row-click="handleView"
|
||||
@filter-change="filter">
|
||||
|
||||
<one-click-operation ref="OneClickOperation" :select-ids="selectIds" :select-names="selectNames"
|
||||
:select-project-names="selectProjectNames"></one-click-operation>
|
||||
|
||||
<el-table border :data="tableData" class="adjust-table table-content" @sort-change="sort"
|
||||
@row-click="handleView"
|
||||
@filter-change="filter" @select-all="handleSelectAll" @select="selectionChange">
|
||||
<el-table-column
|
||||
type="selection"></el-table-column>
|
||||
<el-table-column prop="name" :label="$t('commons.name')" width="250" show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column prop="projectName" :label="$t('load_test.project_name')" width="200" show-overflow-tooltip/>
|
||||
|
@ -46,6 +56,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import OneClickOperation from './OneClickOperation';
|
||||
import MsTablePagination from "../../common/pagination/TablePagination";
|
||||
import MsTableHeader from "../../common/components/MsTableHeader";
|
||||
import MsTableOperator from "../../common/components/MsTableOperator";
|
||||
|
@ -58,6 +69,7 @@
|
|||
|
||||
export default {
|
||||
components: {
|
||||
OneClickOperation,
|
||||
MsTableOperators,
|
||||
MsApiTestStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, MsTableOperator
|
||||
},
|
||||
|
@ -74,6 +86,9 @@
|
|||
pageSize: 5,
|
||||
total: 0,
|
||||
loading: false,
|
||||
selectIds: new Set(),
|
||||
selectNames: new Set(),
|
||||
selectProjectNames: new Set(),
|
||||
buttons: [
|
||||
{
|
||||
tip: this.$t('commons.edit'), icon: "el-icon-edit",
|
||||
|
@ -105,16 +120,46 @@
|
|||
create() {
|
||||
this.$router.push('/api/test/create');
|
||||
},
|
||||
|
||||
handleSelectAll(selection) {
|
||||
if (selection.length > 0) {
|
||||
this.tableData.forEach(item => {
|
||||
this.selectIds.add(item.id);
|
||||
this.selectProjectNames.add(item.projectName)
|
||||
});
|
||||
} else {
|
||||
this.selectIds.clear()
|
||||
this.selectProjectNames.clear()
|
||||
}
|
||||
},
|
||||
selectionChange(selection, row) {
|
||||
if (this.selectIds.has(row.id)) {
|
||||
this.selectIds.delete(row.id);
|
||||
this.selectProjectNames.delete(row.projectName)
|
||||
} else {
|
||||
this.selectIds.add(row.id);
|
||||
this.selectProjectNames.add(row.projectName)
|
||||
}
|
||||
},
|
||||
runTest() {
|
||||
if (this.selectIds.size < 1) {
|
||||
this.$warning(this.$t('test_track.plan_view.select_manipulate'));
|
||||
} else {
|
||||
this.$refs.OneClickOperation.openOneClickOperation();
|
||||
}
|
||||
},
|
||||
search() {
|
||||
if (this.projectId !== 'all') {
|
||||
this.condition.projectId = this.projectId;
|
||||
}
|
||||
|
||||
let url = "/api/list/" + this.currentPage + "/" + this.pageSize;
|
||||
this.result = this.$post(url, this.condition, response => {
|
||||
let data = response.data;
|
||||
this.total = data.itemCount;
|
||||
this.tableData = data.listObject;
|
||||
this.tableData.forEach(item => {
|
||||
this.selectNames.add(item.name)
|
||||
})
|
||||
});
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:title="$t('load_test.run')"
|
||||
:visible.sync="oneClickOperationVisible"
|
||||
width="30%"
|
||||
left
|
||||
:destroy-on-close="true"
|
||||
show-close
|
||||
@closed="handleClose">
|
||||
<el-form :model="ruleForm" label-position="right" label-width="120px" size="small" :rules="rule">
|
||||
<el-form-item :label="$t('test_track.case.test_name')" prop="testName">
|
||||
<el-input v-model="ruleForm.testName" autocomplete="off" clearable show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<ms-dialog-footer
|
||||
@cancel="oneClickOperationVisible = false"
|
||||
@confirm="checkedSaveAndRunTest"/>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsDialogFooter from '../../common/components/MsDialogFooter'
|
||||
import {Test} from "./model/ScenarioModel";
|
||||
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
|
||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||
import MsApiReportDialog from "./ApiReportDialog";
|
||||
import {removeGoBackListener} from "../../../../common/js/utils";
|
||||
|
||||
|
||||
export default {
|
||||
name: "OneClickOperation",
|
||||
components: {
|
||||
MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig, MsDialogFooter
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
oneClickOperationVisible: false,
|
||||
test: null,
|
||||
tests: [],
|
||||
ruleForm: {},
|
||||
rule: {
|
||||
testName: [
|
||||
{required: true, message: this.$t('api_test.input_name'), trigger: 'blur'},
|
||||
],
|
||||
}
|
||||
};
|
||||
},
|
||||
props: {
|
||||
selectIds: {
|
||||
type: Set
|
||||
},
|
||||
selectNames: {
|
||||
type: Set
|
||||
},
|
||||
selectProjectNames: {
|
||||
type: Set
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openOneClickOperation() {
|
||||
this.oneClickOperationVisible = true;
|
||||
},
|
||||
checkedSaveAndRunTest() {
|
||||
if (this.selectNames.has(this.testName)) {
|
||||
this.$warning(this.$t('load_test.already_exists'));
|
||||
} else {
|
||||
if (this.selectProjectNames.size > 1) {
|
||||
this.$warning(this.$t('load_test.same_project_test'));
|
||||
} else {
|
||||
for (let x of this.selectIds) {
|
||||
this.getTest(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getTest(id) {
|
||||
this.result = this.$get("/api/get/" + id, response => {
|
||||
if (response.data) {
|
||||
let item = response.data;
|
||||
this.tests.push(item);
|
||||
let test = new Test({
|
||||
projectId: item.projectId,
|
||||
name: this.ruleForm.testName,
|
||||
scenarioDefinition: JSON.parse(item.scenarioDefinition),
|
||||
schedule: {},
|
||||
});
|
||||
this.test = this.test || test;
|
||||
this.test.scenarioDefinition = this.test.scenarioDefinition.concat(test.scenarioDefinition);
|
||||
if (this.tests.length === this.selectIds.size) {
|
||||
this.tests = [];
|
||||
this.saveRunTest();
|
||||
this.oneClickOperationVisible = false;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
saveRunTest() {
|
||||
this.save(() => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.runTest();
|
||||
})
|
||||
},
|
||||
save(callback) {
|
||||
let url = "/api/create";
|
||||
this.result = this.$request(this.getOptions(url), () => {
|
||||
this.create = false;
|
||||
if (callback) callback();
|
||||
});
|
||||
},
|
||||
runTest() {
|
||||
this.result = this.$post("/api/run", {id: this.test.id, triggerMode: 'MANUAL'}, (response) => {
|
||||
this.$success(this.$t('api_test.running'));
|
||||
this.$router.push({
|
||||
path: '/api/report/view/' + response.data
|
||||
})
|
||||
});
|
||||
},
|
||||
getOptions(url) {
|
||||
let formData = new FormData();
|
||||
let requestJson = JSON.stringify(this.test);
|
||||
formData.append('request', new Blob([requestJson], {
|
||||
type: "application/json"
|
||||
}));
|
||||
let jmx = this.test.toJMX();
|
||||
let blob = new Blob([jmx.xml], {type: "application/octet-stream"});
|
||||
formData.append("files", new File([blob], jmx.name));
|
||||
return {
|
||||
method: 'POST',
|
||||
url: url,
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': undefined
|
||||
}
|
||||
};
|
||||
},
|
||||
handleClose() {
|
||||
this.ruleForm = {}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -5,9 +5,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsMainContainer"
|
||||
}
|
||||
export default {
|
||||
name: "MsMainContainer"
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
<span class="operate-button">
|
||||
<ms-table-button :is-tester-permission="isTesterPermission" v-if="showCreate" icon="el-icon-circle-plus-outline"
|
||||
:content="createTip" @click="create"/>
|
||||
<ms-table-button :is-tester-permission="isTesterPermission" v-if="showRun" icon="el-icon-video-play"
|
||||
type="primary"
|
||||
:content="runTip" @click="runTest"/>
|
||||
|
||||
<slot name="button"></slot>
|
||||
</span>
|
||||
<span>
|
||||
|
@ -40,6 +44,10 @@
|
|||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showRun: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
condition: {
|
||||
type: Object
|
||||
},
|
||||
|
@ -49,6 +57,11 @@
|
|||
return this.$t('commons.create');
|
||||
}
|
||||
},
|
||||
runTip: {
|
||||
type: String,
|
||||
|
||||
},
|
||||
|
||||
isTesterPermission: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
|
@ -61,6 +74,9 @@
|
|||
},
|
||||
create() {
|
||||
this.$emit('create');
|
||||
},
|
||||
runTest() {
|
||||
this.$emit('runTest')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
changeRoute() {
|
||||
// 解决在列表页面点击 显示全部 无效的问题(点击显示全部后改变路由)
|
||||
this.$router.push(this.index + '/all');
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -269,6 +269,8 @@ export default {
|
|||
not_exist: "Test report does not exist",
|
||||
},
|
||||
load_test: {
|
||||
same_project_test: 'Only tests within the same project can be run',
|
||||
run: 'One click operation',
|
||||
operating: 'Operating',
|
||||
pressure_prediction_chart: 'Pressure Prediction Chart',
|
||||
recent: 'Recent Tests',
|
||||
|
|
|
@ -267,6 +267,8 @@ export default {
|
|||
not_exist: "测试报告不存在",
|
||||
},
|
||||
load_test: {
|
||||
same_project_test: '只能运行同一项目内的测试',
|
||||
already_exists: '测试名称不能重复',
|
||||
operating: '操作',
|
||||
recent: '最近的测试',
|
||||
search_by_name: '根据名称搜索',
|
||||
|
@ -319,6 +321,7 @@ export default {
|
|||
custom_http_code: '自定义 HTTP 响应成功状态码',
|
||||
separated_by_commas: '按逗号分隔',
|
||||
create: '创建测试',
|
||||
run: '一键运行',
|
||||
select_resource_pool: '请选择资源池',
|
||||
resource_pool_is_null: '资源池为空',
|
||||
download_log_file: '下载完整日志文件',
|
||||
|
|
|
@ -267,6 +267,8 @@ export default {
|
|||
not_exist: "測試報告不存在",
|
||||
},
|
||||
load_test: {
|
||||
same_project_test: '只能運行同一項目內的測試',
|
||||
run: '一鍵運行',
|
||||
operating: '操作',
|
||||
recent: '最近的測試',
|
||||
search_by_name: '根據名稱搜索',
|
||||
|
|
Loading…
Reference in New Issue