Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Captain.B 2020-04-21 16:59:10 +08:00
commit 536a2d7de2
14 changed files with 288 additions and 236 deletions

View File

@ -29,6 +29,11 @@ public class TestPlanTestCaseController {
return PageUtils.setPageInfo(page, testPlanTestCaseService.getTestPlanCases(request)); return PageUtils.setPageInfo(page, testPlanTestCaseService.getTestPlanCases(request));
} }
@PostMapping("/list/all")
public List<TestPlanCaseDTO> getTestPlanCases(@RequestBody QueryTestPlanCaseRequest request){
return testPlanTestCaseService.getTestPlanCases(request);
}
@PostMapping("/edit") @PostMapping("/edit")
public void editTestCase(@RequestBody TestPlanTestCase testPlanTestCase){ public void editTestCase(@RequestBody TestPlanTestCase testPlanTestCase){
testPlanTestCaseService.editTestCase(testPlanTestCase); testPlanTestCaseService.editTestCase(testPlanTestCase);

View File

@ -24,7 +24,7 @@ import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class JtlResolver { public class GenerateReport {
private static final Integer ERRORS_TOP_SIZE = 5; private static final Integer ERRORS_TOP_SIZE = 5;
private static final String DATE_TIME_PATTERN = "yyyy/MM/dd HH:mm:ss"; private static final String DATE_TIME_PATTERN = "yyyy/MM/dd HH:mm:ss";
@ -186,7 +186,7 @@ public class JtlResolver {
} }
} }
Map<String, List<Metric>> jtlMap = falseList.stream().collect(Collectors.groupingBy(JtlResolver::getResponseCodeAndFailureMessage)); Map<String, List<Metric>> jtlMap = falseList.stream().collect(Collectors.groupingBy(GenerateReport::getResponseCodeAndFailureMessage));
for (Map.Entry<String, List<Metric>> next : jtlMap.entrySet()) { for (Map.Entry<String, List<Metric>> next : jtlMap.entrySet()) {
String key = next.getKey(); String key = next.getKey();
@ -219,7 +219,7 @@ public class JtlResolver {
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<String, List<Metric>> collect = falseList.stream() Map<String, List<Metric>> collect = falseList.stream()
.collect(Collectors.groupingBy(JtlResolver::getResponseCodeAndFailureMessage)); .collect(Collectors.groupingBy(GenerateReport::getResponseCodeAndFailureMessage));
for (Map.Entry<String, List<Metric>> next : collect.entrySet()) { for (Map.Entry<String, List<Metric>> next : collect.entrySet()) {
String key = next.getKey(); String key = next.getKey();
@ -270,9 +270,9 @@ public class JtlResolver {
TestOverview testOverview = new TestOverview(); TestOverview testOverview = new TestOverview();
DecimalFormat decimalFormat = new DecimalFormat("0.00"); DecimalFormat decimalFormat = new DecimalFormat("0.00");
List<Metric> totalLineList = JtlResolver.resolver(jtlString); List<Metric> totalLineList = GenerateReport.resolver(jtlString);
// todo 修改测试概览的数值 // todo 修改测试概览的数值
List<Metric> totalLineList2 = JtlResolver.resolver(jtlString); List<Metric> totalLineList2 = GenerateReport.resolver(jtlString);
// 时间戳转时间 // 时间戳转时间
for (Metric metric : totalLineList2) { for (Metric metric : totalLineList2) {
metric.setTimestamp(stampToDate(DATE_TIME_PATTERN, metric.getTimestamp())); metric.setTimestamp(stampToDate(DATE_TIME_PATTERN, metric.getTimestamp()));
@ -355,7 +355,7 @@ public class JtlResolver {
public static ReportTimeInfo getReportTimeInfo(String jtlString) { public static ReportTimeInfo getReportTimeInfo(String jtlString) {
ReportTimeInfo reportTimeInfo = new ReportTimeInfo(); ReportTimeInfo reportTimeInfo = new ReportTimeInfo();
List<Metric> totalLineList = JtlResolver.resolver(jtlString); List<Metric> totalLineList = GenerateReport.resolver(jtlString);
totalLineList.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp()))); totalLineList.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp())));

View File

@ -11,7 +11,7 @@ import io.metersphere.controller.request.ReportRequest;
import io.metersphere.dto.ReportDTO; import io.metersphere.dto.ReportDTO;
import io.metersphere.engine.Engine; import io.metersphere.engine.Engine;
import io.metersphere.engine.EngineFactory; import io.metersphere.engine.EngineFactory;
import io.metersphere.report.JtlResolver; import io.metersphere.report.GenerateReport;
import io.metersphere.report.base.ChartsData; import io.metersphere.report.base.ChartsData;
import io.metersphere.report.base.Errors; import io.metersphere.report.base.Errors;
import io.metersphere.report.base.ReportTimeInfo; import io.metersphere.report.base.ReportTimeInfo;
@ -90,7 +90,7 @@ public class ReportService {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
RequestStatisticsDTO requestStatistics = JtlResolver.getRequestStatistics(content); RequestStatisticsDTO requestStatistics = GenerateReport.getRequestStatistics(content);
return requestStatistics; return requestStatistics;
} }
@ -98,7 +98,7 @@ public class ReportService {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
List<Errors> errors = JtlResolver.getErrorsList(content); List<Errors> errors = GenerateReport.getErrorsList(content);
return errors; return errors;
} }
@ -106,7 +106,7 @@ public class ReportService {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
ErrorsTop5DTO errors = JtlResolver.getErrorsTop5DTO(content); ErrorsTop5DTO errors = GenerateReport.getErrorsTop5DTO(content);
return errors; return errors;
} }
@ -114,7 +114,7 @@ public class ReportService {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
TestOverview testOverview = JtlResolver.getTestOverview(content); TestOverview testOverview = GenerateReport.getTestOverview(content);
return testOverview; return testOverview;
} }
@ -122,7 +122,7 @@ public class ReportService {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
ReportTimeInfo reportTimeInfo = JtlResolver.getReportTimeInfo(content); ReportTimeInfo reportTimeInfo = GenerateReport.getReportTimeInfo(content);
return reportTimeInfo; return reportTimeInfo;
} }
@ -130,7 +130,7 @@ public class ReportService {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
List<ChartsData> chartsDataList = JtlResolver.getLoadChartData(content); List<ChartsData> chartsDataList = GenerateReport.getLoadChartData(content);
return chartsDataList; return chartsDataList;
} }
@ -138,7 +138,7 @@ public class ReportService {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
List<ChartsData> chartsDataList = JtlResolver.getResponseTimeChartData(content); List<ChartsData> chartsDataList = GenerateReport.getResponseTimeChartData(content);
return chartsDataList; return chartsDataList;
} }

