fix(接口定义): 修复选择案例缺陷

This commit is contained in:
fit2-zhao 2020-12-11 11:21:05 +08:00
parent 54f5e8aad5
commit d75477db11
10 changed files with 1165 additions and 144 deletions

View File

@ -281,7 +281,7 @@
import MsIfController from "./IfController";
import MsApiAssertions from "../../definition/components/assertion/ApiAssertions";
import MsApiExtract from "../../definition/components/extract/ApiExtract";
import MsApiDefinition from "../../definition/ApiDefinition";
import MsApiDefinition from "./api/ApiDefinition";
import MsApiComponent from "./ApiComponent";
import {ELEMENTS, ELEMENT_TYPE} from "./Setting";
import MsApiCustomize from "./ApiCustomize";

View File

@ -0,0 +1,494 @@
<template>
<div>
<el-container style="padding-bottom: 200px">
<el-header style="width: 100% ;padding: 0px">
<el-card>
<el-row>
<el-col :span="api.protocol==='HTTP'? 3:5">
<div class="variable-combine"> {{api.name}}</div>
</el-col>
<el-col :span="api.protocol==='HTTP'? 1:3">
<ms-tag v-if="api.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="api.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="api.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
</el-col>
<el-col :span="api.protocol==='HTTP'? 4:0">
<div class="variable-combine" style="margin-left: 10px">{{api.path ===null ? " " : api.path}}</div>
</el-col>
<el-col :span="2">
<div>{{$t('test_track.plan_view.case_count')}}{{apiCaseList.length}}</div>
</el-col>
<el-col :span="3">
<div>
<el-select size="small" :placeholder="$t('api_test.definition.request.grade_info')" v-model="priorityValue"
class="ms-api-header-select" @change="getApiTest">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div>
<el-select :disabled="isReadOnly" v-model="environment" size="small" class="ms-api-header-select"
:placeholder="$t('api_test.definition.request.run_env')"
@change="environmentChange" clearable>
<el-option v-for="(environment, index) in environments" :key="index"
:label="environment.name + (environment.config.httpConfig.socket ? (': ' + environment.config.httpConfig.protocol + '://' + environment.config.httpConfig.socket) : '')"
:value="environment.id"/>
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
<template v-slot:empty>
<div class="empty-environment">
<el-button class="environment-button" size="mini" type="primary" @click="openEnvironmentConfig">
{{ $t('api_test.environment.environment_config') }}
</el-button>
</div>
</template>
</el-select>
</div>
</el-col>
<el-col :span="3">
<div class="ms-api-header-select">
<el-input size="small" :placeholder="$t('api_test.definition.request.select_case')"
v-model="name" @blur="getApiTest"/>
</div>
</el-col>
<el-col :span="2">
<button type="button" aria-label="Close" class="el-card-btn" @click="apiCaseClose()"><i
class="el-dialog__close el-icon el-icon-close"></i></button>
</el-col>
</el-row>
</el-card>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
</el-header>
<!-- 用例部分 -->
<el-main v-loading="loading" style="overflow: auto">
<div v-for="(item,index) in apiCaseList" :key="index">
<el-card style="margin-top: 5px">
<el-row>
<el-col :span="1">
<el-checkbox v-if="visible" @change="caseChecked(item)"/>
</el-col>
<el-col :span="5">
<div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{index+1}}</div>
</div>
<label class="ms-api-label">{{$t('test_track.case.priority')}}</label>
<el-select size="small" v-model="item.priority" class="ms-api-select">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</el-col>
<el-col :span="14">
<i class="icon el-icon-arrow-right" :class="{'is-active': item.active}"
@click="active(item)"/>
<el-input v-if="item.type==='create'" size="small" v-model="item.name" :name="index" :key="index"
class="ms-api-header-select" style="width: 180px"
@blur="saveTestCase(item)"/>
<span v-else>
{{item.type!= 'create' ? item.name:''}}
<i class="el-icon-edit" style="cursor:pointer" @click="showInput(item)"/>
</span>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span>
{{item.createTime | timestampFormatDate }}
{{item.createUser}} {{$t('api_test.definition.request.create_info')}}
</span>
<span>
{{item.updateTime | timestampFormatDate }}
{{item.updateUser}} {{$t('api_test.definition.request.update_info')}}
</span>
</div>
</el-col>
<el-col :span="3">
<div v-if="item.type!='create'">{{getResult(item.execResult)}}</div>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span> {{item.updateTime | timestampFormatDate }}</span>
{{item.updateUser}}
</div>
</el-col>
</el-row>
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="item.active">
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :is-read-only="isReadOnly" :headers="item.request.headers " :request="item.request" v-if="api.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="item.request" v-if="api.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="item.request" v-if="api.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="item.request" v-if="api.protocol==='DUBBO'"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
{{$t('commons.save')}}
</el-button>
</div>
</el-collapse-transition>
</el-card>
</div>
</el-main>
</el-container>
</div>
</template>
<script>
import MsTag from "../../../../common/components/MsTag";
import MsTipButton from "../../../../common/components/MsTipButton";
import MsApiRequestForm from "../../../definition/components/request/http/ApiRequestForm";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import {parseEnvironment} from "../../../definition/model/EnvironmentModel";
import ApiEnvironmentConfig from "../../../definition/components/environment/ApiEnvironmentConfig";
import {PRIORITY, RESULT_MAP} from "../../../definition/model/JsonData";
import MsApiAssertions from "../../../definition/components/assertion/ApiAssertions";
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
import MsTcpBasisParameters from "../../../definition/components/request/tcp/BasisParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiExtendBtns from "../../../definition/components/reference/ApiExtendBtns";
export default {
name: 'ApiCaseList',
components: {
MsTag,
MsTipButton,
MsApiRequestForm,
ApiEnvironmentConfig,
MsApiAssertions,
MsSqlBasisParameters,
MsTcpBasisParameters,
MsDubboBasisParameters,
MsApiExtendBtns
},
props: {
api: {
type: Object
},
createCase: String,
visible: {
type: Boolean,
default: false,
},
loaded: Boolean,
refreshSign: String,
currentRow: Object,
},
data() {
return {
grades: [],
environments: [],
environment: {},
name: "",
priorityValue: "",
isReadOnly: false,
selectedEvent: Object,
priority: PRIORITY,
apiCaseList: [],
loading: false,
runData: [],
reportId: "",
projectId: "",
checkedCases: new Set(),
}
},
watch: {
//
api() {
this.getApiTest();
},
createCase() {
this.getApiTest();
}
},
created() {
this.projectId = getCurrentProjectID();
this.getEnvironments();
this.getApiTest();
},
methods: {
sysAddition() {
let condition = {};
condition.projectId = this.api.projectId;
condition.apiDefinitionId = this.api.id;
condition.priority = this.priorityValue;
condition.name = this.name;
this.$post("/api/testcase/list", condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.request = JSON.parse(test.request);
}
this.apiCaseList = response.data;
this.addCase();
});
},
getResult(data) {
if (RESULT_MAP.get(data)) {
return RESULT_MAP.get(data);
} else {
return RESULT_MAP.get("default");
}
},
handleCommand(e) {
if (e === "run") {
this.batchRun();
}
},
showInput(row) {
row.type = "create";
row.active = true;
this.active(row);
},
apiCaseClose() {
this.apiCaseList = [];
this.$emit('apiCaseClose');
},
batchRun() {
if (!this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
this.loading = true;
if (this.apiCaseList.length > 0) {
this.apiCaseList.forEach(item => {
if (item.type != "create") {
item.request.name = item.id;
item.request.useEnvironment = this.environment.id;
this.runData.push(item.request);
}
})
this.loading = true;
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
} else {
this.$warning("没有可执行的用例!");
}
},
singleRun(row) {
if (!this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
this.runData = [];
this.loading = true;
row.request.name = row.id;
row.request.useEnvironment = this.environment.id;
this.runData.push(row.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
},
runRefresh(data) {
this.loading = false;
this.$success(this.$t('schedule.event_success'));
this.getApiTest();
this.$emit('refresh');
},
deleteCase(index, row) {
this.$get('/api/testcase/delete/' + row.id, () => {
this.$success(this.$t('commons.delete_success'));
this.apiCaseList.splice(index, 1);
this.$emit('refresh');
});
},
copyCase(data) {
let obj = {name: data.name, priority: data.priority, type: 'create', active: false, request: data.request};
this.apiCaseList.unshift(obj);
},
addCase() {
//
let request = {};
if (this.api.request instanceof Object) {
request = this.api.request;
} else {
request = JSON.parse(this.api.request);
}
let obj = {apiDefinitionId: this.api.id, name: '', priority: 'P0', type: 'create', active: false};
obj.request = request;
this.apiCaseList.unshift(obj);
},
active(item) {
item.active = !item.active;
},
getBodyUploadFiles(row) {
let bodyUploadFiles = [];
row.bodyUploadIds = [];
let request = row.request;
if (request.body && request.body.kvs) {
request.body.kvs.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
let fileId = getUUID().substring(0, 8);
item.name = item.file.name;
item.id = fileId;
row.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
if (request.body.binary) {
request.body.binary.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
let fileId = getUUID().substring(0, 8);
item.name = item.file.name;
item.id = fileId;
row.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
}
return bodyUploadFiles;
},
getApiTest() {
if (this.currentRow) {
this.currentRow.cases = [];
}
let condition = {};
condition.projectId = this.api.projectId;
condition.apiDefinitionId = this.api.id;
condition.priority = this.priorityValue;
condition.name = this.name;
this.$post("/api/testcase/list", condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.request = JSON.parse(test.request);
}
this.apiCaseList = response.data;
});
},
validate(row) {
if (!row.name) {
this.$warning(this.$t('api_test.input_name'));
return true;
}
},
getEnvironments() {
if (this.projectId) {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.environment = undefined;
}
});
} else {
this.environment = undefined;
}
},
openEnvironmentConfig() {
if (!this.projectId) {
this.$error(this.$t('api_test.select_project'));
return;
}
this.$refs.environmentConfig.open(this.projectId);
},
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.environment = this.environments[i];
break;
}
}
},
environmentConfigClose() {
this.getEnvironments();
},
caseChecked(row) {
row.protocol = this.api.protocol;
row.hashTree = [];
if (this.checkedCases.has(row)) {
this.checkedCases.delete(row);
} else {
this.checkedCases.add(row)
}
let arr = Array.from(this.checkedCases);
this.currentRow.cases = arr;
}
}
}
</script>
<style scoped>
.ms-api-select {
margin-left: 20px;
width: 80px;
}
.ms-api-header-select {
margin-left: 20px;
min-width: 100px;
}
.el-card-btn {
float: right;
top: 20px;
right: 0px;
padding: 0;
background: 0 0;
border: none;
outline: 0;
cursor: pointer;
font-size: 18px;
margin-left: 30px;
}
.ms-api-label {
color: #CCCCCC;
}
.ms-api-col {
background-color: #7C3985;
border-color: #7C3985;
margin-right: 10px;
color: white;
}
.variable-combine {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 10px;
}
.icon.is-active {
transform: rotate(90deg);
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 20px 0;
}
.environment-button {
margin-left: 20px;
padding: 7px;
}
.is-selected {
background: #EFF7FF;
}
</style>

