feat(UI自动化): 新增UI报告分享

--story=1009465 --user=刘瑶 【UI测试】报告支持分享功能 https://www.tapd.cn/55049933/s/1238555
This commit is contained in:
nathan.liu 2022-09-01 10:16:35 +08:00 committed by nathanliu2022
parent 459a26615f
commit 7e582596a7
17 changed files with 185 additions and 33 deletions

View File

@ -63,6 +63,7 @@ public class ShiroUtils {
filterChainDefinitionMap.put("/sharePlanReport", "anon"); filterChainDefinitionMap.put("/sharePlanReport", "anon");
filterChainDefinitionMap.put("/sharePerformanceReport", "anon"); filterChainDefinitionMap.put("/sharePerformanceReport", "anon");
filterChainDefinitionMap.put("/shareApiReport", "anon"); filterChainDefinitionMap.put("/shareApiReport", "anon");
filterChainDefinitionMap.put("/shareUiReport", "anon");
filterChainDefinitionMap.put("/system/theme", "anon"); filterChainDefinitionMap.put("/system/theme", "anon");
filterChainDefinitionMap.put("/system/save/baseurl/**", "anon"); filterChainDefinitionMap.put("/system/save/baseurl/**", "anon");

View File

@ -51,4 +51,9 @@ public class IndexController {
public String shareApiRedirect() { public String shareApiRedirect() {
return "share-api-report.html"; return "share-api-report.html";
} }
@GetMapping(value = "/shareUiReport")
public String shareUiRedirect() {
return "share-ui-report.html";
}
} }

View File