View File

@ -8,13 +8,13 @@
<el-input class="test-name" v-model="test.name" maxlength="64" :placeholder="$t('api_test.input_name')"> <el-input class="test-name" v-model="test.name" maxlength="64" :placeholder="$t('api_test.input_name')">
<el-select class="test-project" v-model="test.projectId" slot="prepend" <el-select class="test-project" v-model="test.projectId" slot="prepend"
:placeholder="$t('api_test.select_project')"> :placeholder="$t('api_test.select_project')">
<el-option v-for="item in projects" :key="item.id" :label="item.name" :value="item.id"/> <el-option v-for="project in projects" :key="project.id" :label="project.name" :value="project.id"/>
</el-select> </el-select>
</el-input> </el-input>
<el-button type="primary" plain :disabled="isDisabled" @click="saveTest">保存</el-button> <el-button type="primary" plain :disabled="isDisabled" @click="saveTest">保存</el-button>
</el-row> </el-row>
</el-header> </el-header>
<ms-api-scenario-config :scenarios="test.scenario_definition"/> <ms-api-scenario-config :scenarios="test.scenarioDefinition"/>
</el-container> </el-container>
</el-card> </el-card>
</div> </div>
@ -35,9 +35,10 @@
projects: [], projects: [],
change: false, change: false,
test: { test: {
id: null,
projectId: null, projectId: null,
name: null, name: null,
scenario_definition: [] scenarioDefinition: []
} }
} }
}, },
@ -53,11 +54,21 @@
methods: { methods: {
saveTest: function () { saveTest: function () {
this.change = false; this.change = false;
this.$message({
message: this.$t('commons.save_success'), let param = {
type: 'success' id: this.test.id,
projectId: this.test.projectId,
name: this.test.name,
scenarioDefinition: JSON.stringify(this.test.scenarioDefinition)
}
this.result = this.$post("/api/save", param, response => {
this.test.id = response.data;
this.$message({
message: this.$t('commons.save_success'),
type: 'success'
});
}); });
} }
}, },

View File