View File

@ -0,0 +1,151 @@
<template>
<ms-container>
<ms-aside-container>
<ms-node-tree @selectModule="selectModule" @getApiModuleTree="initTree" @changeProtocol="changeProtocol"
@refresh="refresh" @saveAsEdit="editApi" @exportAPI="exportAPI"/>
</ms-aside-container>
<ms-main-container>
<!-- 主框架列表 -->
<el-tabs v-model="apiDefaultTab">
<el-tab-pane
:key="item.name"
v-for="(item) in apiTabs"
:label="item.title"
:closable="item.closable"
:name="item.name">
<!-- 列表集合 -->
<ms-api-list
v-if="item.type === 'list'"
:current-protocol="currentProtocol"
:current-module="currentModule"
@editApi="editApi"
@handleCase="handleCase"
:visible="visible"
:currentRow="currentRow"
ref="apiList"/>
</el-tab-pane>
</el-tabs>
</ms-main-container>
</ms-container>
</template>
<script>
import MsNodeTree from '../../../definition/components/ApiModule';
import MsApiList from './ApiList';
import MsContainer from "../../../../common/components/MsContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import {downloadFile, getCurrentUser, getUUID, getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiDefinition",
components: {
MsNodeTree,
MsApiList,
MsMainContainer,
MsContainer,
MsAsideContainer,
},
props: {
visible: {
type: Boolean,
default: false,
},
currentRow: {
type: Object,
}
},
data() {
return {
isHide: true,
apiDefaultTab: 'default',
currentProtocol: null,
currentModule: null,
currentApi: {},
moduleOptions: {},
runTestData: {},
apiTabs: [{
title: this.$t('api_test.definition.api_title'),
name: 'default',
type: "list",
closable: false
}],
}
},
methods: {
editApi(row) {
this.currentApi = row;
},
handleCase(testCase) {
this.currentApi = testCase;
this.isHide = false;
},
apiCaseClose() {
this.isHide = true;
},
selectModule(data) {
this.currentModule = data;
},
exportAPI() {
if (!this.$refs.apiList[0].tableData) {
return;
}
let obj = {projectName: getCurrentProjectID(), protocol: this.currentProtocol, data: this.$refs.apiList[0].tableData}
downloadFile("导出API.json", JSON.stringify(obj));
},
refresh(data) {
this.$refs.apiList[0].initApiTable(data);
},
setTabTitle(data) {
for (let index in this.apiTabs) {
let tab = this.apiTabs[index];
if (tab.name === this.apiDefaultTab) {
tab.title = this.$t('api_test.definition.request.edit_api') + "-" + data.name;
break;
}
}
this.runTestData = data;
},
saveApi(data) {
this.setTabTitle(data);
this.$refs.apiList[0].initApiTable(data);
},
initTree(data) {
this.moduleOptions = data;
},
changeProtocol(data) {
this.currentProtocol = data;
}
}
}
</script>
<style scoped>
.ms-api-buttion {
position: absolute;
top: 100px;
right: 4px;
padding: 0;
background: 0 0;
border: none;
outline: 0;
cursor: pointer;
margin-right: 10px;
font-size: 16px;
}
.ms-api-div {
overflow-y: auto;
height: calc(100vh - 155px)
}
/deep/ .el-tabs__header {
margin: 0 0 5px;
}
/deep/ .el-main {
overflow: hidden;
}
</style>

