feat: 接口测试用例保存tag

This commit is contained in:
Captain.B 2021-01-07 15:18:52 +08:00
parent 590e6c9a9c
commit 18340d16e5
11 changed files with 645 additions and 473 deletions

View File

@ -4,6 +4,7 @@ import io.metersphere.api.dto.definition.request.MsTestElement;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Setter @Setter
@ -35,4 +36,6 @@ public class SaveApiTestCaseRequest {
private Long updateTime; private Long updateTime;
private List<String> bodyUploadIds; private List<String> bodyUploadIds;
private List<String> tags = new ArrayList<>();
} }

View File

@ -222,6 +222,7 @@ public class ApiTestCaseService {
test.setPriority(request.getPriority()); test.setPriority(request.getPriority());
test.setUpdateTime(System.currentTimeMillis()); test.setUpdateTime(System.currentTimeMillis());
test.setDescription(request.getDescription()); test.setDescription(request.getDescription());
test.setTags(JSON.toJSONString(new HashSet<>(request.getTags())));
apiTestCaseMapper.updateByPrimaryKeySelective(test); apiTestCaseMapper.updateByPrimaryKeySelective(test);
return test; return test;
} }
@ -243,6 +244,7 @@ public class ApiTestCaseService {
test.setUpdateTime(System.currentTimeMillis()); test.setUpdateTime(System.currentTimeMillis());
test.setDescription(request.getDescription()); test.setDescription(request.getDescription());
test.setNum(getNextNum(request.getApiDefinitionId())); test.setNum(getNextNum(request.getApiDefinitionId()));
test.setTags(JSON.toJSONString(new HashSet<>(request.getTags())));
apiTestCaseMapper.insert(test); apiTestCaseMapper.insert(test);
return test; return test;
} }

View File