@ -4,9 +4,9 @@
<el-col class="assertion-select"> <el-col class="assertion-select">
<el-select class="assertion-item" v-model="regex.subject" size="small" <el-select class="assertion-item" v-model="regex.subject" size="small"
:placeholder="$t('api_test.request.assertions.select_subject')"> :placeholder="$t('api_test.request.assertions.select_subject')">
<el-option label="Http-Code" value="HTTP-CODE"></el-option> <el-option label="HttpCode" value="HTTP_CODE"/>
<el-option label="Header" value="HEADER"></el-option> <el-option label="Header" value="HEADER"/>
<el-option label="Body" value="BODY"></el-option> <el-option label="Body" value="BODY"/>
</el-select> </el-select>
</el-col> </el-col>
<el-col> <el-col>

View File

@ -4,19 +4,19 @@
<el-col class="assertion-select"> <el-col class="assertion-select">
<el-select class="assertion-item" v-model="subject" size="small" <el-select class="assertion-item" v-model="subject" size="small"
:placeholder="$t('api_test.request.assertions.select_subject')"> :placeholder="$t('api_test.request.assertions.select_subject')">
<el-option label="Http-Code" value="HTTP-CODE"></el-option> <el-option label="HttpCode" value="HTTP_CODE"/>
<el-option label="Header" value="HEADER"></el-option> <el-option label="Header" value="HEADER"/>
<el-option label="Body" value="BODY"></el-option> <el-option label="Body" value="BODY"/>
</el-select> </el-select>
</el-col> </el-col>
<el-col class="assertion-select"> <el-col class="assertion-select">
<el-select class="assertion-item" v-model="condition" size="small" <el-select class="assertion-item" v-model="condition" size="small"
:placeholder="$t('api_test.request.assertions.select_contains')"> :placeholder="$t('api_test.request.assertions.select_contains')">
<el-option :label="$t('api_test.request.assertions.contains')" value="CONTAINS"></el-option> <el-option :label="$t('api_test.request.assertions.contains')" value="CONTAINS"/>
<el-option :label="$t('api_test.request.assertions.not_contains')" value="NOT_CONTAINS"></el-option> <el-option :label="$t('api_test.request.assertions.not_contains')" value="NOT_CONTAINS"/>
<el-option :label="$t('api_test.request.assertions.equals')" value="EQUALS"></el-option> <el-option :label="$t('api_test.request.assertions.equals')" value="EQUALS"/>
<el-option :label="$t('api_test.request.assertions.start_with')" value="START_WITH"></el-option> <el-option :label="$t('api_test.request.assertions.start_with')" value="START_WITH"/>
<el-option :label="$t('api_test.request.assertions.end_with')" value="END_WITH"></el-option> <el-option :label="$t('api_test.request.assertions.end_with')" value="END_WITH"/>
</el-select> </el-select>
</el-col> </el-col>
<el-col> <el-col>

View File

@ -12,8 +12,21 @@
<el-input v-model="item.value" placeholder="Value" size="small" maxlength="100" @change="check"/> <el-input v-model="item.value" placeholder="Value" size="small" maxlength="100" @change="check"/>
</el-col> </el-col>
<el-col class="kv-delete"> <el-col class="kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)" <el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"/>
:disabled="isDisable(index)"/> </el-col>
</el-row>
</div>
<div class="kv-row">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col>
<el-input v-model="kv.key" placeholder="Key" size="small" maxlength="100" @change="add"/>
</el-col>
<el-col>
<el-input v-model="kv.value" placeholder="Value" size="small" maxlength="100" @change="add"/>
</el-col>
<el-col class="kv-delete">
<el-button size="mini" class="el-icon-delete-solid" circle :disabled="true"/>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
@ -31,45 +44,33 @@
items: Array items: Array
}, },
data() {
return {
kv: new KeyValue()
}
},
methods: { methods: {
add: function () { add: function () {
this.items.push(new KeyValue()); if (this.kv.key || this.kv.value) {
this.items.push(this.kv);
this.kv = new KeyValue();
}
}, },
remove: function (index) { remove: function (index) {
this.items.splice(index, 1); this.items.splice(index, 1);
if (this.items.length === 0) {
this.add();
}
}, },
check: function () { check: function () {
let isNeedCreate = true;
let removeIndex = -1; let removeIndex = -1;
this.items.forEach((item, index) => { this.items.forEach((item, index) => {
if (!item.key && !item.value) { if (!item.key && !item.value) {
// removeIndex = index;
if (index !== this.items.length - 1) {
removeIndex = index;
}
//
isNeedCreate = false;
} }
}); });
if (isNeedCreate) {
this.add();
}
if (removeIndex !== -1) { if (removeIndex !== -1) {
this.remove(removeIndex); this.remove(removeIndex);
} }
// TODO key // TODO key
},
isDisable: function (index) {
return this.items.length - 1 === index;
}
},
created() {
if (this.items.length === 0) {
this.add();
} }
} }
} }

