feat(测试跟踪): 用例步骤支持两种模式 (#2303)

* feat(测试跟踪): 用例步骤支持两种模式

* fix: 用例评审步骤支持两种模式

Co-authored-by: chenjianxing <jianxing.chen@fit2cloud.com>
Co-authored-by: jianxing <41557596+AgAngle@users.noreply.github.com>
This commit is contained in:
metersphere-bot 2021-04-27 11:57:24 +08:00 committed by GitHub
parent 6613cce4b5
commit e0a6707bfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 675 additions and 368 deletions

View File

@ -51,5 +51,7 @@ public class TestCase implements Serializable {
private String customNum;
private String stepModel;
private static final long serialVersionUID = 1L;
}

View File

@ -1673,6 +1673,77 @@ public class TestCaseExample {
addCriterion("custom_num not between", value1, value2, "customNum");
return (Criteria) this;
}
public Criteria andStepModelIsNull() {
addCriterion("step_model is null");
return (Criteria) this;
}
public Criteria andStepModelIsNotNull() {
addCriterion("step_model is not null");
return (Criteria) this;
}
public Criteria andStepModelEqualTo(String value) {
addCriterion("step_model =", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotEqualTo(String value) {
addCriterion("step_model <>", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelGreaterThan(String value) {
addCriterion("step_model >", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelGreaterThanOrEqualTo(String value) {
addCriterion("step_model >=", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelLessThan(String value) {
addCriterion("step_model <", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelLessThanOrEqualTo(String value) {
addCriterion("step_model <=", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelLike(String value) {
addCriterion("step_model like", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotLike(String value) {
addCriterion("step_model not like", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelIn(List<String> values) {
addCriterion("step_model in", values, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotIn(List<String> values) {
addCriterion("step_model not in", values, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelBetween(String value1, String value2) {
addCriterion("step_model between", value1, value2, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotBetween(String value1, String value2) {
addCriterion("step_model not between", value1, value2, "stepModel");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -27,5 +27,7 @@ public class TestCaseTemplate implements Serializable {
private Long updateTime;
private String stepModel;
private static final long serialVersionUID = 1L;
}

View File

@ -833,6 +833,76 @@ public class TestCaseTemplateExample {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andStepModelIsNull() {
addCriterion("step_model is null");
return (Criteria) this;
}
public Criteria andStepModelIsNotNull() {
addCriterion("step_model is not null");
return (Criteria) this;
}
public Criteria andStepModelEqualTo(String value) {
addCriterion("step_model =", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotEqualTo(String value) {
addCriterion("step_model <>", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelGreaterThan(String value) {
addCriterion("step_model >", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelGreaterThanOrEqualTo(String value) {
addCriterion("step_model >=", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelLessThan(String value) {
addCriterion("step_model <", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelLessThanOrEqualTo(String value) {
addCriterion("step_model <=", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelLike(String value) {
addCriterion("step_model like", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotLike(String value) {
addCriterion("step_model not like", value, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelIn(List<String> values) {
addCriterion("step_model in", values, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotIn(List<String> values) {
addCriterion("step_model not in", values, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelBetween(String value1, String value2) {
addCriterion("step_model between", value1, value2, "stepModel");
return (Criteria) this;
}
public Criteria andStepModelNotBetween(String value1, String value2) {
addCriterion("step_model not between", value1, value2, "stepModel");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -15,5 +15,7 @@ public class TestCaseTemplateWithBLOBs extends TestCaseTemplate implements Seria
private String actualResult;
private String steps;
private static final long serialVersionUID = 1L;
}

View File

@ -25,6 +25,7 @@
<result column="follow_people" jdbcType="VARCHAR" property="followPeople" />
<result column="status" jdbcType="VARCHAR" property="status" />
<result column="custom_num" jdbcType="VARCHAR" property="customNum" />
<result column="step_model" jdbcType="VARCHAR" property="stepModel" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestCaseWithBLOBs">
<result column="remark" jdbcType="LONGVARCHAR" property="remark" />
@ -94,7 +95,7 @@
<sql id="Base_Column_List">
id, node_id, node_path, project_id, `name`, `type`, maintainer, priority, `method`,
prerequisite, create_time, update_time, test_id, sort, num, other_test_name, review_status,
tags, demand_id, demand_name, follow_people, `status`, custom_num
tags, demand_id, demand_name, follow_people, `status`, custom_num, step_model
</sql>
<sql id="Blob_Column_List">
remark, steps, step_description, expected_result, custom_fields
@ -155,9 +156,9 @@
test_id, sort, num,
other_test_name, review_status, tags,
demand_id, demand_name, follow_people,
`status`, custom_num, remark,
steps, step_description, expected_result,
custom_fields)
`status`, custom_num, step_model,
remark, steps, step_description,
expected_result, custom_fields)
values (#{id,jdbcType=VARCHAR}, #{nodeId,jdbcType=VARCHAR}, #{nodePath,jdbcType=VARCHAR},
#{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{maintainer,jdbcType=VARCHAR}, #{priority,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR},
@ -165,9 +166,9 @@
#{testId,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER}, #{num,jdbcType=INTEGER},
#{otherTestName,jdbcType=VARCHAR}, #{reviewStatus,jdbcType=VARCHAR}, #{tags,jdbcType=VARCHAR},
#{demandId,jdbcType=VARCHAR}, #{demandName,jdbcType=VARCHAR}, #{followPeople,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{customNum,jdbcType=VARCHAR}, #{remark,jdbcType=LONGVARCHAR},
#{steps,jdbcType=LONGVARCHAR}, #{stepDescription,jdbcType=LONGVARCHAR}, #{expectedResult,jdbcType=LONGVARCHAR},
#{customFields,jdbcType=LONGVARCHAR})
#{status,jdbcType=VARCHAR}, #{customNum,jdbcType=VARCHAR}, #{stepModel,jdbcType=VARCHAR},
#{remark,jdbcType=LONGVARCHAR}, #{steps,jdbcType=LONGVARCHAR}, #{stepDescription,jdbcType=LONGVARCHAR},
#{expectedResult,jdbcType=LONGVARCHAR}, #{customFields,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseWithBLOBs">
insert into test_case
@ -241,6 +242,9 @@
<if test="customNum != null">
custom_num,
</if>
<if test="stepModel != null">
step_model,
</if>
<if test="remark != null">
remark,
</if>
@ -327,6 +331,9 @@
<if test="customNum != null">
#{customNum,jdbcType=VARCHAR},
</if>
<if test="stepModel != null">
#{stepModel,jdbcType=VARCHAR},
</if>
<if test="remark != null">
#{remark,jdbcType=LONGVARCHAR},
</if>
@ -422,6 +429,9 @@
<if test="record.customNum != null">
custom_num = #{record.customNum,jdbcType=VARCHAR},
</if>
<if test="record.stepModel != null">
step_model = #{record.stepModel,jdbcType=VARCHAR},
</if>
<if test="record.remark != null">
remark = #{record.remark,jdbcType=LONGVARCHAR},
</if>
@ -467,6 +477,7 @@
follow_people = #{record.followPeople,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
custom_num = #{record.customNum,jdbcType=VARCHAR},
step_model = #{record.stepModel,jdbcType=VARCHAR},
remark = #{record.remark,jdbcType=LONGVARCHAR},
steps = #{record.steps,jdbcType=LONGVARCHAR},
step_description = #{record.stepDescription,jdbcType=LONGVARCHAR},
@ -500,7 +511,8 @@
demand_name = #{record.demandName,jdbcType=VARCHAR},
follow_people = #{record.followPeople,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
custom_num = #{record.customNum,jdbcType=VARCHAR}
custom_num = #{record.customNum,jdbcType=VARCHAR},
step_model = #{record.stepModel,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -574,6 +586,9 @@
<if test="customNum != null">
custom_num = #{customNum,jdbcType=VARCHAR},
</if>
<if test="stepModel != null">
step_model = #{stepModel,jdbcType=VARCHAR},
</if>
<if test="remark != null">
remark = #{remark,jdbcType=LONGVARCHAR},
</if>
@ -616,6 +631,7 @@
follow_people = #{followPeople,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
custom_num = #{customNum,jdbcType=VARCHAR},
step_model = #{stepModel,jdbcType=VARCHAR},
remark = #{remark,jdbcType=LONGVARCHAR},
steps = #{steps,jdbcType=LONGVARCHAR},
step_description = #{stepDescription,jdbcType=LONGVARCHAR},
@ -646,7 +662,8 @@
demand_name = #{demandName,jdbcType=VARCHAR},
follow_people = #{followPeople,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
custom_num = #{customNum,jdbcType=VARCHAR}
custom_num = #{customNum,jdbcType=VARCHAR},
step_model = #{stepModel,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -13,11 +13,13 @@
<result column="prerequisite" jdbcType="VARCHAR" property="prerequisite" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="step_model" jdbcType="VARCHAR" property="stepModel" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestCaseTemplateWithBLOBs">
<result column="step_description" jdbcType="LONGVARCHAR" property="stepDescription" />
<result column="expected_result" jdbcType="LONGVARCHAR" property="expectedResult" />
<result column="actual_result" jdbcType="LONGVARCHAR" property="actualResult" />
<result column="steps" jdbcType="LONGVARCHAR" property="steps" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -79,10 +81,10 @@
</sql>
<sql id="Base_Column_List">
id, `name`, `type`, description, case_name, `system`, `global`, workspace_id, prerequisite,
create_time, update_time
create_time, update_time, step_model
</sql>
<sql id="Blob_Column_List">
step_description, expected_result, actual_result
step_description, expected_result, actual_result, steps
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestCaseTemplateExample" resultMap="ResultMapWithBLOBs">
select
@ -136,13 +138,15 @@
insert into test_case_template (id, `name`, `type`,
description, case_name, `system`,
`global`, workspace_id, prerequisite,
create_time, update_time, step_description,
expected_result, actual_result)
create_time, update_time, step_model,
step_description, expected_result,
actual_result, steps)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{caseName,jdbcType=VARCHAR}, #{system,jdbcType=BIT},
#{global,jdbcType=BIT}, #{workspaceId,jdbcType=VARCHAR}, #{prerequisite,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{stepDescription,jdbcType=LONGVARCHAR},
#{expectedResult,jdbcType=LONGVARCHAR}, #{actualResult,jdbcType=LONGVARCHAR})
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{stepModel,jdbcType=VARCHAR},
#{stepDescription,jdbcType=LONGVARCHAR}, #{expectedResult,jdbcType=LONGVARCHAR},
#{actualResult,jdbcType=LONGVARCHAR}, #{steps,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseTemplateWithBLOBs">
insert into test_case_template
@ -180,6 +184,9 @@
<if test="updateTime != null">
update_time,
</if>
<if test="stepModel != null">
step_model,
</if>
<if test="stepDescription != null">
step_description,
</if>
@ -189,6 +196,9 @@
<if test="actualResult != null">
actual_result,
</if>
<if test="steps != null">
steps,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -224,6 +234,9 @@
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="stepModel != null">
#{stepModel,jdbcType=VARCHAR},
</if>
<if test="stepDescription != null">
#{stepDescription,jdbcType=LONGVARCHAR},
</if>
@ -233,6 +246,9 @@
<if test="actualResult != null">
#{actualResult,jdbcType=LONGVARCHAR},
</if>
<if test="steps != null">
#{steps,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestCaseTemplateExample" resultType="java.lang.Long">
@ -277,6 +293,9 @@
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.stepModel != null">
step_model = #{record.stepModel,jdbcType=VARCHAR},
</if>
<if test="record.stepDescription != null">
step_description = #{record.stepDescription,jdbcType=LONGVARCHAR},
</if>
@ -286,6 +305,9 @@
<if test="record.actualResult != null">
actual_result = #{record.actualResult,jdbcType=LONGVARCHAR},
</if>
<if test="record.steps != null">
steps = #{record.steps,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -304,9 +326,11 @@
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
step_model = #{record.stepModel,jdbcType=VARCHAR},
step_description = #{record.stepDescription,jdbcType=LONGVARCHAR},
expected_result = #{record.expectedResult,jdbcType=LONGVARCHAR},
actual_result = #{record.actualResult,jdbcType=LONGVARCHAR}
actual_result = #{record.actualResult,jdbcType=LONGVARCHAR},
steps = #{record.steps,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -323,7 +347,8 @@
workspace_id = #{record.workspaceId,jdbcType=VARCHAR},
prerequisite = #{record.prerequisite,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}
update_time = #{record.updateTime,jdbcType=BIGINT},
step_model = #{record.stepModel,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -361,6 +386,9 @@
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="stepModel != null">
step_model = #{stepModel,jdbcType=VARCHAR},
</if>
<if test="stepDescription != null">
step_description = #{stepDescription,jdbcType=LONGVARCHAR},
</if>
@ -370,6 +398,9 @@
<if test="actualResult != null">
actual_result = #{actualResult,jdbcType=LONGVARCHAR},
</if>
<if test="steps != null">
steps = #{steps,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
@ -385,9 +416,11 @@
prerequisite = #{prerequisite,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
step_model = #{stepModel,jdbcType=VARCHAR},
step_description = #{stepDescription,jdbcType=LONGVARCHAR},
expected_result = #{expectedResult,jdbcType=LONGVARCHAR},
actual_result = #{actualResult,jdbcType=LONGVARCHAR}
actual_result = #{actualResult,jdbcType=LONGVARCHAR},
steps = #{steps,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestCaseTemplate">
@ -401,7 +434,8 @@
workspace_id = #{workspaceId,jdbcType=VARCHAR},
prerequisite = #{prerequisite,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}
update_time = #{updateTime,jdbcType=BIGINT},
step_model = #{stepModel,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -243,6 +243,11 @@ alter table load_test_report
ALTER TABLE issue_template MODIFY COLUMN title varchar(64) NULL COMMENT 'Issue title';
ALTER TABLE test_case_template MODIFY COLUMN case_name varchar(64) NULL COMMENT 'Test Case Name';
-- 用例步骤支持两种编辑模式
ALTER TABLE test_case_template ADD step_model varchar(10) NULL COMMENT 'Step model';
ALTER TABLE test_case_template ADD steps TEXT NULL COMMENT 'Test case step';
ALTER TABLE test_case ADD step_model varchar(10) NULL COMMENT 'Test case step model';
-- 去掉测试方式
UPDATE system_header
SET props='[{"id":"num","label":"ID"},{"id":"name","label":"名称"},{"id":"priority","label":"用例等级"},{"id":"type","label":"类型"},{"id":"tags","label":"标签"},{"id":"nodePath","label":"所属模块"},{"id":"projectName","label":"所属项目"},{"id":"issuesContent","label":"缺陷"},{"id":"executorName","label":"执行人"},{"id":"status","label":"执行结果"},{"id":"updateTime","label":"更新时间"},{"id":"maintainer","label":"责任人"}]'
@ -250,4 +255,4 @@ WHERE `type`='test_plan_function_test_case';
-- 自定义用例ID
alter table project add custom_num tinyint(1) default 0 null comment '是否开启自定义ID(默认关闭)';
alter table test_case add custom_num varchar(64) null comment 'custom num';
alter table test_case add custom_num varchar(64) null comment 'custom num';

View File

@ -77,10 +77,10 @@
<table tableName="test_case_review_scenario"/>
<table tableName="test_plan"/>
<table tableName="test_case_test"/>-->
<!-- <table tableName="test_case_template"></table>-->
<table tableName="test_case_template"></table>
<!-- <table tableName="custom_field"></table>-->
<!-- <table tableName="test_case"></table>-->
<table tableName="issues"></table>
<table tableName="test_case"></table>
<!-- <table tableName="custom_field_template"></table>-->
</context>

View File

@ -8,16 +8,16 @@
ref="msEditDialog">
<el-form :model="form" :rules="rules" label-position="right" label-width="140px" size="small" ref="form">
<el-form-item :label="'字段名'" prop="name">
<el-form-item :label="'字段名'" prop="name" :label-width="labelWidth">
<el-input v-if="isSystem" :disabled="isSystem" :value="$t(systemNameMap[form.name])" autocomplete="off"></el-input>
<el-input v-else v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item :label="'字段备注'" prop="remark">
<el-form-item :label="'字段备注'" prop="remark" :label-width="labelWidth">
<el-input :autosize="{ minRows: 2, maxRows: 4}" type="textarea" v-model="form.remark"></el-input>
</el-form-item>
<el-form-item :label="'使用场景'" prop="type">
<el-form-item :label="'使用场景'" prop="type" :label-width="labelWidth">
<el-select :disabled="isSystem || isTemplateEdit" filterable v-model="form.scene" placeholder="使用场景">
<el-option
v-for="item in sceneOptions"
@ -28,7 +28,7 @@
</el-select>
</el-form-item>
<el-form-item :label="'字段类型'" prop="type">
<el-form-item :label="'字段类型'" prop="type" :label-width="labelWidth">
<el-select :disabled="isSystem" filterable v-model="form.type" placeholder="字段类型">
<el-option
v-for="item in fieldTypeOptions"
@ -42,7 +42,7 @@
<el-form-item
v-if="showOptions"
:label="'选项值'"
prop="options">
prop="options" :label-width="labelWidth">
<ms-single-handle-drag
:data="form.options"/>
</el-form-item>
@ -60,7 +60,7 @@ import {CUSTOM_FIELD_SCENE_OPTION, CUSTOM_FIELD_TYPE_OPTION, SYSTEM_FIELD_NAME_M
export default {
name: "CustomFieldEdit",
components: {MsSingleHandleDrag, MsEditDialog},
props: ['scene'],
props: ['scene','labelWidth'],
data() {
return {
form: {

View File

@ -18,13 +18,13 @@
<ms-form-divider :title="'基础信息'"/>
<el-form :model="form" :rules="rules" label-position="right" label-width="140px" size="small" ref="form">
<el-form-item :label="'名称'" prop="name">
<el-form-item :label="'名称'" prop="name" :label-width="labelWidth">
<el-input :disabled="isSystem" v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<slot name="base"></slot>
<el-form-item :label="'描述'" prop="description">
<el-form-item :label="'描述'" prop="description" :label-width="labelWidth">
<el-input :autosize="{ minRows: 2, maxRows: 4}" type="textarea" v-model="form.description"></el-input>
</el-form-item>
@ -32,12 +32,12 @@
<slot></slot>
<el-form-item :label="'已选字段'" class="filed-list">
<el-form-item :label="'已选字段'" class="filed-list" :label-width="labelWidth">
<el-button type="primary" @click="relateField">添加字段</el-button>
<el-button type="primary" @click="addField" plain>设置自定义字段</el-button>
</el-form-item>
<el-form-item>
<el-form-item :label-width="labelWidth">
<custom-field-form-list
:table-data="relateFields"
:scene="scene"
@ -56,7 +56,7 @@
:scene="scene"
ref="customFieldRelateList"/>
<custom-field-edit :scene="scene" @save="handleCustomFieldAdd" ref="customFieldEdit"/>
<custom-field-edit :label-width="labelWidth" :scene="scene" @save="handleCustomFieldAdd" ref="customFieldEdit"/>
</el-scrollbar>
</el-main>
@ -102,6 +102,7 @@ export default {
scene: String,
url:String,
rules: Object,
labelWidth: String,
form:{
type: Object,
default() {
@ -138,6 +139,9 @@ export default {
if (valid) {
let param = {};
Object.assign(param, this.form);
if (this.form.steps) {
param.steps = JSON.stringify(this.form.steps);
}
param.options = JSON.stringify(this.form.options);
param.workspaceId = getCurrentWorkspaceId();
let customFields = this.relateFields;

View File

@ -1,6 +1,7 @@
<template>
<field-template-edit
:label-width="labelWidth"
:form="form"
:visible.sync="showDialog"
:url="url"
@ -10,7 +11,7 @@
ref="fieldTemplateEdit">
<template v-slot:base>
<el-form-item :label="'缺陷平台'" prop="platform">
<el-form-item :label="'缺陷平台'" prop="platform" :label-width="labelWidth" >
<el-select :disabled="isSystem" filterable v-model="form.platform" placeholder="用例类型">
<el-option
v-for="item in platformOption"
@ -23,11 +24,11 @@
</template>
<template v-slot:default>
<el-form-item :label="'标题'" prop="title">
<el-form-item :label="'标题'" prop="title" :label-width="labelWidth">
<el-input v-model="form.title" autocomplete="off"></el-input>
</el-form-item>
<form-r-ich-text-item :title="$t('缺陷内容')" :data="form" prop="content"/>
<form-r-ich-text-item :label-width="labelWidth" :title="$t('缺陷内容')" :data="form" prop="content"/>
</template>
@ -67,8 +68,9 @@ export default {
description: '',
title: '',
content: '',
customFieldIds: [],
customFieldIds: []
},
labelWidth: '120px',
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},

View File

@ -1,6 +1,7 @@
<template>
<field-template-edit
:label-width="labelWidth"
:form="form"
:rules="rules"
:visible.sync="showDialog"
@ -10,7 +11,7 @@
ref="fieldTemplateEdit">
<template v-slot:base>
<el-form-item :label="'用例类型'" prop="type">
<el-form-item :label="'用例类型'" prop="type" :label-width="labelWidth">
<el-select :disabled="isSystem" filterable v-model="form.type" placeholder="用例类型">
<el-option
v-for="item in caseTypeOption"
@ -23,13 +24,19 @@
</template>
<template v-slot:default>
<el-form-item :label="'用例名称'" prop="caseName">
<el-form-item :label="'用例名称'" prop="caseName" :label-width="labelWidth">
<el-input v-model="form.caseName" autocomplete="off"></el-input>
</el-form-item>
<form-rich-text-item :title="$t('test_track.case.prerequisite')" :data="form" prop="prerequisite"/>
<form-rich-text-item :title="$t('test_track.case.step_desc')" :data="form" prop="stepDescription"/>
<form-rich-text-item :title="$t('test_track.case.expected_results')" :data="form" prop="expectedResult"/>
<form-rich-text-item :title="$t('test_track.plan_view.actual_result')" :data="form" prop="actualResult"/>
<form-rich-text-item :label-width="labelWidth" :title="$t('test_track.case.prerequisite')" :data="form" prop="prerequisite"/>
<form-rich-text-item :label-width="labelWidth" :title="$t('test_track.case.prerequisite')" :data="form" prop="prerequisite"/>
<step-change-item :form="form"/>
<test-case-step-item :label-width="labelWidth" v-if="form.stepModel === 'STEP'" :form="form"/>
<form-rich-text-item :label-width="labelWidth" v-if="form.stepModel === 'TEXT'" :title="$t('test_track.case.step_desc')" :data="form" prop="stepDescription"/>
<form-rich-text-item :label-width="labelWidth" v-if="form.stepModel === 'TEXT'" :title="$t('test_track.case.expected_results')" :data="form" prop="expectedResult"/>
<form-rich-text-item :label-width="labelWidth" v-if="form.stepModel === 'TEXT'" :title="$t('test_track.plan_view.actual_result')" :data="form" prop="actualResult"/>
</template>
</field-template-edit>
@ -47,10 +54,14 @@ import CustomFieldFormList from "@/business/components/settings/workspace/templa
import CustomFieldRelateList from "@/business/components/settings/workspace/template/CustomFieldRelateList";
import FieldTemplateEdit from "@/business/components/settings/workspace/template/FieldTemplateEdit";
import FormRichTextItem from "@/business/components/track/case/components/FormRichTextItem";
import TestCaseStepItem from "@/business/components/track/case/components/TestCaseStepItem";
import StepChangeItem from "@/business/components/track/case/components/StepChangeItem";
export default {
name: "TestCaseTemplateEdit",
components: {
StepChangeItem,
TestCaseStepItem,
FormRichTextItem,
FieldTemplateEdit,
CustomFieldRelateList,
@ -72,7 +83,10 @@ export default {
expectedResult: '',
actualResult: '',
customFieldIds: [],
stepModel: 'STEP',
steps: [],
},
labelWidth: '120px',
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
@ -96,6 +110,7 @@ export default {
open(data, isCopy) {
if (data) {
Object.assign(this.form, data);
this.form.steps = data.steps ? JSON.parse(data.steps) : [];
if (!(data.options instanceof Array)) {
this.form.options = data.options ? JSON.parse(data.options) : [];
}
@ -116,6 +131,7 @@ export default {
expectedResult: '',
actualResult: '',
customFieldIds: [],
steps: []
};
this.url = 'field/template/case/add';
}

View File

@ -1,5 +1,5 @@
<template>
<el-form-item :disable="true" :label="title" :prop="prop">
<el-form-item :disable="true" :label="title" :prop="prop" :label-width="labelWidth">
<test-case-rich-text :disabled="disabled" :content="data[prop]" @updateRichText="updateData"/>
</el-form-item>
</template>
@ -9,7 +9,7 @@ import TestCaseRichText from "@/business/components/track/case/components/MsRich
export default {
name: "FormRichTextItem",
components: {TestCaseRichText},
props: ['data', 'title', 'prop', 'disabled'],
props: ['data', 'title', 'prop', 'disabled', 'labelWidth'],
methods: {
updateData(value) {
this.data[this.prop] = value;

View File

@ -0,0 +1,51 @@
<template>
<el-form-item :label="form.stepModel === 'STEP' ? '步骤描述' : '文本描述'" :label-width="labelWidth">
<el-dropdown placement="bottom-start" @command="handleCommand">
<span class="el-dropdown-link">
更改类型<i class="el-icon-arrow-down el-icon--right"/>
</span>
<el-dropdown-menu>
<el-dropdown-item command="STEP">
<div>步骤描述</div>
<div>使用于简单的测试场景没有明确的测试步骤</div>
</el-dropdown-item>
<el-dropdown-item command="TEXT">
<div>文本描述</div>
<div>适用于需要每一个步骤进行测试的场景有明确的测试步骤预期结果</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-form-item>
</template>
<script>
export default {
name: "StepChangeItem",
props: ['form','labelWidth'],
created() {
if (!this.form.stepModel) {
this.form.stepModel = "STEP";
}
},
methods: {
handleCommand(value) {
this.form.stepModel = value;
}
}
}
</script>
<style scoped>
.el-dropdown-link {
cursor: pointer;
color: var(--primary_color);
}
.el-icon-arrow-down {
font-size: 12px;
}
.step-change-item:hover {
color: var(--primary_color);
background-color: #F5F7FA;
}
</style>

View File

@ -71,11 +71,13 @@
<ms-form-divider :title="$t('步骤信息')"/>
<div class="step-info">
<form-rich-text-item :title="$t('test_track.case.prerequisite')" :data="form" prop="prerequisite"/>
<form-rich-text-item :title="$t('test_track.case.step_desc')" :data="form" prop="stepDesc"/>
<form-rich-text-item :title="$t('test_track.case.expected_results')" :data="form" prop="stepResult"/>
</div>
<form-rich-text-item :label-width="formLabelWidth" :title="$t('test_track.case.prerequisite')" :data="form" prop="prerequisite"/>
<step-change-item :label-width="formLabelWidth" :form="form"/>
<form-rich-text-item :label-width="formLabelWidth" v-if="form.stepModel === 'TEXT'" :title="$t('test_track.case.step_desc')" :data="form" prop="stepDescription"/>
<form-rich-text-item :label-width="formLabelWidth" v-if="form.stepModel === 'TEXT'" :title="$t('test_track.case.expected_results')" :data="form" prop="expectedResult"/>
<test-case-step-item :label-width="formLabelWidth" v-if="form.stepModel === 'STEP'" :form="form" :read-only="readOnly"/>
<ms-form-divider :title="$t('其他信息')"/>
@ -133,7 +135,6 @@ import CustomFiledComponent from "@/business/components/settings/workspace/templ
import {
buildCustomFields,
buildTestCaseOldFields,
compatibleTestCaseStep,
getTemplate,
parseCustomField
} from "@/common/js/custom_field";
@ -141,10 +142,14 @@ import {SYSTEM_FIELD_NAME_MAP} from "@/common/js/table-constants";
import MsFormDivider from "@/business/components/common/components/MsFormDivider";
import TestCaseEditOtherInfo from "@/business/components/track/case/components/TestCaseEditOtherInfo";
import FormRichTextItem from "@/business/components/track/case/components/FormRichTextItem";
import TestCaseStepItem from "@/business/components/track/case/components/TestCaseStepItem";
import StepChangeItem from "@/business/components/track/case/components/StepChangeItem";
export default {
name: "TestCaseEdit",
components: {
StepChangeItem,
TestCaseStepItem,
FormRichTextItem,
TestCaseEditOtherInfo,
MsFormDivider,
@ -189,6 +194,9 @@ export default {
demandName: '',
status: 'Prepare',
reviewStatus: 'Prepare',
stepDescription: '',
expectedResult: '',
stepModel: 'STEP'
customNum: ''
},
readOnly: false,
@ -334,9 +342,12 @@ export default {
//
parseCustomField(this.form, this.testCaseTemplate, this.customFieldForm, this.customFieldRules, buildTestCaseOldFields(this.form));
this.form.name = this.testCaseTemplate.caseName;
this.form.stepDesc = this.testCaseTemplate.stepDescription;
this.form.stepResult = this.testCaseTemplate.expectedResult;
this.form.stepDescription = this.testCaseTemplate.stepDescription;
this.form.expectedResult = this.testCaseTemplate.expectedResult;
this.form.prerequisite = this.testCaseTemplate.prerequisite;
if (this.testCaseTemplate.steps) {
this.form.steps = JSON.parse(this.testCaseTemplate.steps);
}
}
},
@ -481,10 +492,18 @@ export default {
let tmp = {};
Object.assign(tmp, testCase);
tmp.steps = JSON.parse(testCase.steps);
//
compatibleTestCaseStep(testCase, tmp);
if (!tmp.steps || tmp.steps.length < 1) {
tmp.steps = [{
num: 1,
desc: '',
result: ''
}];
}
tmp.tags = JSON.parse(tmp.tags);
Object.assign(this.form, tmp);
if (!this.form.stepModel) {
this.form.stepModel = "STEP";
}
this.form.module = testCase.nodeId;
//
parseCustomField(this.form, this.testCaseTemplate, this.customFieldForm, this.customFieldRules, buildTestCaseOldFields(this.form));
@ -498,26 +517,6 @@ export default {
this.testCase = testCase.isCopy ? {} : testCase;
}
},
handleAddStep(index, data) {
let step = {};
step.num = data.num + 1;
step.desc = "";
step.result = "";
this.form.steps.forEach(step => {
if (step.num > data.num) {
step.num++;
}
});
this.form.steps.splice(index + 1, 0, step);
},
handleDeleteStep(index, data) {
this.form.steps.splice(index, 1);
this.form.steps.forEach(step => {
if (step.num > data.num) {
step.num--;
}
});
},
close() {
//
removeGoBackListener(this.close);
@ -566,9 +565,7 @@ export default {
buildParam() {
let param = {};
Object.assign(param, this.form);
param.steps = null; // 便
param.expectedResult = this.form.stepResult;
param.stepDescription = this.form.stepDesc; //
param.steps = JSON.stringify(this.form.steps);
param.nodeId = this.form.module;
param.nodePath = getNodePath(this.form.module, this.moduleOptions);
if (this.projectId) {
@ -651,14 +648,12 @@ export default {
};
},
validate(param) {
if(param.steps != null) {
for (let i = 0; i < param.steps.length; i++) {
if ((param.steps[i].desc && param.steps[i].desc.length > 300) ||
(param.steps[i].result && param.steps[i].result.length > 300)) {
this.$warning(this.$t('test_track.case.step_desc') + ","
+ this.$t('test_track.case.expectedResults') + this.$t('test_track.length_less_than') + '300');
return false;
}
for (let i = 0; i < param.steps.length; i++) {
if ((param.steps[i].desc && param.steps[i].desc.length > 300) ||
(param.steps[i].result && param.steps[i].result.length > 300)) {
this.$warning(this.$t('test_track.case.step_desc') + ","
+ this.$t('test_track.case.expected_results') + this.$t('test_track.length_less_than') + '300');
return false;
}
}
if (param.name == '') {
@ -785,8 +780,4 @@ export default {
height: 32px;
width: 56px;
}
.step-info {
padding: 30px;
}
</style>

View File

@ -312,6 +312,6 @@ export default {
}
.other-info-tabs {
padding: 30px 60px;
padding: 10px 60px;
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<el-form-item :label-width="labelWidth" prop="steps">
<el-table
:data="form.steps"
class="tb-edit"
border
size="mini"
:default-sort="{prop: 'num', order: 'ascending'}"
highlight-current-row>
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="10%"></el-table-column>
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="35%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
:disabled="readOnly"
type="textarea"
:autosize="{ minRows: 1, maxRows: 6}"
:rows="2"
v-model="scope.row.desc"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="35%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
:disabled="readOnly"
type="textarea"
:autosize="{ minRows: 1, maxRows: 6}"
:rows="2"
v-model="scope.row.result"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('commons.input_content')" min-width="25%">
<template v-slot:default="scope">
<el-button
type="primary"
:disabled="readOnly"
icon="el-icon-plus"
circle size="mini"
@click="handleAddStep(scope.$index, scope.row)"></el-button>
<el-button
icon="el-icon-document-copy"
type="success"
:disabled="readOnly"
circle size="mini"
@click="handleCopyStep(scope.$index, scope.row)"></el-button>
<el-button
type="danger"
icon="el-icon-delete"
circle size="mini"
@click="handleDeleteStep(scope.$index, scope.row)"
:disabled="readOnly || (scope.$index == 0 && form.steps.length <= 1)"></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</template>
<script>
export default {
name: "TestCaseStepItem",
props: {
labelWidth: String,
form: Object,
readOnly: Boolean
},
created() {
if (!this.form.steps || this.form.steps.length < 1) {
this.form.steps = [{
num: 1,
desc: '',
result: ''
}];
}
},
methods: {
handleAddStep(index, data) {
let step = {};
step.num = data.num + 1;
step.desc = "";
step.result = "";
this.form.steps.forEach(step => {
if (step.num > data.num) {
step.num++;
}
});
this.form.steps.splice(index + 1, 0, step);
},
handleCopyStep(index, data) {
let step = {};
step.num = data.num + 1;
step.desc = data.desc;
step.result = data.result;
this.form.steps.forEach(step => {
if (step.num > data.num) {
step.num++;
}
});
this.form.steps.splice(index + 1, 0, step);
},
handleDeleteStep(index, data) {
this.form.steps.splice(index, 1);
this.form.steps.forEach(step => {
if (step.num > data.num) {
step.num--;
}
});
},
}
}
</script>
<style scoped>
</style>

View File

@ -48,8 +48,4 @@
</script>
<style scoped>
.el-row {
width: 50%;
}
</style>

View File

@ -17,7 +17,6 @@
<el-scrollbar>
<el-header>
<el-row type="flex" class="head-bar">
<el-col :span="4">
@ -38,19 +37,22 @@
<el-divider content-position="left">{{ testCase.name }}</el-divider>
</el-col>
</el-row>
</el-header>
<div class="case_container">
<el-form>
<el-form :model="testCase">
<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 :span="7">
<el-form-item :label="$t('test_track.case.module')" prop="nodePath" :label-width="formLabelWidth">
{{testCase.nodePath}}
</el-form-item >
</el-col>
<el-col :span="5">
<span class="cast_label">{{ $t('test_track.case.module') }}</span>
<span class="cast_item">{{ testCase.nodePath }}</span>
<el-col :span="7">
<el-form-item :label="$t('test_track.plan.plan_project')" prop="projectName" :label-width="formLabelWidth">
{{testCase.projectName}}
</el-form-item >
</el-col>
<el-col :span="10">
<test-plan-test-case-status-button class="status-button"
@ -60,42 +62,23 @@
</el-col>
</el-row>
<el-row>
<el-col :span="4" :offset="1">
<span class="cast_label">{{ $t('test_track.plan.plan_project') }}</span>
<span class="cast_item">{{ testCase.projectName }}</span>
</el-col>
</el-row>
<el-row>
<el-col :span="4" :offset="1" v-if="testCase.testId == 'other'">
<span class="cast_label">{{ $t('test_track.case.test_name') }}</span>
<span class="cast_item">{{ testCase.otherTestName }}</span>
</el-col>
</el-row>
<el-form ref="customFieldForm"
class="case-form">
<el-row>
<el-col :span="7" v-for="(item, index) in testCaseTemplate.customFields" :key="index">
<el-form-item :label="item.system ? $t(systemNameMap[item.name]) : item.name" :prop="item.name"
label-width="120px">
<el-form-item :label-width="formLabelWidth" :label="item.system ? $t(systemNameMap[item.name]) : item.name" :prop="item.name">
<custom-filed-component :disabled="true" :data="item" :form="{}" prop="defaultValue"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row>
<el-col :span="22" :offset="1">
<div class="step-info">
<form-rich-text-item :disabled="true" :title="$t('test_track.case.prerequisite')" :data="testCase" prop="prerequisite"/>
<form-rich-text-item :disabled="true" :title="$t('test_track.case.step_desc')" :data="testCase" prop="stepDesc"/>
<form-rich-text-item :disabled="true" :title="$t('test_track.case.expected_results')" :data="testCase" prop="stepResult"/>
<form-rich-text-item :title="$t('test_track.plan_view.actual_result')" :data="testCase" prop="actualResult"/>
</div>
</el-col>
</el-row>
<form-rich-text-item :label-width="formLabelWidth" :disabled="true" :title="$t('test_track.case.prerequisite')" :data="testCase" prop="prerequisite"/>
<step-change-item :label-width="formLabelWidth" :form="testCase"/>
<test-plan-case-step-results-item :label-width="formLabelWidth" :is-read-only="isReadOnly" v-if="testCase.stepModel === 'STEP'" :test-case="testCase"/>
<form-rich-text-item :label-width="formLabelWidth" v-if="testCase.stepModel === 'TEXT'" :disabled="true" :title="$t('test_track.case.step_desc')" :data="testCase" prop="stepDescription"/>
<form-rich-text-item :label-width="formLabelWidth" v-if="testCase.stepModel === 'TEXT'" :disabled="true" :title="$t('test_track.case.expected_results')" :data="testCase" prop="expectedResult"/>
<form-rich-text-item :label-width="formLabelWidth" v-if="testCase.stepModel === 'TEXT'" :title="$t('test_track.plan_view.actual_result')" :data="testCase" prop="actualResult"/>
<test-case-edit-other-info @openTest="openTest" :read-only="true" :is-test-plan="true" :project-id="projectId" :form="testCase" :case-id="testCase.caseId" ref="otherInfo"/>
</el-form>
@ -141,17 +124,23 @@ import TestCaseAttachment from "@/business/components/track/case/components/Test
import CaseComment from "@/business/components/track/case/components/CaseComment";
import MsPreviousNextButton from "../../../../../common/components/MsPreviousNextButton";
import ReviewComment from "@/business/components/track/review/commom/ReviewComment";
import {buildTestCaseOldFields, compatibleTestCaseStep, getTemplate, parseCustomField} from "@/common/js/custom_field";
import {buildTestCaseOldFields, getTemplate, parseCustomField} from "@/common/js/custom_field";
import FormRichTextItem from "@/business/components/track/case/components/FormRichTextItem";
import MsFormDivider from "@/business/components/common/components/MsFormDivider";
import TestCaseEditOtherInfo from "@/business/components/track/case/components/TestCaseEditOtherInfo";
import CustomFiledComponent from "@/business/components/settings/workspace/template/CustomFiledComponent";
import {SYSTEM_FIELD_NAME_MAP} from "@/common/js/table-constants";
import IssueDescriptionTableItem from "@/business/components/track/issue/IssueDescriptionTableItem";
import StepChangeItem from "@/business/components/track/case/components/StepChangeItem";
import TestCaseStepItem from "@/business/components/track/case/components/TestCaseStepItem";
import TestPlanCaseStepResultsItem from "@/business/components/track/plan/view/comonents/functional/TestPlanCaseStepResultsItem";
export default {
name: "FunctionalTestCaseEdit",
components: {
TestPlanCaseStepResultsItem,
TestCaseStepItem,
StepChangeItem,
IssueDescriptionTableItem,
CustomFiledComponent,
TestCaseEditOtherInfo,
@ -190,7 +179,8 @@ export default {
hasZentaoId: false,
tableData: [],
comments: [],
testCaseTemplate: {}
testCaseTemplate: {},
formLabelWidth: "100px",
};
},
props: {
@ -278,9 +268,22 @@ export default {
let param = {};
param.id = this.testCase.id;
param.status = this.testCase.status;
param.results = [];
param.remark = this.testCase.remark;
param.projectId = this.projectId;
let option = this.getOption(param);
for (let i = 0; i < this.testCase.steptResults.length; i++) {
let result = {};
result.actualResult = this.testCase.steptResults[i].actualResult;
result.executeResult = this.testCase.steptResults[i].executeResult;
if (result.actualResult && result.actualResult.length > 300) {
this.$warning(this.$t('test_track.plan_view.actual_result')
+ this.$t('test_track.length_less_than') + '300');
return;
}
param.results.push(result);
}
param.results = JSON.stringify(param.results);
param.actualResult = this.testCase.actualResult;
this.$post('/test/plan/case/edit', param, () => {
this.$request(option, (response) => {
@ -327,8 +330,26 @@ export default {
item.issues = {};
}
item.steps = JSON.parse(item.steps);
//
compatibleTestCaseStep(item, item);
if (!item.stepModel) {
item.stepModel = 'STEP';
}
item.steptResults = [];
if (item.steps) {
for (let i = 0; i < item.steps.length; i++) {
if (item.results) {
if (item.results[i]) {
item.steps[i].actualResult = item.results[i].actualResult;
item.steps[i].executeResult = item.results[i].executeResult;
}
item.steptResults.push(item.steps[i]);
} else {
item.steptResults.push({
actualResult: '',
executeResult: ''
});
}
}
}
this.testCase = item;
parseCustomField(this.testCase, this.testCaseTemplate, null, null, buildTestCaseOldFields(this.testCase));
if (!this.testCase.actualResult) {
@ -427,6 +448,7 @@ export default {
.status-button {
padding-left: 4%;
padding-right: 4%;
}
.head-right {

View File

@ -0,0 +1,90 @@
<template>
<el-form-item class="result-item" :label-width="labelWidth">
<el-table
:data="testCase.steptResults"
class="tb-edit"
size="mini"
:border="true"
:default-sort="{prop: 'num', order: 'ascending'}"
highlight-current-row>
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="5%"></el-table-column>
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="21%">
<template v-slot:default="scope">
<el-input
size="mini"
class="border-hidden"
type="textarea"
:autosize="{ minRows: 1, maxRows: 4}"
:disabled="true"
v-model="scope.row.desc"/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="21%">
<template v-slot:default="scope">
<el-input
size="mini"
class="border-hidden"
type="textarea"
:autosize="{ minRows: 1, maxRows: 4}"
:disabled="true"
v-model="scope.row.result"/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.plan_view.actual_result')" min-width="21%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:rows="2"
:disabled="isReadOnly"
v-model="scope.row.actualResult"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.plan_view.step_result')" min-width="12%">
<template v-slot:default="scope">
<el-select
:disabled="isReadOnly"
v-model="scope.row.executeResult"
@change="stepResultChange()"
filterable
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-form-item>
</template>
<script>
export default {
name: "TestPlanCaseStepResultsItem",
props: ['testCase', 'isReadOnly', 'labelWidth'],
methods: {
stepResultChange() {
if (this.testCase.method === 'manual' || !this.testCase.method) {
this.isFailure = this.testCase.steptResults.filter(s => {
return s.executeResult === 'Failure' || s.executeResult === 'Blocking';
}).length > 0;
} else {
this.isFailure = false;
}
},
}
}
</script>
<style scoped>
</style>

View File

@ -62,211 +62,44 @@
</el-header>
<div class="case_container">
<!-- <el-row>
<el-col :span="9" :offset="1">
<span class="cast_label">{{ $t('test_track.case.priority') }}</span>
<span class="cast_item">{{ testCase.priority }}</span>
</el-col>
<el-col :span="10" :offset="1">
<span class="cast_label">{{ $t('test_track.case.module') }}</span>
<span class="cast_item">{{ testCase.nodePath }}</span>
</el-col>
</el-row>
<el-row>
<el-col :offset="1">
<span class="cast_label">关联测试</span>
<span v-for="(item,index) in testCase.list" :key="index">
<el-button @click="openTest(item)" type="text" style="margin-left: 7px;">{{
item.testName
}}</el-button>
</span>
</el-col>
</el-row>
<el-row>
<el-col :offset="1">
<span class="cast_label">{{ $t('test_track.case.prerequisite') }}</span>
<span class="cast_item">{{ testCase.prerequisite }}</span>
</el-col>
</el-row>
&lt;!&ndash; <el-row>
<el-col class="test-detail" :span="20" :offset="1">
<el-tabs v-model="activeTab" type="border-card">
<el-tab-pane name="detail" :label="$t('test_track.plan_view.test_detail')">
<api-test-detail :is-read-only="true" v-if="testCase.type === 'api'"
:id="testCase.testId" ref="apiTestDetail"/>
<performance-test-detail v-if="testCase.type === 'performance'"
:is-read-only="true"
:id="testCase.testId"
ref="performanceTestDetail"/>
<api-case-item :type="mark" :api="api" :api-case="apiCase" v-if="testCase.type==='testcase'"
ref="apiCaseConfig"/>
<ms-edit-api-scenario :type="mark" v-if="testCase.type==='automation'" :currentScenario="currentScenario"
ref="autoScenarioConfig"></ms-edit-api-scenario>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>&ndash;&gt;
<el-row>
<el-col :span="20" :offset="1">
<div>
<span class="cast_label">{{ $t('test_track.case.steps') }}</span>
</div>
<el-table
:data="testCase.steptResults"
class="tb-edit"
size="mini"
:border="true"
:default-sort="{prop: 'num', order: 'ascending'}"
highlight-current-row>
<el-table-column :label="$t('test_track.case.number')" prop="num"
min-width="5%"/>
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="21%">
<template v-slot:default="scope">
<el-input
size="mini"
class="border-hidden"
type="textarea"
:autosize="{ minRows: 1, maxRows: 4}"
:disabled="true"
v-model="scope.row.desc"/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="21%">
<template v-slot:default="scope">
<el-input
size="mini"
class="border-hidden"
type="textarea"
:autosize="{ minRows: 1, maxRows: 4}"
:disabled="true"
v-model="scope.row.result"/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.plan_view.actual_result')" min-width="21%">
<template v-slot:default="scope">
<el-input
class="table-edit-input"
size="mini"
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:rows="2"
:disabled="true"
v-model="scope.row.actualResult"
:placeholder="$t('commons.input_content')"
clearable/>
</template>
</el-table-column>
<el-table-column :label="$t('test_track.plan_view.step_result')" min-width="12%">
<template v-slot:default="scope">
<el-select
:disabled="true"
v-model="scope.row.executeResult"
@change="stepResultChange()"
size="mini">
<el-option :label="$t('test_track.plan_view.pass')" value="Pass"
style="color: #7ebf50;"/>
<el-option :label="$t('test_track.plan_view.failure')" value="Failure"
style="color: #e57471;"/>
<el-option :label="$t('test_track.plan_view.blocking')" value="Blocking"
style="color: #dda451;"/>
<el-option :label="$t('test_track.plan_view.skip')" value="Skip"
style="color: #919399;"/>
</el-select>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-row>
<el-col :span="15" :offset="1">
<div>
<span class="cast_label">{{ $t('commons.remark') }}</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"/>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="20" :offset="1">
<div>
<span class="cast_label">{{ $t('test_track.case.attachment') }}:</span>
</div>
<div>
<test-case-attachment :table-data="tableData"
:read-only="false"
:is-delete="false"
/>
</div>
</el-col>
</el-row>-->
<el-form>
<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 :span="7">
<el-form-item :label="$t('test_track.case.module')" prop="nodePath" :label-width="formLabelWidth">
{{testCase.nodePath}}
</el-form-item >
</el-col>
<el-col :span="5">
<span class="cast_label">{{ $t('test_track.case.module') }}</span>
<span class="cast_item">{{ testCase.nodePath }}</span>
<el-col :span="7">
<el-form-item :label="$t('test_track.plan.plan_project')" prop="projectName" :label-width="formLabelWidth">
{{testCase.projectName}}
</el-form-item >
</el-col>
</el-row>
<el-row>
<el-col :span="4" :offset="1">
<span class="cast_label">{{ $t('test_track.plan.plan_project') }}</span>
<span class="cast_item">{{ testCase.projectName }}</span>
</el-col>
</el-row>
<el-form ref="customFieldForm"
class="case-form">
<el-row>
<el-col :span="7" v-for="(item, index) in testCaseTemplate.customFields" :key="index">
<el-form-item :label="item.system ? $t(systemNameMap[item.name]) : item.name" :prop="item.name"
:label-width="formLabelWidth">
<custom-filed-component :disabled="true" :data="item" :form="{}" prop="defaultValue"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row>
<el-col :span="4" :offset="1" v-if="testCase.testId == 'other'">
<span class="cast_label">{{ $t('test_track.case.test_name') }}</span>
<span class="cast_item">{{ testCase.otherTestName }}</span>
</el-col>
</el-row>
<form-rich-text-item :label-width="formLabelWidth" :disabled="true" :title="$t('test_track.case.prerequisite')"
:data="testCase" prop="prerequisite"/>
<step-change-item :label-width="formLabelWidth" :form="testCase"/>
<form-rich-text-item :label-width="formLabelWidth" :disabled="true" v-if="testCase.stepModel === 'TEXT'" :title="$t('test_track.case.step_desc')" :data="testCase" prop="stepDescription"/>
<form-rich-text-item :label-width="formLabelWidth" :disabled="true" v-if="testCase.stepModel === 'TEXT'" :title="$t('test_track.case.expected_results')" :data="testCase" prop="expectedResult"/>
<!-- <el-form ref="customFieldForm"
class="case-form">
<el-row>
<el-col :span="7" v-for="(item, index) in testCaseTemplate.customFields" :key="index">
<el-form-item :label="item.system ? $t(systemNameMap[item.name]) : item.name" :prop="item.name"
label-width="120px">
<custom-filed-component :disabled="true" :data="item" :form="{}" prop="defaultValue"/>
</el-form-item>
</el-col>
</el-row>
</el-form>-->
<test-case-step-item :label-width="formLabelWidth" :read-only="true" v-if="testCase.stepModel === 'STEP'" :form="testCase"/>
<el-row>
<el-col :span="22" :offset="1">
<div class="step-info">
<form-rich-text-item :disabled="true" :title="$t('test_track.case.prerequisite')"
:data="testCase" prop="prerequisite"/>
<form-rich-text-item :disabled="true" :title="$t('test_track.case.step_desc')"
:data="testCase" prop="stepDesc"/>
<form-rich-text-item :disabled="true" :title="$t('test_track.case.expected_results')"
:data="testCase" prop="stepResult"/>
<form-rich-text-item :title="$t('test_track.plan_view.actual_result')" :data="testCase"
prop="actualResult"/>
</div>
</el-col>
</el-row>
<test-case-edit-other-info @openTest="openTest" :read-only="true" :is-test-plan="true"
:project-id="projectId" :form="testCase" :case-id="testCase.caseId"
ref="otherInfo"/>
:project-id="projectId" :form="testCase" :case-id="testCase.caseId" ref="otherInfo"/>
</el-form>
</div>
@ -305,15 +138,19 @@ import ReviewComment from "../../commom/ReviewComment";
import TestCaseAttachment from "@/business/components/track/case/components/TestCaseAttachment";
import ApiCaseItem from "@/business/components/api/definition/components/case/ApiCaseItem";
import MsEditApiScenario from "@/business/components/api/automation/scenario/EditApiScenario";
import {buildTestCaseOldFields, compatibleTestCaseStep, getTemplate, parseCustomField} from "@/common/js/custom_field";
import {buildTestCaseOldFields, getTemplate, parseCustomField} from "@/common/js/custom_field";
import TestCaseEditOtherInfo from "@/business/components/track/case/components/TestCaseEditOtherInfo";
import {SYSTEM_FIELD_NAME_MAP} from "@/common/js/table-constants";
import FormRichTextItem from "@/business/components/track/case/components/FormRichTextItem";
import CustomFiledComponent from "@/business/components/settings/workspace/template/CustomFiledComponent";
import StepChangeItem from "@/business/components/track/case/components/StepChangeItem";
import TestCaseStepItem from "@/business/components/track/case/components/TestCaseStepItem";
export default {
name: "TestReviewTestCaseEdit",
components: {
TestCaseStepItem,
StepChangeItem,
CustomFiledComponent,
FormRichTextItem,
TestCaseEditOtherInfo,
@ -350,6 +187,7 @@ export default {
testCaseTemplate: {},
hasTapdId: false,
hasZentaoId: false,
formLabelWidth: '100px'
};
},
props: {
@ -460,10 +298,11 @@ export default {
item.issues = {};
}
item.steps = JSON.parse(item.steps);
//
compatibleTestCaseStep(item, item);
if (!item.stepModel) {
item.stepModel = 'STEP';
}
parseCustomField(item, this.testCaseTemplate, null, null, buildTestCaseOldFields(item));
this.testCase = item;
//parseCustomField(this.testCase, this.testCaseTemplate, null, null, buildTestCaseOldFields(this.testCase));
if (!this.testCase.actualResult) {
// ,使
this.testCase.actualResult = this.testCaseTemplate.actualResult;
@ -491,7 +330,6 @@ export default {
openTestCaseEdit(testCase) {
this.showDialog = true;
this.activeTab = 'detail';
this.initData(testCase);
this.getComments(testCase);
this.hasTapdId = false;
this.hasZentaoId = false;
@ -647,4 +485,9 @@ export default {
.tb-edit >>> *[disabled] {
opacity: 0.7;
}
.step-info {
padding-left: 40px;
padding-right: 15px;
}
</style>

View File

@ -25,6 +25,7 @@ export function parseCustomField(data, template, customFieldForm, rules, oldFiel
item.defaultValue = JSON.parse(item.defaultValue);
}
// 添加自定义字段必填校验
if (item.required) {
let msg = (item.system ? i18n.t(SYSTEM_FIELD_NAME_MAP[item.name]) : item.name) + i18n.t('commons.cannot_be_null');
if (rules) {
@ -89,40 +90,6 @@ export function getTemplate(baseUrl, vueObj) {
});
}
// 兼容旧版本的步骤
export function compatibleTestCaseStep(testCase, tmp) {
if(testCase.expectedResult !== null) { // 改成富文本后加入的新数据 或 经过兼容的旧数据
tmp.stepResult = testCase.expectedResult + '<br>';
} else { // 如果是旧数据
if(tmp.steps !== null) {
tmp.stepResult = '';
tmp.steps.forEach(item => {
tmp.stepResult += item.num + ': ' + item.result + '<br>';
});
}
}
if(testCase.stepDescription !== null) {
tmp.stepDesc = testCase.stepDescription + '<br>';
} else {
if(tmp.steps !== null) {
tmp.stepDesc = '';
tmp.steps.forEach(item => {
tmp.stepDesc += item.num + ': ' + item.desc + '<br>';
});
}
}
if(!testCase.actualResult) {
if(tmp.results) {
tmp.actualResult = '';
tmp.results.forEach(item => {
if (item.actualResult) {
tmp.actualResult += item.actualResult + '<br>';
}
});
}
}
}
// 兼容旧字段
export function buildTestCaseOldFields(testCase) {
let oldFields = new Map();