@ -12,6 +12,7 @@ public class ProjectConfig {
private String trackShareReportTime; private String trackShareReportTime;
private String performanceShareReportTime; private String performanceShareReportTime;
private String apiShareReportTime; private String apiShareReportTime;
private String uiShareReportTime;
private Boolean caseCustomNum = false; private Boolean caseCustomNum = false;
private Boolean scenarioCustomNum = false; private Boolean scenarioCustomNum = false;
private String apiQuickMenu; private String apiQuickMenu;
@ -25,6 +26,8 @@ public class ProjectConfig {
private String cleanApiReportExpr; private String cleanApiReportExpr;
private Boolean cleanLoadReport = false; private Boolean cleanLoadReport = false;
private String cleanLoadReportExpr; private String cleanLoadReportExpr;
private Boolean cleanUiReport = false;
private String cleanUiReportExpr;
private Boolean urlRepeatable = false; private Boolean urlRepeatable = false;
private String triggerUpdate; private String triggerUpdate;
private Boolean openUpdateTime = false; private Boolean openUpdateTime = false;

View File

@ -53,8 +53,10 @@ public class CleanUpReportJob extends MsScheduleJob {
if (BooleanUtils.isTrue(config.getCleanLoadReport())) { if (BooleanUtils.isTrue(config.getCleanLoadReport())) {
this.doCleanUp(projectService::cleanUpLoadReport, config.getCleanLoadReportExpr()); this.doCleanUp(projectService::cleanUpLoadReport, config.getCleanLoadReportExpr());
} }
// 定时删除 UI 调试模式生成的截图 if (BooleanUtils.isTrue(config.getCleanUiReport())) {
projectService.cleanUpUiReportImg(); // 定时删除 UI 调试模式生成的截图
this.doCleanUp(projectService::cleanUpUiReportImg, config.getCleanUiReportExpr());
}
} catch (Exception e) { } catch (Exception e) {
LogUtil.error("clean up report error."); LogUtil.error("clean up report error.");
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);

View File

@ -1027,14 +1027,16 @@ public class ProjectService {
} }
// 删除 UI 报告产生的截图 // 删除 UI 报告产生的截图
public void cleanUpUiReportImg() { public void cleanUpUiReportImg(long backupTime, String projectId) {
try { try {
// 属于定时任务删除调试报告情况 // 属于定时任务删除调试报告情况
// 获取昨天的当前时间 // 获取昨天的当前时间
Date backupTime = org.apache.commons.lang3.time.DateUtils.addDays(new Date(), -1); // Date backupTime = org.apache.commons.lang3.time.DateUtils.addDays(new Date(), -1);
// 清理类型为 UI 报告类型且时间为昨天之前的 UI 调试类型报告截图 // 清理类型为 UI 报告类型且时间为昨天之前的 UI 调试类型报告截图
ApiScenarioReportExample example = new ApiScenarioReportExample(); ApiScenarioReportExample example = new ApiScenarioReportExample();
example.createCriteria().andCreateTimeLessThan(backupTime.getTime()).andReportTypeEqualTo(ReportTypeConstants.UI_INDEPENDENT.name()) example.createCriteria()
.andProjectIdEqualTo(projectId)
.andCreateTimeLessThan(backupTime).andReportTypeEqualTo(ReportTypeConstants.UI_INDEPENDENT.name())
.andExecuteTypeEqualTo(ExecuteType.Debug.name()); .andExecuteTypeEqualTo(ExecuteType.Debug.name());
List<ApiScenarioReport> apiScenarioReports = apiScenarioReportMapper.selectByExample(example); List<ApiScenarioReport> apiScenarioReports = apiScenarioReportMapper.selectByExample(example);
// 删除调试报告的截图 // 删除调试报告的截图

@ -1 +1 @@
Subproject commit 73584558c69e47496daa0e40b19f162c479693f8 Subproject commit 53c8fbe1c2a3beff233546305206621047b03dbd

View File

@ -31,7 +31,7 @@
</el-button> </el-button>
<el-popover <el-popover
v-if="!isPlan && (!debug || exportFlag) && !isTemplate && !isUi" v-if="!isPlan && (!debug || exportFlag) && !isTemplate"
v-permission="['PROJECT_PERFORMANCE_REPORT:READ+EXPORT']" v-permission="['PROJECT_PERFORMANCE_REPORT:READ+EXPORT']"
style="margin-right: 10px;float: right;" style="margin-right: 10px;float: right;"
placement="bottom" placement="bottom"
@ -55,12 +55,12 @@
{{ $t('api_test.automation.rerun') }} {{ $t('api_test.automation.rerun') }}
</el-button> </el-button>
<ui-download-screenshot :report="report" v-if="isUi && showCancelButton"/>
<el-button v-if="showCancelButton" class="export-button" plain size="mini" @click="returnView"> <el-button v-if="showCancelButton" class="export-button" plain size="mini" @click="returnView">
{{ $t('commons.cancel') }} {{ $t('commons.cancel') }}
</el-button> </el-button>
<ui-download-screenshot :report="report" v-if="isUi"/>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -176,13 +176,22 @@ export default {
let pram = {}; let pram = {};
pram.customData = report.id; pram.customData = report.id;
pram.shareType = 'API_REPORT'; pram.shareType = 'API_REPORT';
let thisHost = window.location.host;
let shareUrl = thisHost + "/shareApiReport";
if(this.isUi){
pram.shareType = 'UI_REPORT';
shareUrl = thisHost + "/shareUiReport";
}
generateShareInfoWithExpired(pram, (data) => { generateShareInfoWithExpired(pram, (data) => {
let thisHost = window.location.host; this.shareUrl = shareUrl + data.shareUrl;
this.shareUrl = thisHost + "/shareApiReport" + data.shareUrl;
}); });
}, },
getProjectApplication() { getProjectApplication() {
this.$get('/project_application/get/' + getCurrentProjectID() + "/API_SHARE_REPORT_TIME", res => { let path = "/API_SHARE_REPORT_TIME";
if(this.isUi){
path = "/UI_SHARE_REPORT_TIME";
}
this.$get('/project_application/get/' + getCurrentProjectID() + path, res => {
if (res.data) { if (res.data) {
let quantity = res.data.typeValue.substring(0, res.data.typeValue.length - 1); let quantity = res.data.typeValue.substring(0, res.data.typeValue.length - 1);
let unit = res.data.typeValue.substring(res.data.typeValue.length - 1); let unit = res.data.typeValue.substring(res.data.typeValue.length - 1);

View File

@ -121,24 +121,45 @@
<!-- UI 测试 --> <!-- UI 测试 -->
<el-tab-pane :label="$t('commons.ui_test')" name="ui_test"> <el-tab-pane :label="$t('commons.ui_test')" name="ui_test">
<el-row style="margin-top: 10px"> <!-- 启用设置 -->
<span style="font-weight:bold">{{ $t('commons.view_settings') }}</span> <el-col :span="8" class="commons-api-enable">
</el-row> <el-row style="margin-top: 10px">
<el-row style="margin-top: 15px"> <span style="font-weight:bold">{{ this.$t('commons.enable_settings') }}</span>
<app-manage-item :title="$t('ui.ui_debug_mode')" </el-row>
:append-span="12" :prepend-span="12" :middle-span="0"> <el-row style="margin-top: 15px">
<template #append> <timing-item ref="uiTimingItem" :choose.sync="config.cleanUiReport"
<el-radio-group v-model="config.uiQuickMenu" @change="switchChange('UI_QUICK_MENU', $event)"> :expr.sync="config.cleanUiReportExpr"
<el-radio label="local" value="local" :disabled="!isXpack"> @chooseChange="switchChange('CLEAN_UI_REPORT', config.cleanUiReport, ['CLEAN_UI_REPORT_EXPR', config.cleanUiReportExpr])"
{{ $t('ui.ui_local_debug') }} :title="$t('project.timing_clean_ui_report')"/>
</el-radio> <timing-item ref="uiTimingItem" :choose.sync="config.shareReport"
<el-radio label="server" value="server" :disabled="!isXpack"> :expr.sync="config.uiShareReportTime" :share-link="true"
{{ $t('ui.ui_server_debug') }} :unit-options="applyUnitOptions"
</el-radio> @chooseChange="switchChange('UI_SHARE_REPORT_TIME', config.uiShareReportTime)"
</el-radio-group> :title="$t('report.report_sharing_link')"/>
</template> </el-row>
</app-manage-item> </el-col>
</el-row>
<!-- 显示设置 -->
<el-col :span="8" class="commons-view-setting">
<el-row style="margin-top: 10px">
<span style="font-weight:bold">{{ $t('commons.view_settings') }}</span>
</el-row>
<el-row style="margin-top: 15px">
<app-manage-item :title="$t('ui.ui_debug_mode')"
:append-span="12" :prepend-span="12" :middle-span="0">
<template #append>
<el-radio-group v-model="config.uiQuickMenu" @change="switchChange('UI_QUICK_MENU', $event)">
<el-radio label="local" value="local" :disabled="!isXpack">
{{ $t('ui.ui_local_debug') }}
</el-radio>
<el-radio label="server" value="server" :disabled="!isXpack">
{{ $t('ui.ui_server_debug') }}
</el-radio>
</el-radio-group>
</template>
</app-manage-item>
</el-row>
</el-col>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('commons.performance')" name="performance"> <el-tab-pane :label="$t('commons.performance')" name="performance">
@ -297,7 +318,9 @@ export default {
cleanApiReport: false, cleanApiReport: false,
cleanApiReportExpr: "", cleanApiReportExpr: "",
cleanLoadReport: false, cleanLoadReport: false,
cleanLoadReportExpr: "" cleanLoadReportExpr: "",
cleanUiReport: false,
cleanUiReportExpr: ""
}, },
count: 0, count: 0,
isXpack: false, isXpack: false,
@ -320,6 +343,7 @@ export default {
config: { config: {
trackShareReportTime: "", trackShareReportTime: "",
performanceShareReportTime: "", performanceShareReportTime: "",
uiShareReportTime: "",
apiShareReportTime: "", apiShareReportTime: "",
caseCustomNum: false, caseCustomNum: false,
scenarioCustomNum: false, scenarioCustomNum: false,
@ -334,6 +358,8 @@ export default {
cleanApiReportExpr: "", cleanApiReportExpr: "",
cleanLoadReport: false, cleanLoadReport: false,
cleanLoadReportExpr: "", cleanLoadReportExpr: "",
cleanUiReport: false,
cleanUiReportExpr: "",
urlRepeatable: false, urlRepeatable: false,
shareReport: true, shareReport: true,
openUpdateTime: false, openUpdateTime: false,

@ -1 +1 @@
Subproject commit 57f594ed643407d3a5513515dceda4c7ca2c1352 Subproject commit 5910db55736251f71f6bb024b3c7ae1e3ef4ea24

View File

@ -871,6 +871,7 @@ export default {
timing_clean_plan_report: "Regularly clean up test report", timing_clean_plan_report: "Regularly clean up test report",
timing_clean_api_report: "Regularly clean up api report", timing_clean_api_report: "Regularly clean up api report",
timing_clean_load_report: "Regularly clean up performance report", timing_clean_load_report: "Regularly clean up performance report",
timing_clean_ui_report: "Regularly clean up ui report",
keep_recent: "Keep recent", keep_recent: "Keep recent",
please_select_cleaning_time: "please select cleaning time" please_select_cleaning_time: "please select cleaning time"
}, },

View File

@ -878,7 +878,8 @@ export default {
}, },
timing_clean_plan_report: "定时清理测试计划报告", timing_clean_plan_report: "定时清理测试计划报告",
timing_clean_api_report: "定时清理接口测试报告", timing_clean_api_report: "定时清理接口测试报告",
timing_clean_load_report: "定时清理性能测试报告", timing_clean_load_report: "定时清理性能测试报告",
timing_clean_ui_report: "定时清理UI测试报告",
keep_recent: "保留最近", keep_recent: "保留最近",
please_select_cleaning_time: "请选择清理时间!" please_select_cleaning_time: "请选择清理时间!"
}, },

View File

@ -876,6 +876,7 @@ export default {
timing_clean_plan_report: "定時清理測試計劃報告", timing_clean_plan_report: "定時清理測試計劃報告",
timing_clean_api_report: "定時清理接口測試報告", timing_clean_api_report: "定時清理接口測試報告",
timing_clean_load_report: "定時清理性能測試報告", timing_clean_load_report: "定時清理性能測試報告",
timing_clean_ui_report: "定時清理UI測試報告",
keep_recent: "保留最近", keep_recent: "保留最近",
please_select_cleaning_time: "請選擇清理時間!" please_select_cleaning_time: "請選擇清理時間!"
}, },

View File

@ -0,0 +1,36 @@
<template>
<UiShareReportDetail :report-id="reportId" :share-id="shareId" :is-share="isShare" :is-plan="true" :show-cancel-button="false" ></UiShareReportDetail>
</template>
<script>
import {getShareId} from "@/common/js/utils";
import {getShareInfo} from "@/network/share";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const UiShareReportDetail = requireComponent.keys().length > 0 ? requireComponent("./ui/automation/report/UiShareReportDetail.vue") : {};
export default {
name: "ShareUiReportTemplate",
components: {'UiShareReportDetail' : UiShareReportDetail.default},
data() {
return {
reportId: '',
shareId: '',
isShare: true,
};
},
created() {
this.shareId = getShareId();
getShareInfo(this.shareId, (data) => {
if (!data) {
this.$error('报告已删除!');
return;
}
if (data.shareType === 'UI_REPORT') {
this.reportId = data.customData;
}
});
},
};
</script>
<style scoped>
</style>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="shortcut icon" href="<%= BASE_URL %>favicon.ico">
<title>Ui Report</title>
</head>
<body>
<div id="shareUiReport"></div>
</body>
</html>

View File

@ -0,0 +1,4 @@
import ShareUiReportTemplate from "@/template/report/ui/share/ShareUiReportTemplate";
import uiReportUse from "@/template/report/ui/uiReportUse";
uiReportUse('#shareUiReport', ShareUiReportTemplate);

View File

@ -0,0 +1,43 @@
import Vue from 'vue';
import ElementUI, {Button, Card, Col, Form, FormItem, Input, Main, Popover, Row, Table, TableColumn} from 'element-ui';
import '@/assets/theme/index.css';
import '@/common/css/menu-header.css';
import '@/common/css/main.css';
import i18n from "@/i18n/i18n";
import chart from "@/common/js/chart";
import filters from "@/common/js/filter";
import icon from "@/common/js/icon";
import message from "@/common/js/message";
import ajax from "@/common/js/ajax";
function uiReportUse(id, template) {
Vue.use(ElementUI, {
i18n: (key, value) => i18n.t(key, value)
});
Vue.use(Row);
Vue.use(Col);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Input);
Vue.use(Button);
Vue.use(chart);
Vue.use(Main);
Vue.use(Card);
Vue.use(TableColumn);
Vue.use(Table);
Vue.use(filters);
Vue.use(icon);
Vue.use(message);
Vue.use(ajax);
Vue.use(Popover);
new Vue({
el: id,
i18n,
render: h => h(template)
});
}
export default uiReportUse;

View File

@ -49,6 +49,11 @@ module.exports = {
template: "src/template/report/api/share/share-api-report.html", template: "src/template/report/api/share/share-api-report.html",
filename: "share-api-report.html", filename: "share-api-report.html",
}, },
shareUiReport: {
entry: "src/template/report/ui/share/share-ui-report.js",
template: "src/template/report/ui/share/share-ui-report.html",
filename: "share-ui-report.html",
},
enterpriseReport: { enterpriseReport: {
entry: "src/template/enterprise/share/share-enterprise-report.js", entry: "src/template/enterprise/share/share-enterprise-report.js",
template: "src/template/enterprise/share/share-enterprise-report.html", template: "src/template/enterprise/share/share-enterprise-report.html",