View File

@ -11,7 +11,7 @@
</div> </div>
<div class="request-btn"> <div class="request-btn">
<el-dropdown trigger="click" @command="handleCommand"> <el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link el-icon-more"></span> <span class="el-dropdown-link el-icon-more"/>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type: 'copy', index: index}">复制请求</el-dropdown-item> <el-dropdown-item :command="{type: 'copy', index: index}">复制请求</el-dropdown-item>
<el-dropdown-item :command="{type: 'delete', index: index}">删除请求</el-dropdown-item> <el-dropdown-item :command="{type: 'delete', index: index}">删除请求</el-dropdown-item>

View File

@ -1,20 +1,20 @@
<template> <template>
<el-form :model="request" :rules="rules" ref="request" label-width="100px"> <el-form :model="request" :rules="rules" ref="request" label-width="100px">
<el-form-item :label="$t('api_test.request.name')" prop="name"> <el-form-item :label="$t('api_test.request.name')" prop="name">
<el-input v-model="request.name" maxlength="100"></el-input> <el-input v-model="request.name" maxlength="100"/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('api_test.request.url')" prop="url"> <el-form-item :label="$t('api_test.request.url')" prop="url">
<el-input v-model="request.url" maxlength="100" :placeholder="$t('api_test.request.url_description')"> <el-input v-model="request.url" maxlength="100" :placeholder="$t('api_test.request.url_description')">
<el-select v-model="request.method" slot="prepend" class="request-method-select"> <el-select v-model="request.method" slot="prepend" class="request-method-select">
<el-option label="GET" value="GET"></el-option> <el-option label="GET" value="GET"/>
<el-option label="POST" value="POST"></el-option> <el-option label="POST" value="POST"/>
<el-option label="PUT" value="PUT"></el-option> <el-option label="PUT" value="PUT"/>
<el-option label="PATCH" value="PATCH"></el-option> <el-option label="PATCH" value="PATCH"/>
<el-option label="DELETE" value="DELETE"></el-option> <el-option label="DELETE" value="DELETE"/>
<el-option label="OPTIONS" value="OPTIONS"></el-option> <el-option label="OPTIONS" value="OPTIONS"/>
<el-option label="HEAD" value="HEAD"></el-option> <el-option label="HEAD" value="HEAD"/>
<el-option label="CONNECT" value="CONNECT"></el-option> <el-option label="CONNECT" value="CONNECT"/>
</el-select> </el-select>
</el-input> </el-input>
</el-form-item> </el-form-item>
@ -30,7 +30,7 @@
<ms-api-body :body="request.body"/> <ms-api-body :body="request.body"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions"> <el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
<ms-api-assertions :assertions="request.assertions"></ms-api-assertions> <ms-api-assertions :assertions="request.assertions"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_test.request.extract')" name="extract" v-if="false"> <el-tab-pane :label="$t('api_test.request.extract')" name="extract" v-if="false">
TODO TODO

View File

@ -18,14 +18,13 @@
</ms-api-collapse-item> </ms-api-collapse-item>
</ms-api-collapse> </ms-api-collapse>
</div> </div>
<el-button class="scenario-create" type="primary" size="mini" icon="el-icon-plus" plain <el-button class="scenario-create" type="primary" size="mini" icon="el-icon-plus" plain @click="createScenario"/>
@click="createScenario"/>
</el-aside> </el-aside>
<el-main class="scenario-main"> <el-main class="scenario-main">
<div class="scenario-form"> <div class="scenario-form">
<ms-api-scenario-form :scenario="selected" v-if="isScenario"></ms-api-scenario-form> <ms-api-scenario-form :scenario="selected" v-if="isScenario"/>
<ms-api-request-form :request="selected" v-if="isRequest"></ms-api-request-form> <ms-api-request-form :request="selected" v-if="isRequest"/>
</div> </div>
</el-main> </el-main>
</el-container> </el-container>

View File