@ -1,8 +1,9 @@
package io.metersphere.base.domain; package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
@Data @Data
public class ApiTestCase implements Serializable { public class ApiTestCase implements Serializable {
private String id; private String id;
@ -25,5 +26,7 @@ public class ApiTestCase implements Serializable {
private Integer num; private Integer num;
private String tags;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -773,6 +773,76 @@ public class ApiTestCaseExample {
addCriterion("num not between", value1, value2, "num"); addCriterion("num not between", value1, value2, "num");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andTagsIsNull() {
addCriterion("tags is null");
return (Criteria) this;
}
public Criteria andTagsIsNotNull() {
addCriterion("tags is not null");
return (Criteria) this;
}
public Criteria andTagsEqualTo(String value) {
addCriterion("tags =", value, "tags");
return (Criteria) this;
}
public Criteria andTagsNotEqualTo(String value) {
addCriterion("tags <>", value, "tags");
return (Criteria) this;
}
public Criteria andTagsGreaterThan(String value) {
addCriterion("tags >", value, "tags");
return (Criteria) this;
}
public Criteria andTagsGreaterThanOrEqualTo(String value) {
addCriterion("tags >=", value, "tags");
return (Criteria) this;
}
public Criteria andTagsLessThan(String value) {
addCriterion("tags <", value, "tags");
return (Criteria) this;
}
public Criteria andTagsLessThanOrEqualTo(String value) {
addCriterion("tags <=", value, "tags");
return (Criteria) this;
}
public Criteria andTagsLike(String value) {
addCriterion("tags like", value, "tags");
return (Criteria) this;
}
public Criteria andTagsNotLike(String value) {
addCriterion("tags not like", value, "tags");
return (Criteria) this;
}
public Criteria andTagsIn(List<String> values) {
addCriterion("tags in", values, "tags");
return (Criteria) this;
}
public Criteria andTagsNotIn(List<String> values) {
addCriterion("tags not in", values, "tags");
return (Criteria) this;
}
public Criteria andTagsBetween(String value1, String value2) {
addCriterion("tags between", value1, value2, "tags");
return (Criteria) this;
}
public Criteria andTagsNotBetween(String value1, String value2) {
addCriterion("tags not between", value1, value2, "tags");
return (Criteria) this;
}
} }
public static class Criteria extends GeneratedCriteria { public static class Criteria extends GeneratedCriteria {

View File

@ -12,6 +12,7 @@
<result column="create_time" jdbcType="BIGINT" property="createTime" /> <result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" /> <result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="num" jdbcType="INTEGER" property="num" /> <result column="num" jdbcType="INTEGER" property="num" />
<result column="tags" jdbcType="VARCHAR" property="tags" />
</resultMap> </resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiTestCaseWithBLOBs"> <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiTestCaseWithBLOBs">
<result column="description" jdbcType="LONGVARCHAR" property="description" /> <result column="description" jdbcType="LONGVARCHAR" property="description" />
@ -78,7 +79,7 @@
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, project_id, `name`, priority, api_definition_id, create_user_id, update_user_id, id, project_id, `name`, priority, api_definition_id, create_user_id, update_user_id,
create_time, update_time, num create_time, update_time, num, tags
</sql> </sql>
<sql id="Blob_Column_List"> <sql id="Blob_Column_List">
description, request, response description, request, response
@ -135,13 +136,13 @@
insert into api_test_case (id, project_id, `name`, insert into api_test_case (id, project_id, `name`,
priority, api_definition_id, create_user_id, priority, api_definition_id, create_user_id,
update_user_id, create_time, update_time, update_user_id, create_time, update_time,
num, description, request, num, tags, description,
response) request, response)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{priority,jdbcType=VARCHAR}, #{apiDefinitionId,jdbcType=VARCHAR}, #{createUserId,jdbcType=VARCHAR}, #{priority,jdbcType=VARCHAR}, #{apiDefinitionId,jdbcType=VARCHAR}, #{createUserId,jdbcType=VARCHAR},
#{updateUserId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{updateUserId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{num,jdbcType=INTEGER}, #{description,jdbcType=LONGVARCHAR}, #{request,jdbcType=LONGVARCHAR}, #{num,jdbcType=INTEGER}, #{tags,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR},
#{response,jdbcType=LONGVARCHAR}) #{request,jdbcType=LONGVARCHAR}, #{response,jdbcType=LONGVARCHAR})
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiTestCaseWithBLOBs"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiTestCaseWithBLOBs">
insert into api_test_case insert into api_test_case
@ -176,6 +177,9 @@
<if test="num != null"> <if test="num != null">
num, num,
</if> </if>
<if test="tags != null">
tags,
</if>
<if test="description != null"> <if test="description != null">
description, description,
</if> </if>
@ -217,6 +221,9 @@
<if test="num != null"> <if test="num != null">
#{num,jdbcType=INTEGER}, #{num,jdbcType=INTEGER},
</if> </if>
<if test="tags != null">
#{tags,jdbcType=VARCHAR},
</if>
<if test="description != null"> <if test="description != null">
#{description,jdbcType=LONGVARCHAR}, #{description,jdbcType=LONGVARCHAR},
</if> </if>
@ -267,6 +274,9 @@
<if test="record.num != null"> <if test="record.num != null">
num = #{record.num,jdbcType=INTEGER}, num = #{record.num,jdbcType=INTEGER},
</if> </if>
<if test="record.tags != null">
tags = #{record.tags,jdbcType=VARCHAR},
</if>
<if test="record.description != null"> <if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR}, description = #{record.description,jdbcType=LONGVARCHAR},
</if> </if>
@ -293,6 +303,7 @@
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
num = #{record.num,jdbcType=INTEGER}, num = #{record.num,jdbcType=INTEGER},
tags = #{record.tags,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR}, description = #{record.description,jdbcType=LONGVARCHAR},
request = #{record.request,jdbcType=LONGVARCHAR}, request = #{record.request,jdbcType=LONGVARCHAR},
response = #{record.response,jdbcType=LONGVARCHAR} response = #{record.response,jdbcType=LONGVARCHAR}
@ -311,7 +322,8 @@
update_user_id = #{record.updateUserId,jdbcType=VARCHAR}, update_user_id = #{record.updateUserId,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
num = #{record.num,jdbcType=INTEGER} num = #{record.num,jdbcType=INTEGER},
tags = #{record.tags,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -346,6 +358,9 @@
<if test="num != null"> <if test="num != null">
num = #{num,jdbcType=INTEGER}, num = #{num,jdbcType=INTEGER},
</if> </if>
<if test="tags != null">
tags = #{tags,jdbcType=VARCHAR},
</if>
<if test="description != null"> <if test="description != null">
description = #{description,jdbcType=LONGVARCHAR}, description = #{description,jdbcType=LONGVARCHAR},
</if> </if>
@ -369,6 +384,7 @@
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
num = #{num,jdbcType=INTEGER}, num = #{num,jdbcType=INTEGER},
tags = #{tags,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR}, description = #{description,jdbcType=LONGVARCHAR},
request = #{request,jdbcType=LONGVARCHAR}, request = #{request,jdbcType=LONGVARCHAR},
response = #{response,jdbcType=LONGVARCHAR} response = #{response,jdbcType=LONGVARCHAR}
@ -384,7 +400,8 @@
update_user_id = #{updateUserId,jdbcType=VARCHAR}, update_user_id = #{updateUserId,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
num = #{num,jdbcType=INTEGER} num = #{num,jdbcType=INTEGER},
tags = #{tags,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>

View File

@ -162,6 +162,7 @@
atc.update_user_id, atc.update_user_id,
atc.update_time, atc.update_time,
atc.num, atc.num,
atc.tags,
ader.status execResult, ader.status execResult,
ader.create_time execTime ader.create_time execTime
from from

View File

@ -1,8 +1,8 @@
ALTER TABLE api_definition ALTER TABLE api_definition
ADD tag VARCHAR(1000) NULL; ADD tags VARCHAR(1000) NULL;
ALTER TABLE api_test_case ALTER TABLE api_test_case
ADD tag VARCHAR(1000) NULL; ADD tags VARCHAR(1000) NULL;
ALTER TABLE test_case ALTER TABLE test_case
ADD tag VARCHAR(1000) NULL; ADD tags VARCHAR(1000) NULL;

View File

@ -1,309 +1,377 @@
<template> <template>
<el-card style="margin-top: 5px" @click.native="selectTestCase(apiCase,$event)"> <el-card style="margin-top: 5px" @click.native="selectTestCase(apiCase,$event)">
<el-row> <el-row>
<el-col :span="6"> <el-col :span="6">
<div class="el-step__icon is-text ms-api-col"> <div class="el-step__icon is-text ms-api-col">
<div class="el-step__icon-inner">{{index+1}}</div> <div class="el-step__icon-inner">{{ index + 1 }}</div>
</div> </div>
<label class="ms-api-label">{{$t('test_track.case.priority')}}</label> <label class="ms-api-label">{{ $t('test_track.case.priority') }}</label>
<el-select size="small" v-model="apiCase.priority" class="ms-api-select" @change="changePriority(apiCase)"> <el-select size="small" v-model="apiCase.priority" class="ms-api-select" @change="changePriority(apiCase)">
<el-option v-for="grd in priorities" :key="grd.id" :label="grd.name" :value="grd.id"/> <el-option v-for="grd in priorities" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="10"> <el-col :span="10">
<i class="icon el-icon-arrow-right" :class="{'is-active': apiCase.active}" <i class="icon el-icon-arrow-right" :class="{'is-active': apiCase.active}"
@click="active(apiCase)"/> @click="active(apiCase)"/>
<el-input v-if="!apiCase.id || isShowInput" size="small" v-model="apiCase.name" :name="index" :key="index" <el-input v-if="!apiCase.id || isShowInput" size="small" v-model="apiCase.name" :name="index" :key="index"
class="ms-api-header-select" style="width: 180px" class="ms-api-header-select" style="width: 180px"
@blur="saveTestCase(apiCase)" placeholder="请输入用例名称"/> @blur="saveTestCase(apiCase)" placeholder="请输入用例名称"/>
<span v-else> <span v-else>
{{apiCase.id ? apiCase.name:''}} {{ apiCase.id ? apiCase.name : '' }}
<i class="el-icon-edit" style="cursor:pointer" @click="showInput(apiCase)" v-tester/> <i class="el-icon-edit" style="cursor:pointer" @click="showInput(apiCase)" v-tester/>
</span> </span>
<div v-if="apiCase.id" style="color: #999999;font-size: 12px">
<label class="ms-api-label" style="padding-left: 20px; padding-right: 20px;">{{ $t('commons.tag') }}</label>
<el-tag
:key="apiCase.id + '_' + index"
v-for="(tag, index) in apiCase.tags"
closable
size="mini"
:disable-transitions="false"
@close="handleClose(tag)">
{{ tag }}
</el-tag>
<el-input
class="input-new-tag"
v-if="inputVisible"
v-model="inputValue"
ref="saveTagInput"
size="mini"
@keyup.enter.native="handleInputConfirm"
@blur="handleInputConfirm"
>
</el-input>
<el-button v-else class="button-new-tag" size="mini" @click="showTagInput">+</el-button>
<div v-if="apiCase.id" style="color: #999999;font-size: 12px">
<span> <span>
{{apiCase.createTime | timestampFormatDate }} {{ apiCase.createTime | timestampFormatDate }}
{{apiCase.createUser}} {{$t('api_test.definition.request.create_info')}} {{ apiCase.createUser }} {{ $t('api_test.definition.request.create_info') }}
</span> </span>
<span> <span>
{{apiCase.updateTime | timestampFormatDate }} {{ apiCase.updateTime | timestampFormatDate }}
{{apiCase.updateUser}} {{$t('api_test.definition.request.update_info')}} {{ apiCase.updateUser }} {{ $t('api_test.definition.request.update_info') }}
</span> </span>
</div> </div>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<ms-tip-button @click="singleRun(apiCase)" :tip="$t('api_test.run')" icon="el-icon-video-play" <ms-tip-button @click="singleRun(apiCase)" :tip="$t('api_test.run')" icon="el-icon-video-play"
style="background-color: #409EFF;color: white" size="mini" :disabled="!apiCase.id" circle v-tester/> style="background-color: #409EFF;color: white" size="mini" :disabled="!apiCase.id" circle v-tester/>
<ms-tip-button @click="copyCase(apiCase)" :tip="$t('commons.copy')" icon="el-icon-document-copy" <ms-tip-button @click="copyCase(apiCase)" :tip="$t('commons.copy')" icon="el-icon-document-copy"
size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/> size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/>
<ms-tip-button @click="deleteCase(index,apiCase)" :tip="$t('commons.delete')" icon="el-icon-delete" <ms-tip-button @click="deleteCase(index,apiCase)" :tip="$t('commons.delete')" icon="el-icon-delete"
size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/> size="mini" :disabled="!apiCase.id || isCaseEdit" circle v-tester/>
<ms-api-extend-btns :is-case-edit="isCaseEdit" :row="apiCase" v-tester/> <ms-api-extend-btns :is-case-edit="isCaseEdit" :row="apiCase" v-tester/>
</el-col> </el-col>
<el-col :span="3"> <el-col :span="3">
<el-link type="danger" v-if="apiCase.execResult && apiCase.execResult==='error'" @click="showExecResult(apiCase)">{{getResult(apiCase.execResult)}}</el-link> <el-link type="danger" v-if="apiCase.execResult && apiCase.execResult==='error'" @click="showExecResult(apiCase)">
<el-link v-else-if="apiCase.execResult && apiCase.execResult==='success'" @click="showExecResult(apiCase)">{{getResult(apiCase.execResult)}}</el-link> {{ getResult(apiCase.execResult) }}
<div v-else> {{getResult(apiCase.execResult)}}</div> </el-link>
<el-link v-else-if="apiCase.execResult && apiCase.execResult==='success'" @click="showExecResult(apiCase)">
{{ getResult(apiCase.execResult) }}
</el-link>
<div v-else> {{ getResult(apiCase.execResult) }}</div>
<div v-if="apiCase.id" style="color: #999999;font-size: 12px"> <div v-if="apiCase.id" style="color: #999999;font-size: 12px">
<span> {{apiCase.execTime | timestampFormatDate }}</span> <span> {{ apiCase.execTime | timestampFormatDate }}</span>
{{apiCase.updateUser}} {{ apiCase.updateUser }}
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<!-- 请求参数--> <!-- 请求参数-->
<el-collapse-transition> <el-collapse-transition>
<div v-if="apiCase.active"> <div v-if="apiCase.active">
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p> <p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-api-request-form :is-read-only="isReadOnly" :headers="apiCase.request.headers " :request="apiCase.request" v-if="api.protocol==='HTTP'"/> <ms-api-request-form :is-read-only="isReadOnly" :headers="apiCase.request.headers " :request="apiCase.request" v-if="api.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="apiCase.request" v-if="api.protocol==='TCP'"/> <ms-tcp-basis-parameters :request="apiCase.request" v-if="api.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="apiCase.request" v-if="api.protocol==='SQL'"/> <ms-sql-basis-parameters :request="apiCase.request" v-if="api.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="apiCase.request" v-if="api.protocol==='DUBBO'"/> <ms-dubbo-basis-parameters :request="apiCase.request" v-if="api.protocol==='DUBBO'"/>
<!-- 保存操作 --> <!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(apiCase)" v-tester> <el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(apiCase)" v-tester>
{{$t('commons.save')}} {{ $t('commons.save') }}
</el-button> </el-button>
</div> </div>
</el-collapse-transition> </el-collapse-transition>
</el-card> </el-card>
</template> </template>
<script> <script>
import {getCurrentProjectID, getUUID} from "../../../../../../common/js/utils"; import {getCurrentProjectID, getUUID} from "../../../../../../common/js/utils";
import {PRIORITY, RESULT_MAP} from "../../model/JsonData"; import {PRIORITY, RESULT_MAP} from "../../model/JsonData";
import MsTag from "../../../../common/components/MsTag"; import MsTag from "../../../../common/components/MsTag";
import MsTipButton from "../../../../common/components/MsTipButton"; import MsTipButton from "../../../../common/components/MsTipButton";
import MsApiRequestForm from "../request/http/ApiRequestForm"; import MsApiRequestForm from "../request/http/ApiRequestForm";
import ApiEnvironmentConfig from "../environment/ApiEnvironmentConfig"; import ApiEnvironmentConfig from "../environment/ApiEnvironmentConfig";
import MsApiAssertions from "../assertion/ApiAssertions"; import MsApiAssertions from "../assertion/ApiAssertions";
import MsSqlBasisParameters from "../request/database/BasisParameters"; import MsSqlBasisParameters from "../request/database/BasisParameters";
import MsTcpBasisParameters from "../request/tcp/BasisParameters"; import MsTcpBasisParameters from "../request/tcp/BasisParameters";
import MsDubboBasisParameters from "../request/dubbo/BasisParameters"; import MsDubboBasisParameters from "../request/dubbo/BasisParameters";
import MsApiExtendBtns from "../reference/ApiExtendBtns"; import MsApiExtendBtns from "../reference/ApiExtendBtns";
export default { export default {
name: "ApiCaseItem", name: "ApiCaseItem",
components: { components: {
MsTag, MsTag,
MsTipButton, MsTipButton,
MsApiRequestForm, MsApiRequestForm,
ApiEnvironmentConfig, ApiEnvironmentConfig,
MsApiAssertions, MsApiAssertions,
MsSqlBasisParameters, MsSqlBasisParameters,
MsTcpBasisParameters, MsTcpBasisParameters,
MsDubboBasisParameters, MsDubboBasisParameters,
MsApiExtendBtns MsApiExtendBtns
},
data() {
return {
result: {},
grades: [],
environment: {},
isReadOnly: false,
selectedEvent: Object,
priorities: PRIORITY,
runData: [],
reportId: "",
checkedCases: new Set(),
visible: false,
condition: {},
isShowInput: false,
inputVisible: false,
inputValue: ''
}
},
props: {
apiCase: {
type: Object,
default() {
return {}
}
}, },
data() { index: {
return { type: Number,
result: {}, default() {
grades: [], return 0
environment: {}, }
isReadOnly: false, },
selectedEvent: Object, api: {
priorities: PRIORITY, type: Object,
runData: [], default() {
reportId: "", return {}
checkedCases: new Set(), }
visible: false, },
condition: {}, isCaseEdit: Boolean,
isShowInput: false },
watch: {},
methods: {
deleteCase(index, row) {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$get('/api/testcase/delete/' + row.id, () => {
this.$success(this.$t('commons.delete_success'));
this.$emit('refresh');
});
}
} }
}, });
props: {
apiCase: {
type: Object,
default() {
return {}
}
},
index: {
type: Number,
default() {
return 0
}
},
api: {
type: Object,
default() {
return {}
}
},
isCaseEdit: Boolean,
},
watch: {
},
methods: {
deleteCase(index, row) { },
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ", '', { singleRun(data) {
confirmButtonText: this.$t('commons.confirm'), this.$emit('singleRun', data);
callback: (action) => { },
if (action === 'confirm') { copyCase(data) {
this.$get('/api/testcase/delete/' + row.id, () => { let obj = {name: "copy_" + data.name, priority: data.priority, active: true, request: data.request};
this.$success(this.$t('commons.delete_success')); this.$emit('copyCase', obj);
this.$emit('refresh'); },
});
}
}
});
}, selectTestCase(item, $event) {
singleRun(data) { if (!item.id || !this.loaded) {
this.$emit('singleRun', data); return;
}, }
copyCase(data) { if ($event.currentTarget.className.indexOf('is-selected') > 0) {
let obj = {name: "copy_" + data.name, priority: data.priority, active: true, request: data.request}; $event.currentTarget.className = "el-card is-always-shadow";
this.$emit('copyCase', obj); this.$emit('selectTestCase', null);
}, } else {
if (this.selectedEvent.currentTarget != undefined) {
this.selectedEvent.currentTarget.className = "el-card is-always-shadow";
}
this.selectedEvent.currentTarget = $event.currentTarget;
$event.currentTarget.className = "el-card is-always-shadow is-selected";
this.$emit('selectTestCase', item);
}
selectTestCase(item, $event) { },
if (!item.id || !this.loaded) { changePriority(row) {
return; if (row.id) {
} this.saveTestCase(row);
if ($event.currentTarget.className.indexOf('is-selected') > 0) { }
$event.currentTarget.className = "el-card is-always-shadow"; },
this.$emit('selectTestCase', null); saveTestCase(row) {
} else { this.isShowInput = false;
if (this.selectedEvent.currentTarget != undefined) { if (this.validate(row)) {
this.selectedEvent.currentTarget.className = "el-card is-always-shadow"; return;
} }
this.selectedEvent.currentTarget = $event.currentTarget; let bodyFiles = this.getBodyUploadFiles(row);
$event.currentTarget.className = "el-card is-always-shadow is-selected"; row.projectId = getCurrentProjectID();
this.$emit('selectTestCase', item); row.active = true;
} row.request.path = this.api.path;
row.request.method = this.api.method;
}, row.apiDefinitionId = row.apiDefinitionId || this.api.id;
changePriority(row) { let url = "/api/testcase/create";
if (row.id) { if (row.id) {
this.saveTestCase(row); url = "/api/testcase/update";
} }
}, this.$fileUpload(url, null, bodyFiles, row, () => {
saveTestCase(row) { this.$success(this.$t('commons.save_success'));
this.isShowInput = false; this.$emit('refresh');
if (this.validate(row)) { });
return; },
} showInput(row) {
let bodyFiles = this.getBodyUploadFiles(row); // row.type = "create";
row.projectId = getCurrentProjectID(); this.isShowInput = true;
row.active = true; row.active = true;
row.request.path = this.api.path; this.active(row);
row.request.method = this.api.method; },
row.apiDefinitionId = row.apiDefinitionId || this.api.id; active(item) {
let url = "/api/testcase/create"; item.active = !item.active;
if (row.id) { },
url = "/api/testcase/update"; getResult(data) {
} if (RESULT_MAP.get(data)) {
this.$fileUpload(url, null, bodyFiles, row, () => { return RESULT_MAP.get(data);
this.$success(this.$t('commons.save_success')); } else {
this.$emit('refresh'); return RESULT_MAP.get("default");
}); }
}, },
showInput(row) { validate(row) {
// row.type = "create"; if (!row.name) {
this.isShowInput = true; this.$warning(this.$t('api_test.input_name'));
row.active = true; return true;
this.active(row); }
}, },
active(item) { showExecResult(data) {
item.active = !item.active; this.$emit('showExecResult', data);
}, },
getResult(data) { getBodyUploadFiles(row) {
if (RESULT_MAP.get(data)) { let bodyUploadFiles = [];
return RESULT_MAP.get(data); row.bodyUploadIds = [];
} else { let request = row.request;
return RESULT_MAP.get("default"); if (request.body && request.body.kvs) {
} request.body.kvs.forEach(param => {
}, if (param.files) {
validate(row) { param.files.forEach(item => {
if (!row.name) { if (item.file) {
this.$warning(this.$t('api_test.input_name')); let fileId = getUUID().substring(0, 8);
return true; item.name = item.file.name;
} item.id = fileId;
}, row.bodyUploadIds.push(fileId);
showExecResult(data) { bodyUploadFiles.push(item.file);
this.$emit('showExecResult', data);
},
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) { if (request.body.binary) {
param.files.forEach(item => { request.body.binary.forEach(param => {
if (item.file) { if (param.files) {
let fileId = getUUID().substring(0, 8); param.files.forEach(item => {
item.name = item.file.name; if (item.file) {
item.id = fileId; let fileId = getUUID().substring(0, 8);
row.bodyUploadIds.push(fileId); item.name = item.file.name;
bodyUploadFiles.push(item.file); item.id = fileId;
} row.bodyUploadIds.push(fileId);
}); bodyUploadFiles.push(item.file);
} }
}); });
} }
} });
return bodyUploadFiles; }
},
} }
return bodyUploadFiles;
},
handleClose(tag) {
this.apiCase.tags.splice(this.apiCase.tags.indexOf(tag), 1);
this.saveTestCase(this.apiCase)
},
showTagInput() {
this.inputVisible = true;
this.$nextTick(_ => {
this.$refs.saveTagInput.$refs.input.focus();
});
},
handleInputConfirm() {
let inputValue = this.inputValue;
if (inputValue) {
this.apiCase.tags.push(inputValue);
this.saveTestCase(this.apiCase)
}
this.inputVisible = false;
this.inputValue = '';
} }
}
}
</script> </script>
<style scoped> <style scoped>
.ms-api-select { .ms-api-select {
margin-left: 20px; margin-left: 20px;
width: 80px; width: 80px;
} }
.ms-api-header-select { .ms-api-header-select {
margin-left: 20px; margin-left: 20px;
min-width: 100px; min-width: 100px;
} }
.ms-api-label { .ms-api-label {
color: #CCCCCC; color: #CCCCCC;
} }
.ms-api-col { .ms-api-col {
background-color: #7C3985; background-color: #7C3985;
border-color: #7C3985; border-color: #7C3985;
margin-right: 10px; margin-right: 10px;
color: white; color: white;
} }
.icon.is-active { .icon.is-active {
transform: rotate(90deg); transform: rotate(90deg);
} }
.tip { .tip {
padding: 3px 5px; padding: 3px 5px;
font-size: 16px; font-size: 16px;
border-radius: 4px; border-radius: 4px;
border-left: 4px solid #783887; border-left: 4px solid #783887;
margin: 20px 0; margin: 20px 0;
} }
.is-selected { .is-selected {
background: #EFF7FF; background: #EFF7FF;
} }
.el-tag + .el-tag {
margin-left: 10px;
}
.button-new-tag {
margin-left: 10px;
height: 20px;
/*line-height: 30px;*/
padding-top: 0;
padding-bottom: 0;
}
.input-new-tag {
width: 90px;
margin-left: 10px;
vertical-align: bottom;
}
</style> </style>

