Merge branch 'master' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
d30cb9246a
|
@ -137,6 +137,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
requestResult.setBody(result.getSamplerData());
|
||||
requestResult.setHeaders(result.getRequestHeaders());
|
||||
requestResult.setRequestSize(result.getSentBytes());
|
||||
requestResult.setStartTime(result.getStartTime());
|
||||
requestResult.setTotalAssertions(result.getAssertionResults().length);
|
||||
requestResult.setSuccess(result.isSuccessful());
|
||||
requestResult.setError(result.getErrorCount());
|
||||
|
|
|
@ -16,6 +16,8 @@ public class RequestResult {
|
|||
|
||||
private long requestSize;
|
||||
|
||||
private long startTime;
|
||||
|
||||
private int error;
|
||||
|
||||
private boolean success;
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.quartz.TriggerKey;
|
|||
public class ApiTestJob extends MsScheduleJob {
|
||||
|
||||
private APITestService apiTestService;
|
||||
private MailService mailService;
|
||||
public ApiTestJob() {
|
||||
apiTestService = (APITestService) CommonBeanFactory.getBean(APITestService.class);
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c2dacf960cdb1ed35664bdd3432120b1203b73d8
|
||||
Subproject commit cf6b06526324326a563d933e07118fac014a63b4
|
|
@ -90,6 +90,10 @@ export default {
|
|||
methods: {
|
||||
registerEvents() {
|
||||
ApiEvent.$on(LIST_CHANGE, () => {
|
||||
// todo 这里偶尔会有 refs 为空的情况
|
||||
if (!this.$refs.projectRecent) {
|
||||
return;
|
||||
}
|
||||
this.$refs.projectRecent.recent();
|
||||
this.$refs.testRecent.recent();
|
||||
this.$refs.reportRecent.recent();
|
||||
|
|
|
@ -1,232 +1,25 @@
|
|||
<template>
|
||||
<ms-container v-loading="loading" :element-loading-text="$t('api_report.running')">
|
||||
<ms-main-container>
|
||||
<el-card>
|
||||
<section class="report-container" v-if="this.report.testId">
|
||||
<header class="report-header">
|
||||
<el-row>
|
||||
<el-col>
|
||||
<span>{{ report.projectName }} / </span>
|
||||
<router-link :to="path">{{ report.testName }}</router-link>
|
||||
<span class="time">{{ report.createTime | timestampFormatDate }}</span>
|
||||
<el-button class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)"
|
||||
style="margin-left: 1200px">
|
||||
{{$t('test_track.plan_view.export_report')}}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</header>
|
||||
<main v-if="this.isNotRunning">
|
||||
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<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>
|
||||
<ms-api-report-export v-if="reportExportVisible" id="apiTestReport" :title="report.testName" :content="content" :total-time="totalTime"/>
|
||||
</main>
|
||||
</section>
|
||||
</el-card>
|
||||
</ms-main-container>
|
||||
</ms-container>
|
||||
<ms-api-report-view-detail :report-id="reportId"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
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";
|
||||
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||
import MsApiReportExport from "./ApiReportExport";
|
||||
import {exportPdf} from "../../../../common/js/utils";
|
||||
import html2canvas from "html2canvas";
|
||||
import MsApiReportViewDetail from "./ApiReportViewDetail";
|
||||
|
||||
export default {
|
||||
name: "MsApiReportView",
|
||||
components: {
|
||||
MsApiReportExport,
|
||||
MsMainContainer,
|
||||
MsContainer, MsScenarioResults, MsRequestResultTail, MsMetricChart, MsScenarioResult, MsRequestResult
|
||||
MsApiReportViewDetail,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "total",
|
||||
content: {},
|
||||
report: {},
|
||||
loading: true,
|
||||
fails: [],
|
||||
totalTime: 0,
|
||||
isRequestResult: false,
|
||||
request: {},
|
||||
scenarioName: null,
|
||||
reportExportVisible: false
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
this.isRequestResult = false
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.loading = true;
|
||||
this.report = {};
|
||||
this.content = {};
|
||||
this.fails = [];
|
||||
this.isRequestResult = false;
|
||||
},
|
||||
handleClick(tab, event) {
|
||||
this.isRequestResult = false
|
||||
},
|
||||
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.totalTime = 0
|
||||
this.content.scenarios.forEach((scenario) => {
|
||||
this.totalTime = this.totalTime + Number(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 = false;
|
||||
this.$nextTick(function () {
|
||||
this.isRequestResult = true;
|
||||
this.request = requestResult.request;
|
||||
this.scenarioName = requestResult.scenarioName;
|
||||
});
|
||||
},
|
||||
handleExport(name) {
|
||||
this.loading = true;
|
||||
this.reportExportVisible = true;
|
||||
let reset = this.exportReportReset;
|
||||
|
||||
this.$nextTick(function () {
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById('apiTestReport'), {
|
||||
scale: 2
|
||||
}).then(function(canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
reset();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
exportReportReset() {
|
||||
this.reportExportVisible = false;
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route': 'getReport',
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.report-container {
|
||||
height: calc(100vh - 155px);
|
||||
min-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.report-header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.report-header .time {
|
||||
color: #909399;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.report-container .fail {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.report-container .is-active .fail {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.export-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
<template>
|
||||
<ms-container v-loading="loading" :element-loading-text="$t('api_report.running')">
|
||||
<ms-main-container>
|
||||
<el-card>
|
||||
<section class="report-container" v-if="this.report.testId">
|
||||
|
||||
<ms-api-report-view-header :report="report" @reportExport="handleExport"/>
|
||||
|
||||
<main v-if="this.isNotRunning">
|
||||
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<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>
|
||||
<ms-api-report-export v-if="reportExportVisible" id="apiTestReport" :title="report.testName" :content="content" :total-time="totalTime"/>
|
||||
</main>
|
||||
</section>
|
||||
</el-card>
|
||||
</ms-main-container>
|
||||
</ms-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
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";
|
||||
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||
import MsApiReportExport from "./ApiReportExport";
|
||||
import {exportPdf} from "../../../../common/js/utils";
|
||||
import html2canvas from "html2canvas";
|
||||
import MsApiReportViewHeader from "./ApiReportViewHeader";
|
||||
|
||||
export default {
|
||||
name: "MsApiReportViewDetail",
|
||||
components: {
|
||||
MsApiReportViewHeader,
|
||||
MsApiReportExport,
|
||||
MsMainContainer,
|
||||
MsContainer, MsScenarioResults, MsRequestResultTail, MsMetricChart, MsScenarioResult, MsRequestResult
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "total",
|
||||
content: {},
|
||||
report: {},
|
||||
loading: true,
|
||||
fails: [],
|
||||
totalTime: 0,
|
||||
isRequestResult: false,
|
||||
request: {},
|
||||
scenarioName: null,
|
||||
reportExportVisible: false
|
||||
}
|
||||
},
|
||||
props: ['reportId'],
|
||||
activated() {
|
||||
this.isRequestResult = false;
|
||||
},
|
||||
watch: {
|
||||
reportId() {
|
||||
this.getReport();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.loading = true;
|
||||
this.report = {};
|
||||
this.content = {};
|
||||
this.fails = [];
|
||||
this.report = {};
|
||||
this.isRequestResult = false;
|
||||
},
|
||||
handleClick(tab, event) {
|
||||
this.isRequestResult = false
|
||||
},
|
||||
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.totalTime = 0
|
||||
this.content.scenarios.forEach((scenario) => {
|
||||
this.totalTime = this.totalTime + Number(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 = false;
|
||||
this.$nextTick(function () {
|
||||
this.isRequestResult = true;
|
||||
this.request = requestResult.request;
|
||||
this.scenarioName = requestResult.scenarioName;
|
||||
});
|
||||
},
|
||||
handleExport(name) {
|
||||
this.loading = true;
|
||||
this.reportExportVisible = true;
|
||||
let reset = this.exportReportReset;
|
||||
|
||||
this.$nextTick(function () {
|
||||
setTimeout(() => {
|
||||
html2canvas(document.getElementById('apiTestReport'), {
|
||||
scale: 2
|
||||
}).then(function(canvas) {
|
||||
exportPdf(name, [canvas]);
|
||||
reset();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
exportReportReset() {
|
||||
this.reportExportVisible = false;
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.getReport();
|
||||
},
|
||||
|
||||
computed: {
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.report-container {
|
||||
height: calc(100vh - 155px);
|
||||
min-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.report-header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.report-header .time {
|
||||
color: #909399;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.report-container .fail {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.report-container .is-active .fail {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.export-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<header class="report-header">
|
||||
<el-row>
|
||||
<el-col>
|
||||
<span>{{ report.projectName }} / </span>
|
||||
<router-link :to="path">{{ report.testName }}</router-link>
|
||||
<span class="time">{{ report.createTime | timestampFormatDate }}</span>
|
||||
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)"
|
||||
style="margin-left: 1200px">
|
||||
{{$t('test_track.plan_view.export_report')}}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {checkoutTestManagerOrTestUser} from "../../../../common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsApiReportViewHeader",
|
||||
props: ['report'],
|
||||
computed: {
|
||||
path() {
|
||||
return "/api/test/edit?id=" + this.report.testId;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isReadOnly: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!checkoutTestManagerOrTestUser()) {
|
||||
this.isReadOnly = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleExport(name) {
|
||||
this.$emit('reportExport', name);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.export-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -2,10 +2,13 @@
|
|||
<div class="request-result">
|
||||
<div @click="active">
|
||||
<el-row :gutter="10" type="flex" align="middle" class="info">
|
||||
<el-col :span="16">
|
||||
<el-col :span="12">
|
||||
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
|
||||
{{scenarioName}}
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
{{$t('api_report.start_time')}}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
{{$t('api_report.response_time')}}
|
||||
</el-col>
|
||||
|
@ -20,17 +23,20 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="10" type="flex" align="middle" class="info">
|
||||
<el-col :span="4">
|
||||
<el-col :span="2">
|
||||
<div class="method">
|
||||
{{request.method}}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col :span="10">
|
||||
<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="4">
|
||||
{{request.startTime | timestampFormatDate(true) }}
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<div class="time">
|
||||
{{request.responseResult.responseTime}}
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
</el-select>
|
||||
</el-input>
|
||||
|
||||
<el-tooltip :content="'Ctrl + S'"
|
||||
placement="top"
|
||||
:enterable="false">
|
||||
<el-button type="primary" plain :disabled="isReadOnly" @click="saveTest">
|
||||
{{ $t('commons.save') }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<el-button type="primary" plain :disabled="isReadOnly"
|
||||
@click="saveRunTest">
|
||||
|
@ -67,7 +71,7 @@
|
|||
|
||||
<script>
|
||||
import MsApiScenarioConfig from "./components/ApiScenarioConfig";
|
||||
import {Test, Scenario} from "./model/ScenarioModel"
|
||||
import {Scenario, Test} from "./model/ScenarioModel"
|
||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||
import MsApiReportDialog from "./ApiReportDialog";
|
||||
import {checkoutTestManagerOrTestUser, downloadFile, getUUID} from "@/common/js/utils";
|
||||
|
@ -368,11 +372,25 @@ export default {
|
|||
this.debugReportId = response.data;
|
||||
this.resetBodyFile();
|
||||
});
|
||||
},
|
||||
handleEvent(event) {
|
||||
if (event.keyCode === 83 && event.ctrlKey) {
|
||||
console.log('拦截到 ctrl + s');//ctrl+s
|
||||
this.saveTest();
|
||||
event.preventDefault();
|
||||
event.returnValue = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.init();
|
||||
//
|
||||
document.addEventListener('keydown', this.handleEvent)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleEvent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -147,6 +147,7 @@ export default {
|
|||
deleteScenario(index) {
|
||||
this.scenarios.splice(index, 1);
|
||||
if (this.scenarios.length === 0) {
|
||||
this.type = this.types.CREATE;
|
||||
this.createScenario();
|
||||
this.select(this.scenarios[0]);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
codeTemplates: [
|
||||
{
|
||||
title: this.$t('api_test.request.processor.code_template_get_variable'),
|
||||
value: 'vars.get("variable_name");',
|
||||
value: 'vars.get("variable_name")',
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.request.processor.code_template_set_variable'),
|
||||
|
@ -42,17 +42,17 @@
|
|||
},
|
||||
{
|
||||
title: this.$t('api_test.request.processor.code_template_get_response_header'),
|
||||
value: 'prev.getResponseHeaders();',
|
||||
value: 'prev.getResponseHeaders()',
|
||||
disabled: this.isPreProcessor
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.request.processor.code_template_get_response_code'),
|
||||
value: 'prev.getResponseCode();',
|
||||
value: 'prev.getResponseCode()',
|
||||
disabled: this.isPreProcessor
|
||||
},
|
||||
{
|
||||
title: this.$t('api_test.request.processor.code_template_get_response_result'),
|
||||
value: 'prev.getResponseDataAsString();',
|
||||
value: 'prev.getResponseDataAsString()',
|
||||
disabled: this.isPreProcessor
|
||||
}
|
||||
],
|
||||
|
@ -93,6 +93,9 @@
|
|||
this.jsr223Processor.script = "";
|
||||
}
|
||||
this.jsr223Processor.script += template.value;
|
||||
if (this.jsr223Processor.language === 'beanshell') {
|
||||
this.jsr223Processor.script += ';';
|
||||
}
|
||||
this.reload();
|
||||
},
|
||||
reload() {
|
||||
|
|
|
@ -5,12 +5,25 @@
|
|||
<el-input v-model="request.name" maxlength="300" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<div class="one-row">
|
||||
<el-form-item :label="$t('api_test.request.sql.dataSource')" prop="dataSource">
|
||||
<el-select v-model="request.dataSource">
|
||||
<el-option v-for="(item, index) in databaseConfigsOptions" :key="index" :value="item.id" :label="item.name"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('api_test.request.sql.timeout')" prop="queryTimeout">
|
||||
<el-input-number :disabled="isReadOnly" size="mini" v-model="request.queryTimeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="request.useEnvironment"
|
||||
:active-text="$t('api_test.request.refer_to_environment')" @change="getDatabaseConfigsOptions">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="$t('api_test.request.sql.result_variable')" prop="resultVariable">
|
||||
<el-input v-model="request.resultVariable" maxlength="300" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
@ -25,17 +38,6 @@
|
|||
<!--</el-select>-->
|
||||
<!--</el-form-item>-->
|
||||
|
||||
<el-form-item :label="$t('api_test.request.sql.timeout')" prop="queryTimeout">
|
||||
<el-input-number :disabled="isReadOnly" size="mini" v-model="request.queryTimeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-switch
|
||||
v-model="request.useEnvironment"
|
||||
:active-text="$t('api_test.request.refer_to_environment')" @change="getDatabaseConfigsOptions">
|
||||
</el-switch>
|
||||
</el-form-item>
|
||||
|
||||
<el-button :disabled="!request.enable || !scenario.enable || isReadOnly" class="debug-button" size="small" type="primary" @click="runDebug">{{$t('api_test.request.debug')}}</el-button>
|
||||
|
||||
<el-tabs v-model="activeName">
|
||||
|
@ -147,4 +149,12 @@
|
|||
height: calc(100vh - 570px);
|
||||
}
|
||||
|
||||
.one-row .el-form-item {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.one-row .el-form-item:nth-child(2) {
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -98,6 +98,10 @@ export default {
|
|||
methods: {
|
||||
registerEvents() {
|
||||
PerformanceEvent.$on(LIST_CHANGE, () => {
|
||||
// todo 这里偶尔会有 refs 为空的情况
|
||||
if (!this.$refs.projectRecent) {
|
||||
return;
|
||||
}
|
||||
this.$refs.projectRecent.recent();
|
||||
this.$refs.testRecent.recent();
|
||||
this.$refs.reportRecent.recent();
|
||||
|
|
|
@ -150,6 +150,10 @@ export default {
|
|||
},
|
||||
registerEvents() {
|
||||
TrackEvent.$on(LIST_CHANGE, () => {
|
||||
// todo 这里偶尔会有 refs 为空的情况
|
||||
if (!this.$refs.projectRecent) {
|
||||
return;
|
||||
}
|
||||
this.$refs.projectRecent.recent();
|
||||
this.$refs.planRecent.recent();
|
||||
this.$refs.caseRecent.recent();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<ms-report-export-template :title="title" :type="$t('report.load_test_report')">
|
||||
<ms-report-export-template :title="title" :type="$t('report.test_plan_report')">
|
||||
<div v-for="(item, index) in previews" :key="item.id">
|
||||
<template-component :isReportView="true" :metric="metric" :preview="item" :index="index" ref="templateComponent"/>
|
||||
</div>
|
||||
|
|
|
@ -449,6 +449,7 @@
|
|||
testRun(reportId) {
|
||||
this.testCase.reportId = reportId;
|
||||
this.saveReport(reportId);
|
||||
this.activeTab = 'result';
|
||||
},
|
||||
testTabChange(data) {
|
||||
if (this.testCase.type == 'performance' && data.paneName == 'result') {
|
||||
|
|
|
@ -36,12 +36,12 @@
|
|||
<div v-for="(item, index) in previews" :key="item.id">
|
||||
<template-component :isReportView="true" :metric="metric" :preview="item" :index="index" ref="templateComponent"/>
|
||||
</div>
|
||||
<ms-test-case-report-export v-if="reportExportVisible" id="testCaseReportExport" :title="report.name" :metric="metric" :previews="previews"/>
|
||||
</el-main>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
</el-drawer>
|
||||
<ms-test-case-report-export v-if="reportExportVisible" id="testCaseReportExport" :title="report.name" :metric="metric" :previews="previews"/>
|
||||
<test-case-report-template-edit :metric="metric" ref="templateEdit" @refresh="getReport"/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</el-row>
|
||||
</el-header>
|
||||
|
||||
<ms-api-scenario-config :project-id="test.projectId" :is-read-only="true" :scenarios="test.scenarioDefinition" ref="config"/>
|
||||
<ms-api-scenario-config :test="test" :project-id="test.projectId" :is-read-only="true" :scenarios="test.scenarioDefinition" ref="config"/>
|
||||
|
||||
</el-container>
|
||||
</el-card>
|
||||
|
|
|
@ -1,136 +1,22 @@
|
|||
<template>
|
||||
<ms-container>
|
||||
<ms-main-container>
|
||||
<div>
|
||||
<span v-if="!reportId">{{$t('commons.not_performed_yet')}}</span>
|
||||
<el-card v-if="reportId">
|
||||
<section class="report-container" v-loading="loading">
|
||||
<header class="report-header">
|
||||
<span>{{report.projectName}} / </span>
|
||||
<span class="time">{{report.createTime | timestampFormatDate}}</span>
|
||||
</header>
|
||||
<main>
|
||||
<ms-metric-chart v-if="content" :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>
|
||||
</main>
|
||||
</section>
|
||||
</el-card>
|
||||
</ms-main-container>
|
||||
</ms-container>
|
||||
<ms-api-report-view-detail v-if="reportId" :report-id="reportId"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import MsScenarioResult from "../../../../../api/report/components/ScenarioResult";
|
||||
import MsMetricChart from "../../../../../api/report/components/MetricChart";
|
||||
import MsScenarioResults from "../../../../../api/report/components/ScenarioResults";
|
||||
import MsRequestResult from "../../../../../api/report/components/RequestResult";
|
||||
import MsContainer from "../../../../../common/components/MsContainer";
|
||||
import MsMainContainer from "../../../../../common/components/MsMainContainer";
|
||||
import MsApiReportViewDetail from "../../../../../api/report/ApiReportViewDetail";
|
||||
|
||||
export default {
|
||||
name: "ApiTestResult",
|
||||
components: {MsMainContainer, MsContainer, MsRequestResult, MsScenarioResults, MsMetricChart, MsScenarioResult},
|
||||
data() {
|
||||
return {
|
||||
activeName: "total",
|
||||
content: {},
|
||||
report: {},
|
||||
loading: true,
|
||||
fails: [],
|
||||
}
|
||||
},
|
||||
props:['reportId'],
|
||||
watch: {
|
||||
reportId() {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.loading = true;
|
||||
this.report = {};
|
||||
this.content = {};
|
||||
this.fails = [];
|
||||
this.getReport();
|
||||
},
|
||||
getReport() {
|
||||
if (this.reportId) {
|
||||
let url = "/api/report/get/" + this.reportId;
|
||||
this.$get(url, response => {
|
||||
this.report = response.data || {};
|
||||
if (this.report.status == 'Completed' || this.report.status == 'Success' || this.report.status == 'Error') {
|
||||
this.content = JSON.parse(this.report.content);
|
||||
this.getFails();
|
||||
this.loading = false;
|
||||
} else {
|
||||
setTimeout(this.getReport, 2000)
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
getFails() {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
components: {MsApiReportViewDetail},
|
||||
props: ['reportId'],
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.report-container .el-tabs__header {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.report-container {
|
||||
height: calc(100vh - 155px);
|
||||
min-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.report-header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.report-header .time {
|
||||
color: #909399;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.report-container .fail {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.report-container .is-active .fail {
|
||||
color: inherit;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -10,7 +10,7 @@ const options = function (value, array) {
|
|||
return value;
|
||||
};
|
||||
|
||||
const timestampFormatDate = function (timestamp) {
|
||||
const timestampFormatDate = function (timestamp, showMs) {
|
||||
if (!timestamp) {
|
||||
return timestamp
|
||||
}
|
||||
|
@ -34,7 +34,14 @@ const timestampFormatDate = function (timestamp) {
|
|||
let s = date.getSeconds();
|
||||
s = s < 10 ? ('0' + s) : s;
|
||||
|
||||
return y + '-' + MM + '-' + d + ' ' + h + ':' + m + ':' + s
|
||||
let format = y + '-' + MM + '-' + d + ' ' + h + ':' + m + ':' + s;
|
||||
|
||||
if (showMs === true) {
|
||||
let ms = date.getMilliseconds();
|
||||
format += ':' + ms
|
||||
}
|
||||
|
||||
return format
|
||||
};
|
||||
|
||||
const filters = {
|
||||
|
|
|
@ -255,7 +255,7 @@ export function exportPdf(name, canvasList) {
|
|||
}
|
||||
}
|
||||
|
||||
pdf.save(name + '.pdf');
|
||||
pdf.save(name.replace(" ", "_") + '.pdf');
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -598,6 +598,7 @@ export default {
|
|||
scenario_name: "Scenario name",
|
||||
response_time: "Response time(ms)",
|
||||
latency: "Latency",
|
||||
start_time: "Start Time",
|
||||
request_size: "Request Size",
|
||||
response_size: "Response Size",
|
||||
response_code: "Response Code",
|
||||
|
|
|
@ -598,6 +598,7 @@ export default {
|
|||
delete_confirm: '确认删除报告: ',
|
||||
delete_batch_confirm: '确认批量删除报告',
|
||||
scenario_name: "场景名称",
|
||||
start_time: "开始时间",
|
||||
response_time: "响应时间(ms)",
|
||||
latency: "网络延迟",
|
||||
request_size: "请求大小",
|
||||
|
|
|
@ -598,6 +598,7 @@ export default {
|
|||
delete_confirm: '確認刪除報告: ',
|
||||
delete_batch_confirm: '確認批量刪除報告',
|
||||
scenario_name: "場景名稱",
|
||||
start_time: "開始時間",
|
||||
response_time: "響應時間(ms)",
|
||||
latency: "網絡延遲",
|
||||
request_size: "請求大小",
|
||||
|
|
Loading…
Reference in New Issue