@ -1,7 +1,7 @@
<template> <template>
<el-form :model="scenario" :rules="rules" ref="scenario" label-width="100px"> <el-form :model="scenario" :rules="rules" ref="scenario" label-width="100px">
<el-form-item :label="$t('api_test.scenario.name')" prop="name"> <el-form-item :label="$t('api_test.scenario.name')" prop="name">
<el-input v-model="scenario.name" maxlength="100"></el-input> <el-input v-model="scenario.name" maxlength="100"/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('api_test.scenario.base_url')" prop="url"> <el-form-item :label="$t('api_test.scenario.base_url')" prop="url">

View File

@ -12,7 +12,7 @@
<plan-node-tree <plan-node-tree
class="node-tree" class="node-tree"
:plan-id="planId" :plan-id="planId"
@nodeSelectEvent="getPlanCases" @nodeSelectEvent="selectNodeIdsChange"
ref="tree"> ref="tree">
</plan-node-tree> </plan-node-tree>
@ -23,6 +23,7 @@
@openTestCaseRelevanceDialog="openTestCaseRelevanceDialog" @openTestCaseRelevanceDialog="openTestCaseRelevanceDialog"
@refresh="refresh" @refresh="refresh"
:plan-id="planId" :plan-id="planId"
:select-node-ids="selectNodeIds"
ref="testCasePlanList"></test-plan-test-case-list> ref="testCasePlanList"></test-plan-test-case-list>
</el-main> </el-main>
</el-container> </el-container>
@ -49,7 +50,8 @@
data() { data() {
return { return {
testPlans: [], testPlans: [],
currentPlan: {} currentPlan: {},
selectNodeIds: []
} }
}, },
computed: { computed: {
@ -67,11 +69,11 @@
}, },
methods: { methods: {
refresh() { refresh() {
this.getPlanCases(); this.selectNodeIds = [];
this.$refs.tree.initTree(); this.$refs.tree.initTree();
}, },
getPlanCases(nodeIds) { selectNodeIdsChange(nodeIds) {
this.$refs.testCasePlanList.initTableData(nodeIds); this.selectNodeIds = nodeIds;
}, },
openTestCaseRelevanceDialog() { openTestCaseRelevanceDialog() {
this.$refs.testCaseRelevance.openTestCaseRelevanceDialog(); this.$refs.testCaseRelevance.openTestCaseRelevanceDialog();
@ -117,8 +119,4 @@
padding: 15px; padding: 15px;
} }
.main-content {
/*background: white;*/
}
</style> </style>

View File

@ -1,158 +1,167 @@
<template> <template>
<el-drawer <el-drawer
:before-close="handleClose" :before-close="handleClose"
:visible.sync="showDialog" :visible.sync="showDialog"
:with-header="false" :with-header="false"
size="100%" size="100%"
ref="drawer"> ref="drawer"
v-loading="result.loading">
<template v-slot:default="scope"> <template v-slot:default="scope">
<div class="container">
<el-header> <el-scrollbar>
<el-row type="flex" class="head-bar"> <el-header>
<el-col :span="12"> <el-row type="flex" class="head-bar">
<el-button plain size="mini"
icon="el-icon-back"
@click="cancel">{{$t('test_track.return')}}</el-button>
</el-col>
<el-col :span="12" class="head-right"> <el-col :span="12">
<span class="head-right-tip" v-if="index + 1 == tableData.length"> <el-button plain size="mini"
{{$t('test_track.plan_view.pre_case')}} : {{tableData ? tableData[index - 1].name : ''}} icon="el-icon-back"
</span> @click="cancel">{{$t('test_track.return')}}</el-button>
<span class="head-right-tip" v-if="index + 1 < tableData.length"> </el-col>
{{$t('test_track.plan_view.next_case')}} : {{tableData ? tableData[index + 1].name : ''}}
</span>
<el-button plain size="mini" icon="el-icon-arrow-up" <el-col :span="12" class="head-right">
:disabled="index + 1 <= 1" <span class="head-right-tip" v-if="index + 1 == testCases.length">
@click="handlePre()"/> {{$t('test_track.plan_view.pre_case')}} : {{testCases[index - 1] ? testCases[index - 1].name : ''}}
<span> {{index + 1}}/{{tableData.length}} </span> </span>
<el-button plain size="mini" icon="el-icon-arrow-down" <span class="head-right-tip" v-if="index + 1 != testCases.length">
:disabled="index + 1 >= tableData.length" {{$t('test_track.plan_view.next_case')}} : {{testCases[index + 1] ? testCases[index + 1].name : ''}}
@click="handleNext()"/> </span>
<el-divider direction="vertical"></el-divider>
<el-button type="primary" size="mini" @click="saveCase">{{$t('test_track.save')}}</el-button> <el-button plain size="mini" icon="el-icon-arrow-up"
</el-col> :disabled="index + 1 <= 1"
@click="handlePre()"/>
<span> {{index + 1}}/{{testCases.length}} </span>
<el-button plain size="mini" icon="el-icon-arrow-down"
:disabled="index + 1 >= testCases.length"
@click="handleNext()"/>
<el-divider direction="vertical"></el-divider>
</el-row> <el-button type="primary" size="mini" @click="saveCase">{{$t('test_track.save')}}</el-button>
</el-col>
<el-row style="margin-top: 0px;"> </el-row>
<el-col>
<el-divider content-position="left">{{testCase.name}}</el-divider>
</el-col>
</el-row>
</el-header> <el-row style="margin-top: 0px;">
<el-col>
<el-divider content-position="left">{{testCase.name}}</el-divider>
</el-col>
</el-row>
<div class="case_container"> </el-header>
<el-row >
<el-col :span="4" :offset="1">
<span class="cast_label">{{$t('test_track.case.priority')}}</span>
<span class="cast_item">{{testCase.priority}}</span>
</el-col>
<el-col :span="5">
<span class="cast_label">{{$t('test_track.case.case_type')}}</span>
<span class="cast_item" v-if="testCase.type == 'functional'">{{$t('commons.functional')}}</span>
<span class="cast_item" v-if="testCase.type == 'performance'">{{$t('commons.performance')}}</span>
<span class="cast_item" v-if="testCase.type == 'api'">{{$t('commons.api')}}</span>
</el-col>
<el-col :span="13">
<test-plan-test-case-status-button class="status-button"
@statusChange="statusChange"
:status="testCase.status"/>
</el-col>
</el-row>
<el-row> <div class="case_container">
<el-col :span="4" :offset="1"> <el-row >
<span class="cast_label">{{$t('test_track.case.method')}}</span> <el-col :span="4" :offset="1">
<span v-if="testCase.method == 'manual'">{{$t('test_track.case.manual')}}</span> <span class="cast_label">{{$t('test_track.case.priority')}}</span>
<span v-if="testCase.method == 'auto'">{{$t('test_track.case.auto')}}</span> <span class="cast_item">{{testCase.priority}}</span>
</el-col> </el-col>
<el-col :span="5"> <el-col :span="5">
<span class="cast_label">{{$t('test_track.case.module')}}</span> <span class="cast_label">{{$t('test_track.case.case_type')}}</span>
<span class="cast_item">{{testCase.nodePath}}</span> <span class="cast_item" v-if="testCase.type == 'functional'">{{$t('commons.functional')}}</span>
</el-col> <span class="cast_item" v-if="testCase.type == 'performance'">{{$t('commons.performance')}}</span>
</el-row> <span class="cast_item" v-if="testCase.type == 'api'">{{$t('commons.api')}}</span>
</el-col>
<el-col :span="13">
<test-plan-test-case-status-button class="status-button"
@statusChange="statusChange"
:status="testCase.status"/>
</el-col>
</el-row>
<el-row> <el-row>
<el-col :span="20" :offset="1"> <el-col :span="4" :offset="1">
<div> <span class="cast_label">{{$t('test_track.case.method')}}</span>
<span class="cast_label">{{$t('test_track.case.steps')}}</span> <span v-if="testCase.method == 'manual'">{{$t('test_track.case.manual')}}</span>
</div> <span v-if="testCase.method == 'auto'">{{$t('test_track.case.auto')}}</span>
<el-table </el-col>
:data="testCase.steptResults" <el-col :span="5">
class="tb-edit" <span class="cast_label">{{$t('test_track.case.module')}}</span>
size="mini" <span class="cast_item">{{testCase.nodePath}}</span>
height="250px" </el-col>
:border="true" </el-row>
:default-sort = "{prop: 'num', order: 'ascending'}"
highlight-current-row> <el-row>
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="5%"></el-table-column> <el-col :span="20" :offset="1">
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="29%"> <div>
<template v-slot:default="scope"> <span class="cast_label">{{$t('test_track.case.steps')}}</span>
<span>{{scope.row.desc}}</span> </div>
</template> <el-table
</el-table-column> :data="testCase.steptResults"
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="28%"> class="tb-edit"
<template v-slot:default="scope">
<span>{{scope.row.result}}</span>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.plan_view.actual_result')" min-width="29%">
<template v-slot:default="scope">
<el-input
size="mini" size="mini"
type="textarea" :border="true"
:rows="2" :default-sort = "{prop: 'num', order: 'ascending'}"
v-model="scope.row.actualResult" highlight-current-row>
:placeholder="$t('commons.input_content')" <el-table-column :label="$t('test_track.case.number')" prop="num" min-width="5%"></el-table-column>
clearable></el-input> <el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="29%">
<span>{{scope.row.actualResult}}</span> <template v-slot:default="scope">
</template> <span>{{scope.row.desc}}</span>
</el-table-column> </template>
<el-table-column :label="$t('test_track.plan_view.step_result')" min-width="9%"> </el-table-column>
<template v-slot:default="scope"> <el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="28%">
<el-select <template v-slot:default="scope">
v-model="scope.row.executeResult" <span>{{scope.row.result}}</span>
size="mini"> </template>
<el-option :label="$t('test_track.plan_view.pass')" value="Pass" style="color: #7ebf50;"></el-option> </el-table-column>
<el-option :label="$t('test_track.plan_view.failure')" value="Failure" style="color: #e57471;"></el-option> <el-table-column :label="$t('test_track.plan_view.actual_result')" min-width="29%">
<el-option :label="$t('test_track.plan_view.blocking')" value="Blocking" style="color: #dda451;"></el-option> <template v-slot:default="scope">
<el-option :label="$t('test_track.plan_view.skip')" value="Skip" style="color: #919399;"></el-option> <el-input
</el-select> size="mini"
</template> type="textarea"
</el-table-column> :rows="2"
</el-table> v-model="scope.row.actualResult"
</el-col> :placeholder="$t('commons.input_content')"
</el-row> clearable></el-input>
<span>{{scope.row.actualResult}}</span>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.plan_view.step_result')" min-width="9%">
<template v-slot:default="scope">
<el-select
v-model="scope.row.executeResult"
size="mini">
<el-option :label="$t('test_track.plan_view.pass')" value="Pass" style="color: #7ebf50;"></el-option>
<el-option :label="$t('test_track.plan_view.failure')" value="Failure" style="color: #e57471;"></el-option>
<el-option :label="$t('test_track.plan_view.blocking')" value="Blocking" style="color: #dda451;"></el-option>
<el-option :label="$t('test_track.plan_view.skip')" value="Skip" style="color: #919399;"></el-option>
</el-select>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-row> <el-row>
<el-col :span="15" :offset="1"> <el-col :span="15" :offset="1">
<div> <div>
<span class="cast_label">{{$t('commons.remark')}}</span> <span class="cast_label">{{$t('commons.remark')}}</span>
<span v-if="testCase.remark == null || testCase.remark == ''" style="color: darkgrey">{{$t('commons.not_filled')}}</span> <span v-if="testCase.remark == null || testCase.remark == ''" style="color: darkgrey">{{$t('commons.not_filled')}}</span>
</div>
<div>
<el-input :rows="3"
type="textarea"
v-if="testCase.remark"
disabled
v-model="testCase.remark"></el-input>
</div>
</el-col>
</el-row>
</div> </div>
<div>
<el-input :rows="3"
type="textarea"
v-if="testCase.remark"
disabled
v-model="testCase.remark"></el-input>
</div>
</el-col>
</el-row>
</el-scrollbar>
</div>
</template>
</div>
</template>
</el-drawer> </el-drawer>
</template> </template>
<script> <script>
@ -163,17 +172,19 @@
components: {TestPlanTestCaseStatusButton}, components: {TestPlanTestCaseStatusButton},
data() { data() {
return { return {
result: {},
showDialog: false, showDialog: false,
testCase: {}, testCase: {},
index: 0 index: 0,
testCases: []
}; };
}, },
props: { props: {
tableData: {
type: Array
},
total: { total: {
type: Number type: Number
},
searchParam: {
type: Object
} }
}, },
methods: { methods: {
@ -213,7 +224,7 @@
this.getTestCase(this.index); this.getTestCase(this.index);
}, },
getTestCase(index) { getTestCase(index) {
let testCase = this.tableData[index]; let testCase = this.testCases[index];
let item = {}; let item = {};
Object.assign(item, testCase); Object.assign(item, testCase);
item.results = JSON.parse(item.results); item.results = JSON.parse(item.results);
@ -227,6 +238,22 @@
item.steptResults.push(item.steps[i]); item.steptResults.push(item.steps[i]);
} }
this.testCase = item; this.testCase = item;
},
openTestCaseEdit(testCase) {
this.showDialog = true;
this.initData(testCase);
},
initData(testCase) {
this.result = this.$post('/test/plan/case/list/all', this.searchParam, response => {
this.testCases = response.data;
for (let i = 0; i < this.testCases.length; i++) {
if (this.testCases[i].id === testCase.id) {
this.index = i;
this.getTestCase(i);
}
}
});
} }
} }
} }
@ -265,12 +292,20 @@
float: right; float: right;
} }
.head-bar {
margin-top: 1%;
}
.head-right-tip { .head-right-tip {
color: darkgrey; color: darkgrey;
} }
.el-scrollbar {
height: 100%;
}
.container {
height: 100vh;
}
.case_container > .el-row{
margin-top: 1%;
}
</style> </style>