View File

@ -42,216 +42,224 @@
</template> </template>
<script> <script>
import ApiCaseHeader from "./ApiCaseHeader"; import ApiCaseHeader from "./ApiCaseHeader";
import ApiCaseItem from "./ApiCaseItem"; import ApiCaseItem from "./ApiCaseItem";
import MsRun from "../Run"; import MsRun from "../Run";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils"; import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import MsDrawer from "../../../../common/components/MsDrawer"; import MsDrawer from "../../../../common/components/MsDrawer";
import {PRIORITY} from "../../model/JsonData"; import {PRIORITY} from "../../model/JsonData";
export default { export default {
name: 'ApiCaseList', name: 'ApiCaseList',
components: { components: {
MsDrawer, MsDrawer,
MsRun, MsRun,
ApiCaseHeader, ApiCaseHeader,
ApiCaseItem, ApiCaseItem,
},
props: {
createCase: String,
loaded: Boolean,
refreshSign: String,
currentApi: {
type: Object
}, },
props: { },
createCase: String, data() {
loaded: Boolean, return {
refreshSign: String, result: {},
currentApi: { grades: [],
type: Object environment: {},
}, isReadOnly: false,
}, selectedEvent: Object,
data() { priorities: PRIORITY,
return { apiCaseList: [],
result: {}, batchLoading: false,
grades: [], singleLoading: false,
environment: {}, singleRunId: "",
isReadOnly: false, runData: [],
selectedEvent: Object, reportId: "",
priorities: PRIORITY, projectId: "",
apiCaseList: [], testCaseId: "",
batchLoading: false, checkedCases: new Set(),
singleLoading: false, visible: false,
singleRunId: "", condition: {},
runData: [], api: {}
reportId: "", }
projectId: "", },
testCaseId: "", watch: {
checkedCases: new Set(), refreshSign() {
visible: false,
condition: {},
api: {}
}
},
watch: {
refreshSign() {
this.api = this.currentApi;
this.getApiTest();
},
createCase() {
this.api = this.currentApi;
this.sysAddition();
}
},
created() {
this.api = this.currentApi; this.api = this.currentApi;
this.projectId = getCurrentProjectID(); this.getApiTest();
if (this.createCase) {
this.sysAddition();
} else {
this.getApiTest();
}
}, },
computed: { createCase() {
isCaseEdit() { this.api = this.currentApi;
return this.testCaseId ? true : false; this.sysAddition();
} }
},
created() {
this.api = this.currentApi;
this.projectId = getCurrentProjectID();
if (this.createCase) {
this.sysAddition();
} else {
this.getApiTest();
}
},
computed: {
isCaseEdit() {
return this.testCaseId ? true : false;
}
},
methods: {
open(api, testCaseId) {
this.api = api;
// testCaseId
this.testCaseId = testCaseId;
this.getApiTest();
this.visible = true;
}, },
methods: { setEnvironment(environment) {
open(api, testCaseId) { this.environment = environment;
this.api = api; },
// testCaseId sysAddition() {
this.testCaseId = testCaseId; this.condition.projectId = this.projectId;
this.getApiTest(); this.condition.apiDefinitionId = this.api.id;
this.visible = true; this.$post("/api/testcase/list", this.condition, response => {
}, for (let index in response.data) {
setEnvironment(environment) { let test = response.data[index];
this.environment = environment; test.request = JSON.parse(test.request);
}, }
sysAddition() { this.apiCaseList = response.data;
this.addCase();
});
},
apiCaseClose() {
this.apiCaseList = [];
this.visible = false;
},
runRefresh(data) {
this.batchLoading = false;
this.singleLoading = false;
this.singleRunId = "";
this.$success(this.$t('schedule.event_success'));
this.getApiTest();
this.$emit('refresh');
},
refresh(data) {
this.getApiTest();
this.$emit('refresh');
},
getApiTest() {
if (this.api) {
this.condition.projectId = this.projectId; this.condition.projectId = this.projectId;
this.condition.apiDefinitionId = this.api.id; if (this.isCaseEdit) {
this.$post("/api/testcase/list", this.condition, response => { this.condition.id = this.testCaseId;
} else {
this.condition.apiDefinitionId = this.api.id;
}
this.result = this.$post("/api/testcase/list", this.condition, response => {
for (let index in response.data) { for (let index in response.data) {
let test = response.data[index]; let test = response.data[index];
test.request = JSON.parse(test.request); test.request = JSON.parse(test.request);
if (!test.request.hashTree) {
test.request.hashTree = [];
}
} }
this.apiCaseList = response.data; this.apiCaseList = response.data;
this.addCase(); if (this.apiCaseList.length == 0 && !this.loaded) {
}); this.addCase();
},
apiCaseClose() {
this.apiCaseList = [];
this.visible = false;
},
runRefresh(data) {
this.batchLoading = false;
this.singleLoading = false;
this.singleRunId = "";
this.$success(this.$t('schedule.event_success'));
this.getApiTest();
this.$emit('refresh');
},
refresh(data) {
this.getApiTest();
this.$emit('refresh');
},
getApiTest() {
if (this.api) {
this.condition.projectId = this.projectId;
if (this.isCaseEdit) {
this.condition.id = this.testCaseId;
} else {
this.condition.apiDefinitionId = this.api.id;
} }
this.result = this.$post("/api/testcase/list", this.condition, response => { this.apiCaseList.forEach(apiCase => {
for (let index in response.data) { if (!apiCase.tags) {
let test = response.data[index]; apiCase.tags = [];
test.request = JSON.parse(test.request); } else {
if (!test.request.hashTree) { apiCase.tags = JSON.parse(apiCase.tags);
test.request.hashTree = [];
}
}
this.apiCaseList = response.data;
if (this.apiCaseList.length == 0 && !this.loaded) {
this.addCase();
}
});
}
},
addCase() {
if (this.api.request) {
//
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', active: true};
obj.request = request;
this.apiCaseList.unshift(obj);
}
},
copyCase(data) {
this.apiCaseList.unshift(data);
},
handleClose() {
this.visible = false;
},
showExecResult(row) {
this.visible = false;
this.$emit('showExecResult', row);
},
singleRun(row) {
if (!this.environment || !this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
this.runData = [];
this.singleLoading = true;
this.singleRunId = row.id;
row.request.name = row.id;
row.request.useEnvironment = this.environment.id;
this.runData.push(row.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
},
batchRun() {
if (!this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
if (this.apiCaseList.length > 0) {
this.apiCaseList.forEach(item => {
if (item.id) {
item.request.name = item.id;
item.request.useEnvironment = this.environment.id;
this.runData.push(item.request);
} }
}) })
if (this.runData.length > 0) {
this.batchLoading = true; });
/*触发执行操作*/ }
this.reportId = getUUID().substring(0, 8); },
} else { addCase() {
this.$warning("没有可执行的用例!"); if (this.api.request) {
//
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', active: true, tags: []};
obj.request = request;
this.apiCaseList.unshift(obj);
}
},
copyCase(data) {
this.apiCaseList.unshift(data);
},
handleClose() {
this.visible = false;
},
showExecResult(row) {
this.visible = false;
this.$emit('showExecResult', row);
},
singleRun(row) {
if (!this.environment || !this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
this.runData = [];
this.singleLoading = true;
this.singleRunId = row.id;
row.request.name = row.id;
row.request.useEnvironment = this.environment.id;
this.runData.push(row.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
},
batchRun() {
if (!this.environment) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
if (this.apiCaseList.length > 0) {
this.apiCaseList.forEach(item => {
if (item.id) {
item.request.name = item.id;
item.request.useEnvironment = this.environment.id;
this.runData.push(item.request);
} }
})
if (this.runData.length > 0) {
this.batchLoading = true;
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
} else { } else {
this.$warning("没有可执行的用例!"); this.$warning("没有可执行的用例!");
} }
} else {
this.$warning("没有可执行的用例!");
} }
} }
} }
}
</script> </script>
<style scoped> <style scoped>
.ms-drawer >>> .ms-drawer-body { .ms-drawer >>> .ms-drawer-body {
margin-top: 80px; margin-top: 80px;
} }
</style> </style>

View File

@ -55,8 +55,8 @@
<el-col :span="8"> <el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag"> <el-form-item :label="$t('commons.tag')" prop="tag">
<el-tag <el-tag
:key="tag" :key="basicForm + '_' + index"
v-for="tag in basicForm.tags" v-for="(tag, index) in basicForm.tags"
closable closable
size="mini" size="mini"
:disable-transitions="false" :disable-transitions="false"

View File

@ -78,8 +78,8 @@
<el-col :span="8"> <el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag"> <el-form-item :label="$t('commons.tag')" prop="tag">
<el-tag <el-tag
:key="tag" :key="httpForm + '_' + index"
v-for="tag in httpForm.tags" v-for="(tag, index) in httpForm.tags"
closable closable
size="mini" size="mini"
:disable-transitions="false" :disable-transitions="false"