View File

@ -0,0 +1,412 @@
<template>
<div id="svgBox" style="overflow: auto">
<div id="svgTop" style="background-color: white">
<el-card class="card-content">
<el-input placeholder="搜索" @blur="search" style="float: right ;width: 300px;margin-bottom: 20px;margin-right: 20px" size="small" v-model="condition.name"/>
<el-table border :data="tableData" row-key="id" class="test-content adjust-table"
@select-all="handleSelectAll"
@select="handleSelect" :height="screenHeight">
<el-table-column type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
</template>
</el-table-column>
<el-table-column prop="name" :label="$t('api_test.definition.api_name')" show-overflow-tooltip/>
<el-table-column
prop="status"
column-key="api_status"
:label="$t('api_test.definition.api_status')"
show-overflow-tooltip>
<template v-slot:default="scope">
<ms-tag v-if="scope.row.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="scope.row.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="scope.row.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
<ms-tag v-if="scope.row.status == 'Trash'" type="danger" effect="plain" content="废弃"/>
</template>
</el-table-column>
<el-table-column
prop="method"
:label="$t('api_test.definition.api_type')"
show-overflow-tooltip>
<template v-slot:default="scope" class="request-method">
<el-tag size="mini" :style="{'background-color': getColor(true, scope.row.method)}" class="api-el-tag">
{{ scope.row.method}}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="path"
:label="$t('api_test.definition.api_path')"
show-overflow-tooltip/>
<el-table-column
prop="userName"
:label="$t('api_test.definition.api_principal')"
show-overflow-tooltip/>
<el-table-column width="160" :label="$t('api_test.definition.api_last_time')" prop="updateTime">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
prop="caseTotal"
:label="$t('api_test.definition.api_case_number')"
show-overflow-tooltip/>
<el-table-column
prop="caseStatus"
:label="$t('api_test.definition.api_case_status')"
show-overflow-tooltip/>
<!-- <el-table-column
prop="casePassingRate"
:label="$t('api_test.definition.api_case_passing_rate')"
show-overflow-tooltip/>-->
<el-table-column :label="$t('commons.operating')" min-width="80" align="center">
<template v-slot:default="scope">
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="initApiTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
</el-card>
</div>
<div id="svgResize"/>
<div id="svgDown">
<ms-bottom-container v-bind:enableAsideHidden="isHide">
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="initApiTable" :visible="visible" :currentRow="currentRow" :api="selectApi"/>
</ms-bottom-container>
</div>
</div>
</template>
<script>
import MsTableHeader from '../../../../../components/common/components/MsTableHeader';
import MsTableOperator from "../../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
import MsTableButton from "../../../../common/components/MsTableButton";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
import MsTablePagination from "../../../../common/pagination/TablePagination";
import MsTag from "../../../../common/components/MsTag";
import MsApiCaseList from "./ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../../../definition/components/BottomContainer";
import ShowMoreBtn from "../../../../../components/track/case/components/ShowMoreBtn";
import {API_METHOD_COLOUR} from "../../../definition/model/JsonData";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiList",
components: {
MsTableButton,
MsTableOperatorButton,
MsTableOperator,
MsTableHeader,
MsTablePagination,
MsTag,
MsApiCaseList,
MsContainer,
MsBottomContainer,
ShowMoreBtn
},
data() {
return {
condition: {},
isHide: true,
selectApi: {},
moduleId: "",
deletePath: "/test/case/delete",
selectRows: new Set(),
buttons: [{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch}],
methodColorMap: new Map(API_METHOD_COLOUR),
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
projectId: "",
screenHeight: document.documentElement.clientHeight - 330,//
}
},
props: {
currentProtocol: String,
currentModule: Object,
visible: {
type: Boolean,
default: false,
},
currentRow: {
type: Object,
}
},
created: function () {
this.projectId = getCurrentProjectID();
this.initApiTable();
},
mounted() {
this.dragControllerDiv();
},
watch: {
currentModule() {
this.initApiTable();
this.apiCaseClose();
},
currentProtocol() {
this.initApiTable();
this.apiCaseClose();
},
},
methods: {
initApiTable() {
this.condition.filters = ["Prepare", "Underway", "Completed"];
if (this.currentModule != null) {
if (this.currentModule.id == "root") {
this.condition.moduleIds = [];
} else if (this.currentModule.id == "gc") {
this.condition.moduleIds = [];
this.condition.filters = ["Trash"];
}
else {
this.condition.moduleIds = this.currentModule.ids;
}
}
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
this.result = this.$post("/api/definition/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
});
},
handleSelect(selection, row) {
row.hashTree = [];
if (this.selectRows.has(row)) {
this.$set(row, "showMore", false);
this.selectRows.delete(row);
} else {
this.$set(row, "showMore", true);
this.selectRows.add(row);
}
let arr = Array.from(this.selectRows);
if (this.currentRow) {
this.currentRow.apis = arr;
}
// 1
if (this.selectRows.size === 1) {
this.$set(arr[0], "showMore", false);
} else if (this.selectRows.size === 2) {
arr.forEach(row => {
this.$set(row, "showMore", true);
})
}
},
handleSelectAll(selection) {
if (selection.length > 0) {
if (selection.length === 1) {
selection.hashTree = [];
this.selectRows.add(selection[0]);
} else {
this.tableData.forEach(item => {
item.hashTree = [];
this.$set(item, "showMore", true);
this.selectRows.add(item);
});
}
} else {
this.selectRows.clear();
this.tableData.forEach(row => {
this.$set(row, "showMore", false);
})
}
if (this.currentRow) {
let arr = Array.from(this.selectRows);
this.currentRow.apis = arr;
}
},
search() {
this.initApiTable();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
editApi(row) {
this.$emit('editApi', row);
},
reductionApi(row) {
row.status = 'Underway';
row.request = null;
row.response = null;
this.$fileUpload("/api/definition/update", null, [], row, () => {
this.$success(this.$t('commons.save_success'));
this.search();
});
},
handleDeleteBatch() {
if (this.currentModule != undefined && this.currentModule.id == "gc") {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/api/definition/deleteBatch/', ids, () => {
this.selectRows.clear();
this.initApiTable();
this.$success(this.$t('commons.delete_success'));
});
}
}
});
} else {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/api/definition/removeToGc/', ids, () => {
this.selectRows.clear();
this.initApiTable();
this.$success(this.$t('commons.delete_success'));
});
}
}
});
}
},
handleTestCase(testCase) {
let h = window.screen.height;
let svgTop = document.getElementById("svgTop");
svgTop.style.height = h / 2 - 200 + "px";
let svgDown = document.getElementById("svgDown");
svgDown.style.height = h / 2 + "px";
this.selectApi = testCase;
let request = JSON.parse(testCase.request);
this.selectApi.url = request.path;
this.isHide = false;
},
handleDelete(api) {
if (this.currentModule != undefined && this.currentModule.id == "gc") {
this.$get('/api/definition/delete/' + api.id, () => {
this.$success(this.$t('commons.delete_success'));
this.initApiTable();
});
return;
}
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + api.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = [api.id];
this.$post('/api/definition/removeToGc/', ids, () => {
this.$success(this.$t('commons.delete_success'));
this.initApiTable();
});
}
}
});
},
apiCaseClose() {
let h = window.screen.height;
let svgTop = document.getElementById("svgTop");
svgTop.style.height = h - 200 + "px";
let svgDown = document.getElementById("svgDown");
svgDown.style.height = 0 + "px";
this.isHide = true;
},
getColor(enable, method) {
if (enable) {
return this.methodColorMap.get(method);
}
},
dragControllerDiv: function () {
let svgResize = document.getElementById("svgResize");
let svgTop = document.getElementById("svgTop");
let svgDown = document.getElementById("svgDown");
let svgBox = document.getElementById("svgBox");
svgResize.onmousedown = function (e) {
let startY = e.clientY;
svgResize.top = svgResize.offsetTop;
document.onmousemove = function (e) {
let endY = e.clientY;
let moveLen = svgResize.top + (endY - startY);
let maxT = svgBox.clientHeight - svgResize.offsetHeight;
if (moveLen < 30) moveLen = 30;
if (moveLen > maxT - 30) moveLen = maxT - 30;
svgResize.style.top = moveLen;
svgTop.style.height = moveLen + "px";
svgDown.style.height = (svgBox.clientHeight - moveLen - 5) + "px";
}
document.onmouseup = function (evt) {
document.onmousemove = null;
document.onmouseup = null;
svgResize.releaseCapture && svgResize.releaseCapture();
}
svgResize.setCapture && svgResize.setCapture();
return false;
}
},
}
}
</script>
<style scoped>
.operate-button > div {
display: inline-block;
margin-left: 10px;
}
.request-method {
padding: 0 5px;
color: #1E90FF;
}
.api-el-tag {
color: white;
}
#svgBox {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
#svgTop {
height: calc(30% - 5px);
width: 100%;
float: left;
overflow: auto;
}
#svgResize {
position: relative;
height: 5px;
width: 100%;
cursor: s-resize;
float: left;
}
#svgDown {
height: 70%;
width: 100%;
float: left;
overflow: hidden;
}
</style>