View File

@ -35,11 +35,11 @@
<executor-edit <executor-edit
ref="executorEdit" ref="executorEdit"
:select-ids="selectIds" :select-ids="selectIds"
@refresh="initTableData"/> @refresh="refresh"/>
<status-edit <status-edit
ref="statusEdit" ref="statusEdit"
:select-ids="selectIds" :select-ids="selectIds"
@refresh="initTableData"/> @refresh="refresh"/>
</div> </div>
</template> </template>
@ -154,8 +154,8 @@
<test-plan-test-case-edit <test-plan-test-case-edit
ref="testPlanTestCaseEdit" ref="testPlanTestCaseEdit"
:table-data="tableData" :search-param="condition"
@refresh="initTableData"/> @refresh="refresh"/>
</el-card> </el-card>
</div> </div>
@ -183,37 +183,44 @@
currentPage: 1, currentPage: 1,
pageSize: 5, pageSize: 5,
total: 0, total: 0,
currentDataIndex: 0, selectIds: new Set()
selectIds: new Set(),
} }
}, },
props:{ props:{
planId: { planId: {
type: String type: String
},
selectNodeIds: {
type: Array
} }
}, },
watch: { watch: {
planId() { planId() {
this.initTableData(); this.initTableData();
},
selectNodeIds() {
this.refresh();
} }
}, },
created: function () { created: function () {
this.initTableData(); this.initTableData();
}, },
methods: { methods: {
initTableData(nodeIds) { initTableData() {
if (this.planId) { if (this.planId) {
let param = {}; this.condition.planId = this.planId;
Object.assign(param, this.condition); this.condition.nodeIds = this.selectNodeIds;
param.nodeIds = nodeIds; this.result = this.$post(this.buildPagePath('/test/plan/case/list'), this.condition, response => {
param.planId = this.planId;
this.result = this.$post(this.buildPagePath('/test/plan/case/list'), param, response => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.total = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;
}); });
} }
}, },
refresh() {
this.condition = {};
this.initTableData();
},
search() { search() {
this.initTableData(); this.initTableData();
}, },
@ -221,10 +228,7 @@
return path + "/" + this.currentPage + "/" + this.pageSize; return path + "/" + this.currentPage + "/" + this.pageSize;
}, },
handleEdit(testCase, index) { handleEdit(testCase, index) {
this.currentDataIndex = index; this.$refs.testPlanTestCaseEdit.openTestCaseEdit(testCase);
this.$refs.testPlanTestCaseEdit.index = index;
this.$refs.testPlanTestCaseEdit.getTestCase(index);
this.$refs.testPlanTestCaseEdit.showDialog = true;
}, },
handleDelete(testCase) { handleDelete(testCase) {
this.$alert(this.$t('test_track.plan_view.confirm_cancel_relevance') + ' ' + testCase.name + " ", '', { this.$alert(this.$t('test_track.plan_view.confirm_cancel_relevance') + ' ' + testCase.name + " ", '', {
@ -239,7 +243,6 @@
_handleDelete(testCase) { _handleDelete(testCase) {
let testCaseId = testCase.id; let testCaseId = testCase.id;
this.$post('/test/plan/case/delete/' + testCaseId, {}, () => { this.$post('/test/plan/case/delete/' + testCaseId, {}, () => {
this.initTableData();
this.$emit("refresh"); this.$emit("refresh");
this.$message({ this.$message({
message: this.$t('commons.delete_success'), message: this.$t('commons.delete_success'),