View File

@ -23,11 +23,7 @@
<div v-for="(item,index) in apiCaseList" :key="index">
<el-card style="margin-top: 5px" @click.native="selectTestCase(item,$event)">
<el-row>
<el-col :span="1">
<el-checkbox v-if="visible" @change="caseChecked(item)"/>
</el-col>
<el-col :span="5">
<el-col :span="6">
<div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{index+1}}</div>
</div>
@ -139,13 +135,12 @@
MsApiExtendBtns
},
props: {
api: {
type: Object
},
createCase: String,
loaded: Boolean,
refreshSign: String,
currentRow: Object,
currentApi: {
type: Object
},
},
data() {
return {
@ -162,22 +157,22 @@
projectId: "",
checkedCases: new Set(),
visible: false,
condition: {}
condition: {},
api: {}
}
},
watch: {
refreshSign() {
if (this.currentRow) {
this.currentRow.cases = [];
}
this.api = this.currentApi;
this.getApiTest();
},
createCase() {
this.api = this.currentApi;
this.sysAddition();
}
},
created() {
this.api = this.currentApi;
this.projectId = getCurrentProjectID();
if (this.createCase) {
this.sysAddition();
@ -186,21 +181,16 @@
}
},
methods: {
open() {
this.init();
this.visible = true;
},
init() {
if (this.currentRow) {
this.currentRow.cases = [];
}
open(api) {
this.api = api;
this.getApiTest();
this.visible = true;
},
setEnvironment(environment) {
this.environment = environment;
},
sysAddition() {
this.condition.projectId = this.api.projectId;
this.condition.projectId = this.projectId;
this.condition.apiDefinitionId = this.api.id;
this.$post("/api/testcase/list", this.condition, response => {
for (let index in response.data) {
@ -332,18 +322,20 @@
return bodyUploadFiles;
},
getApiTest() {
this.condition.projectId = this.api.projectId;
this.condition.apiDefinitionId = this.api.id;
this.result = this.$post("/api/testcase/list", this.condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.request = JSON.parse(test.request);
}
this.apiCaseList = response.data;
if (this.apiCaseList.length == 0) {
this.addCase();
}
});
if (this.api) {
this.condition.projectId = this.projectId;
this.condition.apiDefinitionId = this.api.id;
this.result = this.$post("/api/testcase/list", this.condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.request = JSON.parse(test.request);
}
this.apiCaseList = response.data;
if (this.apiCaseList.length == 0) {
this.addCase();
}
});
}
},
validate(row) {
if (!row.name) {
@ -356,7 +348,7 @@
return;
}
let bodyFiles = this.getBodyUploadFiles(row);
row.projectId = this.api.projectId;
row.projectId = this.projectId;
row.apiDefinitionId = row.apiDefinitionId || this.api.id;
let url = "/api/testcase/create";
if (row.id) {
@ -386,17 +378,6 @@
}
},
caseChecked(row) {
row.protocol = this.api.protocol;
row.hashTree = [];
if (this.checkedCases.has(row)) {
this.checkedCases.delete(row);
} else {
this.checkedCases.add(row)
}
let arr = Array.from(this.checkedCases);
this.currentRow.cases = arr;
},
handleClose() {
this.visible = false;
}

View File

@ -1,94 +1,87 @@
<template>
<div>
<el-card class="card-content">
<el-input placeholder="搜索" @blur="search" class="search-input" size="small" v-model="condition.name"/>
<el-input placeholder="搜索" @blur="search" class="search-input" size="small" v-model="condition.name"/>
<el-table border :data="tableData" row-key="id" class="test-content adjust-table"
@select-all="handleSelectAll"
@select="handleSelect" :height="screenHeight">
<el-table-column type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
</template>
</el-table-column>
<el-table border :data="tableData" row-key="id" class="test-content adjust-table"
@select-all="handleSelectAll"
@select="handleSelect" :height="screenHeight">
<el-table-column type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
</template>
</el-table-column>
<el-table-column prop="name" :label="$t('api_test.definition.api_name')" show-overflow-tooltip/>
<el-table-column
prop="status"
column-key="api_status"
:label="$t('api_test.definition.api_status')"
show-overflow-tooltip>
<template v-slot:default="scope">
<ms-tag v-if="scope.row.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="scope.row.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="scope.row.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
<ms-tag v-if="scope.row.status == 'Trash'" type="danger" effect="plain" content="废弃"/>
</template>
</el-table-column>
<el-table-column prop="name" :label="$t('api_test.definition.api_name')" show-overflow-tooltip/>
<el-table-column
prop="status"
column-key="api_status"
:label="$t('api_test.definition.api_status')"
show-overflow-tooltip>
<template v-slot:default="scope">
<ms-tag v-if="scope.row.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="scope.row.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="scope.row.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
<ms-tag v-if="scope.row.status == 'Trash'" type="danger" effect="plain" content="废弃"/>
</template>
</el-table-column>
<el-table-column
prop="method"
:label="$t('api_test.definition.api_type')"
show-overflow-tooltip>
<template v-slot:default="scope" class="request-method">
<el-tag size="mini" :style="{'background-color': getColor(true, scope.row.method)}" class="api-el-tag">
{{ scope.row.method}}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="method"
:label="$t('api_test.definition.api_type')"
show-overflow-tooltip>
<template v-slot:default="scope" class="request-method">
<el-tag size="mini" :style="{'background-color': getColor(true, scope.row.method)}" class="api-el-tag">
{{ scope.row.method}}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="path"
:label="$t('api_test.definition.api_path')"
show-overflow-tooltip/>
<el-table-column
prop="path"
:label="$t('api_test.definition.api_path')"
show-overflow-tooltip/>
<el-table-column
prop="userName"
:label="$t('api_test.definition.api_principal')"
show-overflow-tooltip/>
<el-table-column
prop="userName"
:label="$t('api_test.definition.api_principal')"
show-overflow-tooltip/>
<el-table-column width="160" :label="$t('api_test.definition.api_last_time')" prop="updateTime">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column width="160" :label="$t('api_test.definition.api_last_time')" prop="updateTime">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
prop="caseTotal"
:label="$t('api_test.definition.api_case_number')"
show-overflow-tooltip/>
<el-table-column
prop="caseTotal"
:label="$t('api_test.definition.api_case_number')"
show-overflow-tooltip/>
<el-table-column
prop="caseStatus"
:label="$t('api_test.definition.api_case_status')"
show-overflow-tooltip/>
<el-table-column
prop="caseStatus"
:label="$t('api_test.definition.api_case_status')"
show-overflow-tooltip/>
<el-table-column
prop="casePassingRate"
:label="$t('api_test.definition.api_case_passing_rate')"
show-overflow-tooltip/>
<el-table-column
prop="casePassingRate"
:label="$t('api_test.definition.api_case_passing_rate')"
show-overflow-tooltip/>
<el-table-column :label="$t('commons.operating')" min-width="130" align="center">
<template v-slot:default="scope">
<div v-if="currentRow!=undefined && currentRow.referenced">
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
</div>
<div v-else>
<el-button type="text" @click="reductionApi(scope.row)" v-if="currentModule!=undefined && currentModule.id === 'gc'">恢复</el-button>
<el-button type="text" @click="editApi(scope.row)" v-else>编辑</el-button>
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="initApiTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
</el-card>
<ms-api-case-list @refresh="initApiTable" :currentRow="currentRow"
:api="selectApi" ref="caseList"/>
<el-table-column :label="$t('commons.operating')" min-width="130" align="center">
<template v-slot:default="scope">
<el-button type="text" @click="reductionApi(scope.row)" v-if="currentModule!=undefined && currentModule.id === 'gc'">恢复</el-button>
<el-button type="text" @click="editApi(scope.row)" v-else>编辑</el-button>
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">删除</el-button>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="initApiTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
</el-card>
<ms-api-case-list @refresh="initApiTable" :currentApi="selectApi" ref="caseList"/>
</div>
</template>
@ -146,9 +139,6 @@
visible: {
type: Boolean,
default: false,
},
currentRow: {
type: Object,
}
},
created: function () {
@ -198,9 +188,6 @@
this.selectRows.add(row);
}
let arr = Array.from(this.selectRows);
if (this.currentRow) {
this.currentRow.apis = arr;
}
// 1
if (this.selectRows.size === 1) {
this.$set(arr[0], "showMore", false);
@ -228,10 +215,6 @@
this.$set(row, "showMore", false);
})
}
if (this.currentRow) {
let arr = Array.from(this.selectRows);
this.currentRow.apis = arr;
}
},
search() {
this.initApiTable();
@ -283,11 +266,11 @@
});
}
},
handleTestCase(testCase) {
this.selectApi = testCase;
let request = JSON.parse(testCase.request);
handleTestCase(api) {
this.selectApi = api;
let request = JSON.parse(api.request);
this.selectApi.url = request.path;
this.$refs.caseList.open();
this.$refs.caseList.open(this.selectApi);
},
handleDelete(api) {
if (this.currentModule != undefined && this.currentModule.id == "gc") {

View File

@ -30,7 +30,7 @@
<!-- 加载用例 -->
<el-drawer :visible.sync="visible" direction="btt" :with-header="false" :modal="false" size="50%">
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :api="api"
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :currentApi="api"
:loaded="loaded" :refreshSign="refreshSign" :createCase="createCase"
ref="caseList"/>
</el-drawer>

View File

@ -74,7 +74,7 @@
:loaded="loaded"
:refreshSign="refreshSign"
:createCase="createCase"
:api="api"
:currentApi="api"
ref="caseList"/>
<!-- 环境 -->

View File

@ -29,7 +29,7 @@
<!-- 加载用例 -->
<el-drawer :visible.sync="visible" direction="btt" :with-header="false" :modal="false" size="50%">
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :api="api" :refreshSign="refreshSign"
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :currentApi="api" :refreshSign="refreshSign"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
</el-drawer>

View File

@ -30,7 +30,7 @@
<!-- 加载用例 -->
<el-drawer :visible.sync="visible" direction="btt" :with-header="false" :modal="false" size="50%">
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :api="api" :refreshSign="refreshSign"
<ms-api-case-list @apiCaseClose="apiCaseClose" @selectTestCase="selectTestCase" :currentApi="api" :refreshSign="refreshSign"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
</el-drawer>