feat(UI 自动化): UI测试支持加入到测试计划中

--story=1007518 --user=张大海 【UI测试】支持加入到测试计划中 https://www.tapd.cn/55049933/s/1202992
This commit is contained in:
zhangdahai112 2022-07-17 23:53:53 +08:00 committed by zhangdahai112
parent 3928bde3c3
commit 8764b1493e
52 changed files with 4986 additions and 41 deletions

View File

@ -38,4 +38,7 @@ public class SchedulePlanScenarioExecuteRequest {
private String testPlanReportId;
private RunModeConfigDTO config;
//场景的类型 api/ui
private String type;
}

View File

@ -260,7 +260,7 @@ public class ApiScenarioExecuteService {
/**
* 测试计划接口场景的预执行生成场景报告
*/
private void assemblyPlanScenario(List<ApiScenarioWithBLOBs> apiScenarios, RunScenarioRequest request, Map<String, RunModeDataDTO> executeQueue, List<String> scenarioIds, StringBuilder scenarioNames) {
private void assemblyPlanScenario(List<ApiScenarioWithBLOBs> apiScenarios, RunScenarioRequest request, Map<String, RunModeDataDTO> executeQueue, List<String> scenarioIds, StringBuilder scenarioNames) {
String reportId = request.getId();
Map<String, String> planScenarioIdMap = request.getScenarioTestPlanIdMap();
if (MapUtils.isEmpty(planScenarioIdMap)) {

View File

@ -88,9 +88,10 @@ public class ApiScenarioReportService {
private UiReportServiceProxy uiReportServiceProxy;
@Resource
private ExtApiScenarioReportResultMapper extApiScenarioReportResultMapper;
@Resource
private ScenarioExecutionInfoService scenarioExecutionInfoService;
@Resource
private TestPlanUiScenarioMapper testPlanUiScenarioMapper;
public void saveResult(ResultDTO dto) {
// 报告详情内容
@ -524,6 +525,21 @@ public class ApiScenarioReportService {
uiScenarioMapper.updateByPrimaryKey(scenario);
}
TestPlanUiScenario testPlanUiScenario = testPlanUiScenarioMapper.selectByPrimaryKey(dto.getTestId());
if (testPlanUiScenario != null) {
report.setScenarioId(testPlanUiScenario.getUiScenarioId());
report.setEndTime(System.currentTimeMillis());
testPlanUiScenario.setLastResult(report.getStatus());
long successSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Success.name())).count();
String passRate = new DecimalFormat("0%").format((float) successSize / requestResults.size());
testPlanUiScenario.setPassRate(passRate);
testPlanUiScenario.setReportId(report.getId());
report.setEndTime(System.currentTimeMillis());
testPlanUiScenario.setUpdateTime(System.currentTimeMillis());
testPlanUiScenarioMapper.updateByPrimaryKeySelective(testPlanUiScenario);
}
// // 发送通知
// if (scenario != null && report != null) {
// sendNotice(scenario, report);

View File

@ -0,0 +1,31 @@
package io.metersphere.api.service;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.dto.RunUiScenarioRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.lang.reflect.Method;
import java.util.function.Function;
@Service
@Transactional(rollbackFor = Exception.class)
public class UiAutomationServiceProxy {
public Object run(RunScenarioRequest request) {
return invoke((clazz) -> {
try {
return clazz.getDeclaredMethod("run", RunUiScenarioRequest.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}, request);
}
private Object invoke(Function<Class, Method> getDeclaredMethod, Object... args) {
return CommonBeanFactory.invoke("uiAutomationService", getDeclaredMethod, args);
}
}

View File

@ -51,6 +51,10 @@ public class TestPlanReportContentWithBLOBs extends TestPlanReportContent implem
private String unExecuteScenarios;
private String planUiScenarioReportStruct;
private String uiResult;
private String apiBaseCount;
private static final long serialVersionUID = 1L;

View File

@ -0,0 +1,37 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class TestPlanUiScenario implements Serializable {
private String id;
private String testPlanId;
private String uiScenarioId;
private String status;
private Long createTime;
private Long updateTime;
private String passRate;
private String lastResult;
private String reportId;
private String createUser;
private Long order;
private String environmentType;
private String environmentGroupId;
private String environment;
private static final long serialVersionUID = 1L;
}

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,8 @@
<result column="error_report_scenarios" jdbcType="LONGVARCHAR" property="errorReportScenarios" />
<result column="un_execute_cases" jdbcType="LONGVARCHAR" property="unExecuteCases" />
<result column="un_execute_scenarios" jdbcType="LONGVARCHAR" property="unExecuteScenarios" />
<result column="plan_ui_scenario_report_struct" jdbcType="LONGVARCHAR" property="planUiScenarioReportStruct" />
<result column="ui_result" jdbcType="LONGVARCHAR" property="uiResult" />
<result column="api_base_count" jdbcType="LONGVARCHAR" property="apiBaseCount" />
</resultMap>
<sql id="Example_Where_Clause">
@ -102,7 +104,7 @@
issue_list, api_all_cases, api_failure_cases, scenario_all_cases, scenario_failure_cases,
load_all_Cases, load_failure_cases, plan_scenario_report_struct, plan_api_case_report_struct,
plan_load_case_report_struct, error_report_cases, error_report_scenarios, un_execute_cases,
un_execute_scenarios, api_base_count
un_execute_scenarios, plan_ui_scenario_report_struct, ui_result, api_base_count
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanReportContentExample" resultMap="ResultMapWithBLOBs">
select
@ -164,8 +166,8 @@
plan_scenario_report_struct, plan_api_case_report_struct,
plan_load_case_report_struct, error_report_cases,
error_report_scenarios, un_execute_cases,
un_execute_scenarios, api_base_count
)
un_execute_scenarios, plan_ui_scenario_report_struct,
ui_result, api_base_count)
values (#{id,jdbcType=VARCHAR}, #{testPlanReportId,jdbcType=VARCHAR}, #{startTime,jdbcType=BIGINT},
#{caseCount,jdbcType=BIGINT}, #{endTime,jdbcType=BIGINT}, #{executeRate,jdbcType=DOUBLE},
#{passRate,jdbcType=DOUBLE}, #{isThirdPartIssue,jdbcType=BIT}, #{config,jdbcType=LONGVARCHAR},
@ -177,8 +179,8 @@
#{planScenarioReportStruct,jdbcType=LONGVARCHAR}, #{planApiCaseReportStruct,jdbcType=LONGVARCHAR},
#{planLoadCaseReportStruct,jdbcType=LONGVARCHAR}, #{errorReportCases,jdbcType=LONGVARCHAR},
#{errorReportScenarios,jdbcType=LONGVARCHAR}, #{unExecuteCases,jdbcType=LONGVARCHAR},
#{unExecuteScenarios,jdbcType=LONGVARCHAR}, #{apiBaseCount,jdbcType=LONGVARCHAR}
)
#{unExecuteScenarios,jdbcType=LONGVARCHAR}, #{planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
#{uiResult,jdbcType=LONGVARCHAR}, #{apiBaseCount,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanReportContentWithBLOBs">
insert into test_plan_report_content
@ -270,6 +272,12 @@
<if test="unExecuteScenarios != null">
un_execute_scenarios,
</if>
<if test="planUiScenarioReportStruct != null">
plan_ui_scenario_report_struct,
</if>
<if test="uiResult != null">
ui_result,
</if>
<if test="apiBaseCount != null">
api_base_count,
</if>
@ -362,6 +370,12 @@
<if test="unExecuteScenarios != null">
#{unExecuteScenarios,jdbcType=LONGVARCHAR},
</if>
<if test="planUiScenarioReportStruct != null">
#{planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
</if>
<if test="uiResult != null">
#{uiResult,jdbcType=LONGVARCHAR},
</if>
<if test="apiBaseCount != null">
#{apiBaseCount,jdbcType=LONGVARCHAR},
</if>
@ -463,6 +477,12 @@
<if test="record.unExecuteScenarios != null">
un_execute_scenarios = #{record.unExecuteScenarios,jdbcType=LONGVARCHAR},
</if>
<if test="record.planUiScenarioReportStruct != null">
plan_ui_scenario_report_struct = #{record.planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
</if>
<if test="record.uiResult != null">
ui_result = #{record.uiResult,jdbcType=LONGVARCHAR},
</if>
<if test="record.apiBaseCount != null">
api_base_count = #{record.apiBaseCount,jdbcType=LONGVARCHAR},
</if>
@ -502,6 +522,8 @@
error_report_scenarios = #{record.errorReportScenarios,jdbcType=LONGVARCHAR},
un_execute_cases = #{record.unExecuteCases,jdbcType=LONGVARCHAR},
un_execute_scenarios = #{record.unExecuteScenarios,jdbcType=LONGVARCHAR},
plan_ui_scenario_report_struct = #{record.planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
ui_result = #{record.uiResult,jdbcType=LONGVARCHAR},
api_base_count = #{record.apiBaseCount,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -608,6 +630,12 @@
<if test="unExecuteScenarios != null">
un_execute_scenarios = #{unExecuteScenarios,jdbcType=LONGVARCHAR},
</if>
<if test="planUiScenarioReportStruct != null">
plan_ui_scenario_report_struct = #{planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
</if>
<if test="uiResult != null">
ui_result = #{uiResult,jdbcType=LONGVARCHAR},
</if>
<if test="apiBaseCount != null">
api_base_count = #{apiBaseCount,jdbcType=LONGVARCHAR},
</if>
@ -644,6 +672,8 @@
error_report_scenarios = #{errorReportScenarios,jdbcType=LONGVARCHAR},
un_execute_cases = #{unExecuteCases,jdbcType=LONGVARCHAR},
un_execute_scenarios = #{unExecuteScenarios,jdbcType=LONGVARCHAR},
plan_ui_scenario_report_struct = #{planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
ui_result = #{uiResult,jdbcType=LONGVARCHAR},
api_base_count = #{apiBaseCount,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>

View File

@ -0,0 +1,36 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.TestPlanUiScenario;
import io.metersphere.base.domain.TestPlanUiScenarioExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestPlanUiScenarioMapper {
long countByExample(TestPlanUiScenarioExample example);
int deleteByExample(TestPlanUiScenarioExample example);
int deleteByPrimaryKey(String id);
int insert(TestPlanUiScenario record);
int insertSelective(TestPlanUiScenario record);
List<TestPlanUiScenario> selectByExampleWithBLOBs(TestPlanUiScenarioExample example);
List<TestPlanUiScenario> selectByExample(TestPlanUiScenarioExample example);
TestPlanUiScenario selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") TestPlanUiScenario record, @Param("example") TestPlanUiScenarioExample example);
int updateByExampleWithBLOBs(@Param("record") TestPlanUiScenario record, @Param("example") TestPlanUiScenarioExample example);
int updateByExample(@Param("record") TestPlanUiScenario record, @Param("example") TestPlanUiScenarioExample example);
int updateByPrimaryKeySelective(TestPlanUiScenario record);
int updateByPrimaryKeyWithBLOBs(TestPlanUiScenario record);
int updateByPrimaryKey(TestPlanUiScenario record);
}

View File

@ -0,0 +1,411 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.TestPlanUiScenarioMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestPlanUiScenario">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
<result column="ui_scenario_id" jdbcType="VARCHAR" property="uiScenarioId" />
<result column="status" jdbcType="VARCHAR" property="status" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="pass_rate" jdbcType="VARCHAR" property="passRate" />
<result column="last_result" jdbcType="VARCHAR" property="lastResult" />
<result column="report_id" jdbcType="VARCHAR" property="reportId" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="order" jdbcType="BIGINT" property="order" />
<result column="environment_type" jdbcType="VARCHAR" property="environmentType" />
<result column="environment_group_id" jdbcType="VARCHAR" property="environmentGroupId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestPlanUiScenario">
<result column="environment" jdbcType="LONGVARCHAR" property="environment" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, test_plan_id, ui_scenario_id, `status`, create_time, update_time, pass_rate,
last_result, report_id, create_user, `order`, environment_type, environment_group_id
</sql>
<sql id="Blob_Column_List">
environment
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanUiScenarioExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from test_plan_ui_scenario
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestPlanUiScenarioExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_plan_ui_scenario
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from test_plan_ui_scenario
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from test_plan_ui_scenario
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.TestPlanUiScenarioExample">
delete from test_plan_ui_scenario
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanUiScenario">
insert into test_plan_ui_scenario (id, test_plan_id, ui_scenario_id,
`status`, create_time, update_time,
pass_rate, last_result, report_id,
create_user, `order`, environment_type,
environment_group_id, environment)
values (#{id,jdbcType=VARCHAR}, #{testPlanId,jdbcType=VARCHAR}, #{uiScenarioId,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{createUser,jdbcType=VARCHAR}, #{order,jdbcType=BIGINT}, #{environmentType,jdbcType=VARCHAR},
#{environmentGroupId,jdbcType=VARCHAR}, #{environment,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanUiScenario">
insert into test_plan_ui_scenario
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="testPlanId != null">
test_plan_id,
</if>
<if test="uiScenarioId != null">
ui_scenario_id,
</if>
<if test="status != null">
`status`,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="passRate != null">
pass_rate,
</if>
<if test="lastResult != null">
last_result,
</if>
<if test="reportId != null">
report_id,
</if>
<if test="createUser != null">
create_user,
</if>
<if test="order != null">
`order`,
</if>
<if test="environmentType != null">
environment_type,
</if>
<if test="environmentGroupId != null">
environment_group_id,
</if>
<if test="environment != null">
environment,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="testPlanId != null">
#{testPlanId,jdbcType=VARCHAR},
</if>
<if test="uiScenarioId != null">
#{uiScenarioId,jdbcType=VARCHAR},
</if>
<if test="status != null">
#{status,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="passRate != null">
#{passRate,jdbcType=VARCHAR},
</if>
<if test="lastResult != null">
#{lastResult,jdbcType=VARCHAR},
</if>
<if test="reportId != null">
#{reportId,jdbcType=VARCHAR},
</if>
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
<if test="order != null">
#{order,jdbcType=BIGINT},
</if>
<if test="environmentType != null">
#{environmentType,jdbcType=VARCHAR},
</if>
<if test="environmentGroupId != null">
#{environmentGroupId,jdbcType=VARCHAR},
</if>
<if test="environment != null">
#{environment,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanUiScenarioExample" resultType="java.lang.Long">
select count(*) from test_plan_ui_scenario
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_plan_ui_scenario
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.testPlanId != null">
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
</if>
<if test="record.uiScenarioId != null">
ui_scenario_id = #{record.uiScenarioId,jdbcType=VARCHAR},
</if>
<if test="record.status != null">
`status` = #{record.status,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.passRate != null">
pass_rate = #{record.passRate,jdbcType=VARCHAR},
</if>
<if test="record.lastResult != null">
last_result = #{record.lastResult,jdbcType=VARCHAR},
</if>
<if test="record.reportId != null">
report_id = #{record.reportId,jdbcType=VARCHAR},
</if>
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
<if test="record.order != null">
`order` = #{record.order,jdbcType=BIGINT},
</if>
<if test="record.environmentType != null">
environment_type = #{record.environmentType,jdbcType=VARCHAR},
</if>
<if test="record.environmentGroupId != null">
environment_group_id = #{record.environmentGroupId,jdbcType=VARCHAR},
</if>
<if test="record.environment != null">
environment = #{record.environment,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update test_plan_ui_scenario
set id = #{record.id,jdbcType=VARCHAR},
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
ui_scenario_id = #{record.uiScenarioId,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pass_rate = #{record.passRate,jdbcType=VARCHAR},
last_result = #{record.lastResult,jdbcType=VARCHAR},
report_id = #{record.reportId,jdbcType=VARCHAR},
create_user = #{record.createUser,jdbcType=VARCHAR},
`order` = #{record.order,jdbcType=BIGINT},
environment_type = #{record.environmentType,jdbcType=VARCHAR},
environment_group_id = #{record.environmentGroupId,jdbcType=VARCHAR},
environment = #{record.environment,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_ui_scenario
set id = #{record.id,jdbcType=VARCHAR},
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
ui_scenario_id = #{record.uiScenarioId,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pass_rate = #{record.passRate,jdbcType=VARCHAR},
last_result = #{record.lastResult,jdbcType=VARCHAR},
report_id = #{record.reportId,jdbcType=VARCHAR},
create_user = #{record.createUser,jdbcType=VARCHAR},
`order` = #{record.order,jdbcType=BIGINT},
environment_type = #{record.environmentType,jdbcType=VARCHAR},
environment_group_id = #{record.environmentGroupId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.TestPlanUiScenario">
update test_plan_ui_scenario
<set>
<if test="testPlanId != null">
test_plan_id = #{testPlanId,jdbcType=VARCHAR},
</if>
<if test="uiScenarioId != null">
ui_scenario_id = #{uiScenarioId,jdbcType=VARCHAR},
</if>
<if test="status != null">
`status` = #{status,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="passRate != null">
pass_rate = #{passRate,jdbcType=VARCHAR},
</if>
<if test="lastResult != null">
last_result = #{lastResult,jdbcType=VARCHAR},
</if>
<if test="reportId != null">
report_id = #{reportId,jdbcType=VARCHAR},
</if>
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
<if test="order != null">
`order` = #{order,jdbcType=BIGINT},
</if>
<if test="environmentType != null">
environment_type = #{environmentType,jdbcType=VARCHAR},
</if>
<if test="environmentGroupId != null">
environment_group_id = #{environmentGroupId,jdbcType=VARCHAR},
</if>
<if test="environment != null">
environment = #{environment,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanUiScenario">
update test_plan_ui_scenario
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},
ui_scenario_id = #{uiScenarioId,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pass_rate = #{passRate,jdbcType=VARCHAR},
last_result = #{lastResult,jdbcType=VARCHAR},
report_id = #{reportId,jdbcType=VARCHAR},
create_user = #{createUser,jdbcType=VARCHAR},
`order` = #{order,jdbcType=BIGINT},
environment_type = #{environmentType,jdbcType=VARCHAR},
environment_group_id = #{environmentGroupId,jdbcType=VARCHAR},
environment = #{environment,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlanUiScenario">
update test_plan_ui_scenario
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},
ui_scenario_id = #{uiScenarioId,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pass_rate = #{passRate,jdbcType=VARCHAR},
last_result = #{lastResult,jdbcType=VARCHAR},
report_id = #{reportId,jdbcType=VARCHAR},
create_user = #{createUser,jdbcType=VARCHAR},
`order` = #{order,jdbcType=BIGINT},
environment_type = #{environmentType,jdbcType=VARCHAR},
environment_group_id = #{environmentGroupId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -50,4 +50,7 @@ public interface ExtTestPlanMapper {
@MapKey("id")
Map<String, ParamsDTO> testPlanLoadCaseCount(@Param("planIds")Set<String> planIds);
@MapKey("id")
Map<String, ParamsDTO> testPlanUiScenarioCount(@Param("planIds")Set<String> planIds);
}

View File

@ -395,6 +395,20 @@
</where>
GROUP BY t.test_plan_id
</select>
<select id="testPlanUiScenarioCount" resultType="io.metersphere.api.dto.definition.ParamsDTO">
select t.test_plan_id as id , COUNT(*) as value from test_plan_ui_scenario t
inner join ui_scenario c on t.ui_scenario_id = c.id
<where>
(c.status != 'Trash' or c.status is null)
<if test="planIds != null and planIds.size() > 0">
and t.test_plan_id IN
<foreach collection="planIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
</where>
GROUP BY t.test_plan_id
</select>
<select id="testPlanLoadCaseCount" resultType="io.metersphere.api.dto.definition.ParamsDTO">
select t.test_plan_id as id,COUNT(*) as value from test_plan_load_case t
<where>

View File

@ -0,0 +1,47 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.api.dto.automation.TestPlanScenarioRequest;
import io.metersphere.base.domain.TestPlanUiScenario;
import io.metersphere.dto.TestPlanFailureUiScenarioDTO;
import io.metersphere.dto.UiScenarioDTO;
import io.metersphere.track.dto.PlanReportCaseDTO;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
public interface ExtTestPlanUiScenarioCaseMapper {
void insertIfNotExists(@Param("request") TestPlanUiScenario request);
List<UiScenarioDTO> list(@Param("request") TestPlanScenarioRequest request);
List<String> getExecResultByPlanId(String planId);
List<String> getIdsByPlanId(String planId);
List<String> getNotRelevanceCaseIds(String planId, List<String> relevanceProjectIds);
List<String> selectIds(@Param("request")TestPlanScenarioRequest request);
List<TestPlanUiScenario> selectByIds(@Param("ids")String ids ,@Param("oderId")String oderId );
List<TestPlanUiScenario> selectLegalDataByTestPlanId(String planId);
List<PlanReportCaseDTO> selectForPlanReport(String planId);
List<TestPlanFailureUiScenarioDTO> getFailureList(@Param("planId") String planId, @Param("status") String status);
List<TestPlanFailureUiScenarioDTO> getFailureListByIds(@Param("ids") Collection<String> ids,@Param("status") String status);
List<Integer> getUnderwaySteps(@Param("ids") List<String> underwayIds);
String getProjectIdById(String testPlanScenarioId);
List<String> selectPlanIds();
List<String> getIdsOrderByUpdateTime(@Param("planId") String planId);
Long getPreOrder(@Param("planId")String planId, @Param("baseOrder") Long baseOrder);
Long getLastOrder(@Param("planId")String planId, @Param("baseOrder") Long baseOrder);
}

View File

@ -0,0 +1,330 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestPlanUiScenarioCaseMapper">
<insert id="insertIfNotExists" parameterType="io.metersphere.base.domain.TestPlanUiScenario">
-- 查询没有数据再插入
INSERT INTO test_plan_ui_scenario(id, test_plan_id, ui_scenario_id, create_time, update_time, environment, `order`, environment_group_id, environment_type)
SELECT #{request.id}, #{request.testPlanId}, #{request.uiScenarioId}, #{request.createTime}, #{request.updateTime}, #{request.environment}, #{request.order}, #{request.environmentGroupId}, #{request.environmentType}
FROM DUAL
WHERE NOT EXISTS(
SELECT id FROM
test_plan_ui_scenario
WHERE test_plan_id = #{request.testPlanId} and ui_scenario_id = #{request.uiScenarioId}
)
</insert>
<select id="selectLegalDataByTestPlanId" resultType="io.metersphere.base.domain.TestPlanUiScenario">
SELECT t.* FROM test_plan_ui_scenario t WHERE t.test_plan_id = #{0}
AND t.ui_scenario_id IN (
SELECT id FROM ui_scenario WHERE status IS NULL OR status != 'Trash'
)
ORDER BY `order` DESC
</select>
<select id="list" resultType="io.metersphere.dto.UiScenarioDTO">
SELECT
t.id,
t.environment,
t.create_time,
t.update_time,
t.last_result,
t.pass_rate,
t.report_id,
c.scenario_definition,
c.id AS case_id,
c.user_id,
c.module_id,
c.module_path,
c. NAME,
c. LEVEL,
c. STATUS,
c.principal,
c.step_total,
c. SCHEDULE,
c.description,
c.tags,
c.create_user,
c.project_id,
c.num,
c.custom_num,
t.environment_group_id,
t.environment_type,
project_version. NAME versionName,
project_version.id versionId
FROM
test_plan_ui_scenario t
INNER JOIN ui_scenario c ON t.ui_scenario_id = c.id
INNER JOIN project_version ON c.project_id = project_version.project_id
AND c.version_id = project_version.id
AND c. STATUS != 'Trash'
<if test="request.planId != null and request.planId!=''">
and t.test_plan_id = #{request.planId}
</if>
WHERE 1
<include refid="queryVersionCondition">
<property name="versionTable" value="c"/>
</include>
<if test="request.scenarioIds != null and request.scenarioIds.size() > 0">
and c.id in
<foreach collection="request.scenarioIds" item="caseId" separator="," open="(" close=")">
#{caseId}
</foreach>
</if>
<if test="request.ids != null and request.ids.size() > 0">
<if test="request.projectId != null and request.projectId!=''">
and c.project_id = #{request.projectId}
</if>
and t.id in
<foreach collection="request.ids" item="caseId" separator="," open="(" close=")">
#{caseId}
</foreach>
</if>
<if test="request.name != null and request.name!=''">
and (c.name like CONCAT('%', #{request.name},'%')
or c.num like CONCAT('%', #{request.name},'%')
or c.custom_num like CONCAT('%', #{request.name},'%')
or c.tags like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.status != null and request.status!=''">
and t.last_result like CONCAT('%', #{request.status},'%')
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and c.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<include refid="filters"/>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
<choose>
<when test="order.name == 'update_time' or order.name == 'order'">
t.${order.name} ${order.type}
</when>
<otherwise>
${order.name} ${order.type}
</otherwise>
</choose>
</foreach>
</if>
</select>
<select id="selectByIds" resultType="io.metersphere.base.domain.TestPlanUiScenario">
select t.* from test_plan_ui_scenario t where t.id in (${ids}) ORDER BY FIND_IN_SET(t.id,${oderId})
</select>
<select id="selectIds" resultType="java.lang.String">
select
t.id
from
test_plan_ui_scenario t
inner join
ui_scenario c
on t.ui_scenario_id = c.id and c.status != 'Trash'
<if test="request.planId != null and request.planId!=''">
and t.test_plan_id = #{request.planId}
</if>
left join project p
on c.project_id = p.id
left join user u
on c.user_id = u.id
where 1
<if test="request.ids != null and request.ids.size() > 0">
<if test="request.projectId != null and request.projectId!=''">
and
</if>
t.id in
<foreach collection="request.ids" item="caseId" separator="," open="(" close=")">
#{caseId}
</foreach>
</if>
<if test="request.name != null and request.name!=''">
and (c.name like CONCAT('%', #{request.name},'%')
or c.num like CONCAT('%', #{request.name},'%')
or c.tags like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.status != null and request.status!=''">
and t.last_result like CONCAT('%', #{request.status},'%')
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and c.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<include refid="filters"/>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
<choose>
<when test="order.name == 'update_time' or order.name == 'order'">
t.${order.name} ${order.type}
</when>
<otherwise>
${order.name} ${order.type}
</otherwise>
</choose>
</foreach>
</if>
</select>
<sql id="filters">
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key == 'level'">
and c.level in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key == 'last_result'">
and c.last_result in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key == 'version_id'">
and c.version_id in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
<select id="getExecResultByPlanId" resultType="java.lang.String">
select last_result
from
test_plan_ui_scenario
where test_plan_id = #{planId}
AND ui_scenario_id in (SELECT id FROM ui_scenario WHERE (`status` is null or `status` != 'Trash'))
</select>
<select id="getIdsByPlanId" resultType="java.lang.String">
select id
from test_plan_ui_scenario
where test_plan_id = #{planId}
</select>
<select id="getNotRelevanceCaseIds" resultType="java.lang.String">
select t.id
from test_plan_ui_scenario t
inner join ui_scenario c
on c.id = t.ui_scenario_id
<if test="relevanceProjectIds != null and relevanceProjectIds.size() > 0">
and c.project_id not in
<foreach collection="relevanceProjectIds" item="projectId" separator="," open="(" close=")">
#{projectId}
</foreach>
</if>
where t.test_plan_id = #{planId}
</select>
<select id="selectForPlanReport" resultType="io.metersphere.track.dto.PlanReportCaseDTO">
select id,last_result as status, report_id, ui_scenario_id as caseId from test_plan_ui_scenario where test_plan_id = #{planId}
and ui_scenario_id IN (
SELECT id FROM ui_scenario where status is null or status != 'Trash'
)
</select>
<select id="getFailureList" resultType="io.metersphere.dto.TestPlanFailureUiScenarioDTO">
select
t.id, t.last_result, t.report_id, c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal,
c.status,c.step_total, c.step_total, c.project_id,
c.num, c.custom_num
from
test_plan_ui_scenario t
inner join
ui_scenario c
on t.ui_scenario_id = c.id and (c.status != 'Trash' or c.status is null)
and t.test_plan_id = #{planId}
<if test="status != null and status != 'Fail' and status != 'unExecute'">
and t.last_result = #{status}
</if>
<if test="status == 'unExecute'">
and (t.last_result in ('Stop','unExecute') or t.last_result IS NULL)
</if>
<if test="status == 'Fail'">
and t.last_result in ('Fail','Error')
</if>
where t.test_plan_id = #{planId}
ORDER BY t.order DESC
</select>
<select id="getFailureListByIds" resultType="io.metersphere.dto.TestPlanFailureUiScenarioDTO">
select
t.id, t.last_result, t.report_id, c.user_id, c.module_path, c.name, c.level,c.create_user,c.principal,
c.status,c.step_total, c.step_total, c.project_id,
c.num, c.custom_num
from
test_plan_ui_scenario t
inner join
ui_scenario c
on t.ui_scenario_id = c.id and c.status != 'Trash'
<if test="status != null">
and t.last_result = 'Fail'
</if>
<!-- ui场景执行完毕和 -->
where t.id IN
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
ORDER BY t.order DESC
</select>
<select id="getUnderwaySteps" resultType="java.lang.Integer">
select step_total from ui_scenario c
where c.id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
<select id="getProjectIdById" resultType="java.lang.String">
SELECT project_id FROM test_plan WHERE id in (
SELECT test_plan_id FROM test_plan_ui_scenario WHERE id = #{0}
)
</select>
<select id="selectPlanIds" resultType="java.lang.String">
select DISTINCT test_plan_id from test_plan_ui_scenario;
</select>
<select id="getIdsOrderByUpdateTime" resultType="java.lang.String">
select id from test_plan_ui_scenario where test_plan_id = #{planId} order by update_time ASC;
</select>
<select id="getLastOrder" resultType="java.lang.Long">
select `order` from test_plan_ui_scenario where test_plan_id = #{planId}
<if test="baseOrder != null">
and `order` &gt; #{baseOrder}
</if>
order by `order` desc limit 1;
</select>
<select id="getPreOrder" resultType="java.lang.Long">
select `order` from test_plan_ui_scenario where test_plan_id = #{planId}
<if test="baseOrder != null">
and `order` &lt; #{baseOrder}
</if>
order by `order` desc limit 1;
</select>
<sql id="queryVersionCondition">
<if test="request.versionId != null">
and ${versionTable}.version_id = #{request.versionId}
</if>
<if test="request.refId != null">
and ${versionTable}.ref_id = #{request.refId}
</if>
</sql>
</mapper>

View File

@ -0,0 +1,10 @@
package io.metersphere.dto;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.track.dto.UiRunModeConfigDTO;
import lombok.Data;
@Data
public class RunUiScenarioRequest extends RunScenarioRequest {
private UiRunModeConfigDTO uiConfig;
}

View File

@ -15,6 +15,7 @@ import java.util.Map;
public class TestPlanExecuteReportDTO {
private Map<String,String> testPlanApiCaseIdAndReportIdMap;
private Map<String,String> testPlanScenarioIdAndReportIdMap;
private Map<String,String> testPlanUiScenarioIdAndReportIdMap;
private Map<String,String> testPlanLoadCaseIdAndReportIdMap;
private Map<String,TestPlanFailureApiDTO> apiCaseInfoDTOMap;
private Map<String,TestPlanFailureScenarioDTO> scenarioInfoDTOMap;

View File

@ -0,0 +1,13 @@
package io.metersphere.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class TestPlanFailureUiScenarioDTO extends UiScenarioDTO {
private APIScenarioReportResult response;
}

View File

@ -0,0 +1,36 @@
package io.metersphere.dto;
import io.metersphere.base.domain.UiScenarioWithBLOBs;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class UiScenarioDTO extends UiScenarioWithBLOBs {
private String projectName;
private String userName;
private String creatorName;
private String principalName;
private List<String> tagNames;
private String deleteUser;
private String versionName;
private Boolean versionEnable;
/**
* 场景跨项目ID
*/
private List<String> projectIds;
private String caseId;
private String environment;
/**
* 场景列表 环境
*/
private String env;
private Map<String, String> environmentMap;
private String creator;
}

View File

@ -0,0 +1,33 @@
package io.metersphere.dto;
import io.metersphere.controller.request.BaseQueryRequest;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class UiScenarioRequest extends BaseQueryRequest {
private String id;
private String excludeId;
private String moduleId;
private String name;
private String userId;
private String planId;
private boolean recent = false;
private boolean isSelectThisWeedData;
private long createTime = 0;
private String executeStatus;
private boolean notInTestPlan;
private String reviewId;
private String versionId;
private String refId;
//操作人
private String operator;
//操作时间
private Long operationTime;
/**
* 是否需要查询环境字段
*/
private boolean selectEnvironment = false;
}

View File

@ -275,6 +275,17 @@ public class TestPlanController {
return testPlanService.haveExecCase(id);
}
/**
* 该测试计划是否包含ui场景
*
* @param id
* @return
*/
@GetMapping("/have/ui/case/{id}")
public boolean haveUiCase(@PathVariable String id) {
return testPlanService.haveUiCase(id);
}
@GetMapping("/principal/{planId}")
public List<User> getPlanPrincipal(@PathVariable String planId) {
return testPlanService.getPlanPrincipal(planId);

View File

@ -0,0 +1,120 @@
package io.metersphere.track.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.automation.RunTestPlanScenarioRequest;
import io.metersphere.api.dto.automation.TestPlanScenarioRequest;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.OperLogModule;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.dto.*;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.track.dto.RelevanceScenarioRequest;
import io.metersphere.track.request.testcase.TestPlanScenarioCaseBatchRequest;
import io.metersphere.track.service.TestPlanScenarioCaseService;
import io.metersphere.track.service.TestPlanUiScenarioCaseService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RequestMapping("/test/plan/uiScenario/case")
@RestController
public class TestPlanUiScenarioCaseController {
@Resource
TestPlanUiScenarioCaseService testPlanUiScenarioCaseService;
@PostMapping("/list/{goPage}/{pageSize}")
public Pager<List<UiScenarioDTO>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody TestPlanScenarioRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, testPlanUiScenarioCaseService.list(request));
}
@GetMapping("/list/failure/{planId}")
public List<TestPlanFailureUiScenarioDTO> getFailureList(@PathVariable String planId) {
return testPlanUiScenarioCaseService.getFailureCases(planId);
}
@GetMapping("/list/errorReport/{planId}")
public List<TestPlanFailureUiScenarioDTO> getErrorReportList(@PathVariable String planId) {
return testPlanUiScenarioCaseService.getErrorReportCases(planId);
}
@GetMapping("/list/unExecute/{planId}")
public List<TestPlanFailureUiScenarioDTO> getUnExecuteCases(@PathVariable String planId) {
return testPlanUiScenarioCaseService.getUnExecuteCases(planId);
}
@GetMapping("/list/all/{planId}")
public List<TestPlanFailureUiScenarioDTO> getAllList(@PathVariable String planId) {
return testPlanUiScenarioCaseService.getAllCases(planId);
}
@PostMapping("/selectAllTableRows")
public List<UiScenarioDTO> selectAllTableRows(@RequestBody TestPlanScenarioCaseBatchRequest request) {
return testPlanUiScenarioCaseService.selectAllTableRows(request);
}
@PostMapping("/relevance/list/{goPage}/{pageSize}")
public Pager<List<UiScenarioDTO>> relevanceList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody UiScenarioRequest request) {
return testPlanUiScenarioCaseService.relevanceList(request, goPage, pageSize);
}
@GetMapping("/delete/{id}")
@MsAuditLog(module = OperLogModule.TRACK_TEST_CASE_REVIEW, type = OperLogConstants.UN_ASSOCIATE_CASE, beforeEvent = "#msClass.getLogDetails(#id)", msClass = TestPlanScenarioCaseService.class)
public int deleteTestCase(@PathVariable String id) {
return testPlanUiScenarioCaseService.delete(id);
}
@PostMapping("/batch/delete")
@MsAuditLog(module = OperLogModule.TRACK_TEST_PLAN, type = OperLogConstants.UN_ASSOCIATE_CASE, beforeEvent = "#msClass.getLogDetails(#request.ids)", msClass = TestPlanScenarioCaseService.class)
public void deleteApiCaseBath(@RequestBody TestPlanScenarioCaseBatchRequest request) {
testPlanUiScenarioCaseService.deleteApiCaseBath(request);
}
@PostMapping(value = "/run")
@MsAuditLog(module = OperLogModule.TRACK_TEST_PLAN, type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.planCaseIds)", msClass = TestPlanScenarioCaseService.class)
public List<MsExecResponseDTO> run(@RequestBody RunTestPlanScenarioRequest request) {
request.setExecuteType(ExecuteType.Completed.name());
if(request.getConfig() == null){
RunModeConfigDTO config = new RunModeConfigDTO();
config.setMode(RunModeConstants.PARALLEL.toString());
config.setEnvMap(new HashMap<>());
request.setConfig(config);
}
return testPlanUiScenarioCaseService.run(request);
}
@PostMapping(value = "/jenkins/run")
@MsAuditLog(module = OperLogModule.TRACK_TEST_PLAN, type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.ids)", msClass = TestPlanScenarioCaseService.class)
public List<MsExecResponseDTO> runByRun(@RequestBody RunTestPlanScenarioRequest request) {
request.setExecuteType(ExecuteType.Saved.name());
request.setTriggerMode(ApiRunMode.API.name());
request.setRunMode(ApiRunMode.SCENARIO.name());
return testPlanUiScenarioCaseService.run(request);
}
@PostMapping("/batch/update/env")
@MsAuditLog(module = OperLogModule.TRACK_TEST_PLAN, type = OperLogConstants.BATCH_UPDATE, beforeEvent = "#msClass.batchLogDetails(#request.ids)", content = "#msClass.getLogDetails(#request.ids)", msClass = TestPlanScenarioCaseService.class)
public void batchUpdateEnv(@RequestBody RelevanceScenarioRequest request) {
testPlanUiScenarioCaseService.batchUpdateEnv(request);
}
@PostMapping("/env")
public Map<String, String> getScenarioCaseEnv(@RequestBody HashMap<String, String> map) {
return testPlanUiScenarioCaseService.getScenarioCaseEnv(map);
}
@PostMapping("/edit/order")
public void orderCase(@RequestBody ResetOrderRequest request) {
testPlanUiScenarioCaseService.updateOrder(request);
}
}

View File

@ -15,5 +15,6 @@ public class TestPlanDTOWithMetric extends TestPlanDTO {
private Integer testPlanTestCaseCount;
private Integer testPlanApiCaseCount;
private Integer testPlanApiScenarioCount;
private Integer testPlanUiScenarioCount;
private Integer testPlanLoadCaseCount;
}

View File

@ -17,4 +17,5 @@ public class TestPlanScheduleReportInfoDTO {
private Map<String, String> planScenarioIdMap;
private Map<String, String> apiTestCaseDataMap;
private Map<String, String> performanceIdMap;
private Map<String, String> uiScenarioIdMap;
}

View File

@ -39,6 +39,7 @@ public class TestPlanSimpleReportDTO extends TestPlanReportContent {
private TestPlanFunctionResultReportDTO functionResult;
private TestPlanApiResultReportDTO apiResult;
private TestPlanLoadResultReportDTO loadResult;
private TestPlanUiResultReportDTO uiResult;
List<TestPlanCaseDTO> functionAllCases;
List<IssuesDao> issueList;

View File

@ -0,0 +1,15 @@
package io.metersphere.track.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class TestPlanUiResultReportDTO {
private List<TestCaseReportStatusResultDTO> uiScenarioCaseData;
private List<TestCaseReportStatusResultDTO> uiScenarioData;
private List<TestCaseReportStatusResultDTO> uiScenarioStepData;
}

View File

@ -0,0 +1,8 @@
package io.metersphere.track.dto;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Data;
@Data
public class UiRunModeConfigDTO extends RunModeConfigDTO {
}

View File

@ -0,0 +1,46 @@
package io.metersphere.track.request.testcase;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class UiCaseRelevanceRequest {
/**
* 测试计划ID
*/
private String planId;
private String environmentId;
/**
* 当选择关联全部用例时把加载条件送到后台从后台查询
*/
// private QueryTestCaseRequest request;
/**
* 具体要关联的用例
*/
private List<String> selectIds = new ArrayList<>();
/**
* 项目环境对应关系
*/
private Map<String, String> envMap;
/**
* 用例的环境的对应关系
*/
private Map<String, List<String>> mapping;
/**
*测试评审ID
*/
private String reviewId;
private String environmentType;
private String envGroupId;
}

View File

@ -30,5 +30,9 @@ public class TestplanRunRequest {
// 失败重试
private boolean retryEnable;
private long retryNum;
//ui 测试
private String browser;
private boolean headlessEnabled;
}

View File

@ -16,6 +16,7 @@ import io.metersphere.commons.utils.*;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.dto.TestPlanExecuteReportDTO;
import io.metersphere.dto.TestPlanFailureUiScenarioDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.service.EnvironmentGroupProjectService;
@ -104,6 +105,8 @@ public class TestPlanReportService {
private ApiTestEnvironmentService apiTestEnvironmentService;
@Resource
private ProjectService projectService;
@Resource
ExtTestPlanUiScenarioCaseMapper extTestPlanUiScenarioCaseMapper;
public List<TestPlanReportDTO> list(QueryTestPlanReportRequest request) {
List<TestPlanReportDTO> list = new ArrayList<>();
@ -223,7 +226,7 @@ public class TestPlanReportService {
}
public TestPlanScheduleReportInfoDTO genTestPlanReportBySchedule(String planReportId, String planId, String userId, String triggerMode, RunModeConfigDTO runModeConfigDTO) {
TestPlanReport testPlanReport = this.getTestPlanReport(planReportId);
TestPlanReport testPlanReport = this.getTestPlanReport(planReportId);
TestPlanScheduleReportInfoDTO returnDTO = new TestPlanScheduleReportInfoDTO();
if (testPlanReport != null) {
returnDTO.setTestPlanReport(testPlanReport);
@ -232,6 +235,8 @@ public class TestPlanReportService {
Map<String, String> planScenarioIdMap = new LinkedHashMap<>();
Map<String, String> planTestCaseIdMap = new LinkedHashMap<>();
Map<String, String> performanceIdMap = new LinkedHashMap<>();
Map<String, String> uiScenarioIdMap = new LinkedHashMap<>();
List<TestPlanApiScenarioInfoDTO> testPlanApiScenarioList = extTestPlanScenarioCaseMapper.selectLegalDataByTestPlanId(planId);
for (TestPlanApiScenarioInfoDTO model : testPlanApiScenarioList) {
@ -251,6 +256,10 @@ public class TestPlanReportService {
for (TestPlanLoadCaseDTO dto : testPlanLoadCaseDTOList) {
performanceIdMap.put(dto.getId(), dto.getLoadCaseId());
}
List<TestPlanUiScenario> testPlanUiScenarioList = extTestPlanUiScenarioCaseMapper.selectLegalDataByTestPlanId(planId);
for (TestPlanUiScenario dto : testPlanUiScenarioList) {
uiScenarioIdMap.put(dto.getId(), dto.getUiScenarioId());
}
Map<String, String> apiCaseInfoMap = new HashMap<>();
for (String id : planTestCaseIdMap.keySet()) {
@ -275,6 +284,7 @@ public class TestPlanReportService {
returnDTO.setPlanScenarioIdMap(planScenarioIdMap);
returnDTO.setApiTestCaseDataMap(planTestCaseIdMap);
returnDTO.setPerformanceIdMap(performanceIdMap);
returnDTO.setUiScenarioIdMap(uiScenarioIdMap);
return returnDTO;
}
@ -647,6 +657,9 @@ public class TestPlanReportService {
if (reportDTO.getApiResult() != null) {
testPlanReportContentWithBLOBs.setApiResult(JSONObject.toJSONString(reportDTO.getApiResult()));
}
if (reportDTO.getUiResult() != null) {
testPlanReportContentWithBLOBs.setUiResult(JSONObject.toJSONString(reportDTO.getUiResult()));
}
if (reportDTO.getLoadResult() != null) {
testPlanReportContentWithBLOBs.setLoadResult(JSONObject.toJSONString(reportDTO.getLoadResult()));
}
@ -948,6 +961,9 @@ public class TestPlanReportService {
if (StringUtils.isNotBlank(testPlanReportContent.getUnExecuteScenarios())) {
testPlanReportDTO.setUnExecuteScenarios(JSONObject.parseArray(testPlanReportContent.getUnExecuteScenarios(), TestPlanFailureScenarioDTO.class));
}
if (StringUtils.isNotBlank(testPlanReportContent.getUiResult())) {
testPlanReportDTO.setUiResult(JSONObject.parseObject(testPlanReportContent.getUiResult(), TestPlanUiResultReportDTO.class));
}
testPlanReportDTO.setId(reportId);
TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(testPlanReportContent.getTestPlanReportId());
testPlanReportDTO.setName(testPlanReport.getName());
@ -1020,7 +1036,7 @@ public class TestPlanReportService {
private boolean isDynamicallyGenerateReports(TestPlanReportContentWithBLOBs testPlanReportContent) {
return testPlanReportContent != null &&
(StringUtils.isNotEmpty(testPlanReportContent.getPlanApiCaseReportStruct()) || StringUtils.isNotEmpty(testPlanReportContent.getPlanScenarioReportStruct()) || StringUtils.isNotEmpty(testPlanReportContent.getPlanLoadCaseReportStruct()));
(StringUtils.isNotEmpty(testPlanReportContent.getPlanApiCaseReportStruct()) || StringUtils.isNotEmpty(testPlanReportContent.getPlanScenarioReportStruct()) || StringUtils.isNotEmpty(testPlanReportContent.getPlanLoadCaseReportStruct()) || StringUtils.isNotEmpty(testPlanReportContent.getPlanUiScenarioReportStruct()));
}
private TestPlanReportContentWithBLOBs dynamicallyGenerateReports(TestPlanReportContentWithBLOBs testPlanReportContent) {
@ -1029,7 +1045,7 @@ public class TestPlanReportService {
return testPlanReportContent;
}
public void createTestPlanReportContentReportIds(String testPlanReportID, Map<String, String> apiCaseReportMap, Map<String, String> scenarioReportIdMap, Map<String, String> loadCaseReportIdMap) {
public void createTestPlanReportContentReportIds(String testPlanReportID, Map<String, String> apiCaseReportMap, Map<String, String> scenarioReportIdMap, Map<String, String> loadCaseReportIdMap, Map<String, String> uiScenarioReportMap) {
TestPlanReportContentWithBLOBs content = new TestPlanReportContentWithBLOBs();
content.setId(UUID.randomUUID().toString());
content.setTestPlanReportId(testPlanReportID);
@ -1052,12 +1068,21 @@ public class TestPlanReportService {
if (MapUtils.isNotEmpty(loadCaseReportIdMap)) {
content.setPlanLoadCaseReportStruct(JSONObject.toJSONString(loadCaseReportIdMap));
}
if (MapUtils.isNotEmpty(uiScenarioReportMap)) {
List<TestPlanFailureUiScenarioDTO> uiScenarios =
extTestPlanUiScenarioCaseMapper.getFailureListByIds(uiScenarioReportMap.keySet(), null);
for (TestPlanFailureUiScenarioDTO dto : uiScenarios) {
dto.setReportId(uiScenarioReportMap.get(dto.getId()));
}
content.setPlanUiScenarioReportStruct(JSONObject.toJSONString(uiScenarios));
}
testPlanReportContentMapper.insert(content);
}
public TestPlanExecuteReportDTO genTestPlanExecuteReportDTOByTestPlanReportContent(TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) {
Map<String, String> testPlanApiCaseIdAndReportIdMap = new LinkedHashMap<>();
Map<String, String> testPlanScenarioIdAndReportIdMap = new LinkedHashMap<>();
Map<String, String> testPlanUiScenarioIdAndReportIdMap = new LinkedHashMap<>();
Map<String, String> testPlanLoadCaseIdAndReportIdMap = new LinkedHashMap<>();
Map<String, TestPlanFailureApiDTO> apiCaseInfoDTOMap = new LinkedHashMap<>();
Map<String, TestPlanFailureScenarioDTO> scenarioInfoDTOMap = new LinkedHashMap<>();
@ -1099,6 +1124,24 @@ public class TestPlanReportService {
}
}
}
if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct())) {
List<TestPlanFailureScenarioDTO> scenarioInfoDTOList = null;
try {
scenarioInfoDTOList = JSONArray.parseArray(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct(), TestPlanFailureScenarioDTO.class);
} catch (Exception ignored) {
}
if (scenarioInfoDTOList == null) {
try {
testPlanUiScenarioIdAndReportIdMap = JSONObject.parseObject(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct(), Map.class);
} catch (Exception ignored) {
}
} else {
for (TestPlanFailureScenarioDTO item : scenarioInfoDTOList) {
testPlanUiScenarioIdAndReportIdMap.put(item.getId(), item.getReportId());
scenarioInfoDTOMap.put(item.getId(), item);
}
}
}
if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanLoadCaseReportStruct())) {
try {
testPlanLoadCaseIdAndReportIdMap = JSONObject.parseObject(testPlanReportContentWithBLOBs.getPlanLoadCaseReportStruct(), Map.class);
@ -1106,7 +1149,7 @@ public class TestPlanReportService {
}
}
}
TestPlanExecuteReportDTO returnDTO = new TestPlanExecuteReportDTO(testPlanApiCaseIdAndReportIdMap, testPlanScenarioIdAndReportIdMap, testPlanLoadCaseIdAndReportIdMap, apiCaseInfoDTOMap, scenarioInfoDTOMap);
TestPlanExecuteReportDTO returnDTO = new TestPlanExecuteReportDTO(testPlanApiCaseIdAndReportIdMap, testPlanScenarioIdAndReportIdMap, testPlanUiScenarioIdAndReportIdMap, testPlanLoadCaseIdAndReportIdMap, apiCaseInfoDTOMap, scenarioInfoDTOMap);
return returnDTO;
}

View File

@ -13,10 +13,7 @@ import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.dto.definition.ParamsDTO;
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.api.exec.perf.PerfExecService;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.api.service.*;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
@ -50,6 +47,7 @@ import io.metersphere.track.request.testplan.LoadCaseRequest;
import io.metersphere.track.request.testplan.TestplanRunRequest;
import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.utils.LoggerUtil;
import io.metersphere.dto.RunUiScenarioRequest;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
@ -124,6 +122,8 @@ public class TestPlanService {
@Resource
private TestPlanLoadCaseService testPlanLoadCaseService;
@Resource
private TestPlanUiScenarioCaseService testPlanUiScenarioCaseService;
@Resource
private ApiAutomationService apiAutomationService;
@Resource
private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
@ -184,6 +184,10 @@ public class TestPlanService {
private ExtApiDefinitionExecResultMapper extApiDefinitionExecResultMapper;
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private UiAutomationServiceProxy uiAutomationServiceProxy;
@Resource
private TestPlanUiScenarioMapper testPlanUiScenarioMapper;
public synchronized TestPlan addTestPlan(AddTestPlanRequest testPlan) {
if (getTestPlanByName(testPlan.getName()).size() > 0) {
@ -422,7 +426,17 @@ public class TestPlanService {
}
});
testPlan.setTotal(apiExecResults.size() + scenarioExecResults.size() + functionalExecTotal + loadResults.size());
List<String> uiScenarioExecResults = testPlanUiScenarioCaseService.getExecResultByPlanId(testPlan.getId());
uiScenarioExecResults.forEach(item -> {
if (StringUtils.isNotBlank(item)) {
testPlan.setTested(testPlan.getTested() + 1);
if (StringUtils.equals(item, "success")) {
testPlan.setPassed(testPlan.getPassed() + 1);
}
}
});
testPlan.setTotal(apiExecResults.size() + scenarioExecResults.size() + functionalExecTotal + loadResults.size() + uiScenarioExecResults.size());
testPlan.setPassRate(MathUtils.getPercentWithDecimal(testPlan.getTested() == 0 ? 0 : testPlan.getPassed() * 1.0 / testPlan.getTotal()));
testPlan.setTestRate(MathUtils.getPercentWithDecimal(testPlan.getTotal() == 0 ? 0 : testPlan.getTested() * 1.0 / testPlan.getTotal()));
@ -442,6 +456,7 @@ public class TestPlanService {
Map<String, ParamsDTO> planTestCaseCountMap = extTestPlanMapper.testPlanTestCaseCount(ids);
Map<String, ParamsDTO> planApiCaseMap = extTestPlanMapper.testPlanApiCaseCount(ids);
Map<String, ParamsDTO> planApiScenarioMap = extTestPlanMapper.testPlanApiScenarioCount(ids);
Map<String, ParamsDTO> planUiScenarioMap = extTestPlanMapper.testPlanUiScenarioCount(ids);
Map<String, ParamsDTO> planLoadCaseMap = extTestPlanMapper.testPlanLoadCaseCount(ids);
ArrayList<String> idList = new ArrayList<>(ids);
List<Schedule> scheduleByResourceIds = scheduleService.getScheduleByResourceIds(idList, ScheduleGroup.TEST_PLAN_TEST.name());
@ -465,6 +480,7 @@ public class TestPlanService {
item.setTestPlanTestCaseCount(planTestCaseCountMap.get(item.getId()) == null ? 0 : Integer.parseInt(planTestCaseCountMap.get(item.getId()).getValue() == null ? "0" : planTestCaseCountMap.get(item.getId()).getValue()));
item.setTestPlanApiCaseCount(planApiCaseMap.get(item.getId()) == null ? 0 : Integer.parseInt(planApiCaseMap.get(item.getId()).getValue() == null ? "0" : planApiCaseMap.get(item.getId()).getValue()));
item.setTestPlanApiScenarioCount(planApiScenarioMap.get(item.getId()) == null ? 0 : Integer.parseInt(planApiScenarioMap.get(item.getId()).getValue() == null ? "0" : planApiScenarioMap.get(item.getId()).getValue()));
item.setTestPlanUiScenarioCount(planUiScenarioMap.get(item.getId()) == null ? 0 : Integer.parseInt(planUiScenarioMap.get(item.getId()).getValue() == null ? "0" : planUiScenarioMap.get(item.getId()).getValue()));
item.setTestPlanLoadCaseCount(planLoadCaseMap.get(item.getId()) == null ? 0 : Integer.parseInt(planLoadCaseMap.get(item.getId()).getValue() == null ? "0" : planLoadCaseMap.get(item.getId()).getValue()));
});
calcTestPlanRate(testPlans);
@ -945,7 +961,16 @@ public class TestPlanService {
request.setProjectId(planScenarioExecuteRequest.getProjectId());
request.setRequestOriginator("TEST_PLAN");
request.setPlanCaseIds(new ArrayList<>(testPlanScenarioIdMap.keySet()));
list.addAll(apiAutomationService.run(request));
if ("api".equalsIgnoreCase(planScenarioExecuteRequest.getType())) {
list.addAll(apiAutomationService.run(request));
} else {
RunUiScenarioRequest runUiScenarioRequest = new RunUiScenarioRequest();
BeanUtils.copyBean(runUiScenarioRequest, request);
UiRunModeConfigDTO configDTO = new UiRunModeConfigDTO();
BeanUtils.copyBean(configDTO, Optional.ofNullable(request.getConfig()).orElse(new RunModeConfigDTO()));
runUiScenarioRequest.setUiConfig(configDTO);
list.addAll((Collection<? extends MsExecResponseDTO>) uiAutomationServiceProxy.run(runUiScenarioRequest));
}
}
return list;
}
@ -988,6 +1013,7 @@ public class TestPlanService {
Map<String, String> apiCaseReportMap = null;
Map<String, String> scenarioReportMap = null;
Map<String, String> loadCaseReportMap = null;
Map<String, String> uiScenarioReportMap = null;
if (reportInfoDTO.getApiTestCaseDataMap() != null) {
//执行接口案例任务
LoggerUtil.info("开始执行测试计划接口用例 " + planReportId);
@ -1004,9 +1030,15 @@ public class TestPlanService {
LoggerUtil.info("开始执行测试计划性能用例 " + planReportId);
loadCaseReportMap = perfExecService.run(planReportId, runModeConfig, triggerMode, reportInfoDTO.getPerformanceIdMap());
}
if (apiCaseReportMap != null && scenarioReportMap != null && loadCaseReportMap != null) {
if (reportInfoDTO.getUiScenarioIdMap() != null) {
//执行UI场景执行任务
LoggerUtil.info("开始执行测试计划 UI 场景用例 " + planReportId);
uiScenarioReportMap = this.executeUiScenarioCase(planReportId, testPlanID, projectID, runModeConfig, triggerMode, userId, reportInfoDTO.getUiScenarioIdMap());
}
if (apiCaseReportMap != null && scenarioReportMap != null && loadCaseReportMap != null && uiScenarioReportMap!= null) {
LoggerUtil.info("开始生成测试计划报告内容 " + planReportId);
testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiCaseReportMap, scenarioReportMap, loadCaseReportMap);
testPlanReportService.createTestPlanReportContentReportIds(planReportId, apiCaseReportMap, scenarioReportMap, loadCaseReportMap, uiScenarioReportMap);
}
return planReportId;
@ -1048,6 +1080,40 @@ public class TestPlanService {
scenarioRequest.setTestPlanID(testPlanID);
scenarioRequest.setTestPlanReportId(planReportId);
scenarioRequest.setConfig(runModeConfig);
scenarioRequest.setType("api");
List<MsExecResponseDTO> dtoList = this.scenarioRunModeConfig(scenarioRequest);
return this.parseMsExecREsponseDTOToTestIdReportMap(dtoList);
} else {
return new HashMap<>();
}
}
private Map<String, String> executeUiScenarioCase(String planReportId, String testPlanID, String projectID, RunModeConfigDTO runModeConfig, String triggerMode, String userId, Map<String, String> planScenarioIdMap) {
if (!planScenarioIdMap.isEmpty()) {
SchedulePlanScenarioExecuteRequest scenarioRequest = new SchedulePlanScenarioExecuteRequest();
String scenarioReportID = UUID.randomUUID().toString();
scenarioRequest.setId(scenarioReportID);
scenarioRequest.setReportId(scenarioReportID);
scenarioRequest.setProjectId(projectID);
if (StringUtils.equals(triggerMode, ReportTriggerMode.API.name())) {
scenarioRequest.setTriggerMode(ReportTriggerMode.JENKINS_RUN_TEST_PLAN.name());
scenarioRequest.setRunMode(ApiRunMode.UI_JENKINS_SCENARIO_PLAN.name());
} else if (StringUtils.equals(triggerMode, ReportTriggerMode.MANUAL.name())) {
scenarioRequest.setTriggerMode(ReportTriggerMode.MANUAL.name());
scenarioRequest.setRunMode(ApiRunMode.UI_JENKINS_SCENARIO_PLAN.name());
} else {
scenarioRequest.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
scenarioRequest.setRunMode(ApiRunMode.UI_SCHEDULE_SCENARIO_PLAN.name());
}
scenarioRequest.setExecuteType(ExecuteType.Saved.name());
Map<String, Map<String, String>> testPlanScenarioIdMap = new HashMap<>();
testPlanScenarioIdMap.put(testPlanID, planScenarioIdMap);
scenarioRequest.setTestPlanScenarioIDMap(testPlanScenarioIdMap);
scenarioRequest.setReportUserID(userId);
scenarioRequest.setTestPlanID(testPlanID);
scenarioRequest.setTestPlanReportId(planReportId);
scenarioRequest.setConfig(runModeConfig);
scenarioRequest.setType("ui");
List<MsExecResponseDTO> dtoList = this.scenarioRunModeConfig(scenarioRequest);
return this.parseMsExecREsponseDTOToTestIdReportMap(dtoList);
} else {
@ -1826,8 +1892,10 @@ public class TestPlanService {
TestPlanSimpleReportDTO report = new TestPlanSimpleReportDTO();
TestPlanFunctionResultReportDTO functionResult = new TestPlanFunctionResultReportDTO();
TestPlanApiResultReportDTO apiResult = new TestPlanApiResultReportDTO();
TestPlanUiResultReportDTO uiResult = new TestPlanUiResultReportDTO();
report.setFunctionResult(functionResult);
report.setApiResult(apiResult);
report.setUiResult(uiResult);
report.setStartTime(testPlan.getActualStartTime());
report.setEndTime(testPlan.getActualEndTime());
report.setSummary(testPlan.getReportSummary());
@ -1838,6 +1906,7 @@ public class TestPlanService {
testPlanApiCaseService.calculatePlanReport(planId, report);
testPlanScenarioCaseService.calculatePlanReport(planId, report);
testPlanLoadCaseService.calculatePlanReport(planId, report);
testPlanUiScenarioCaseService.calculatePlanReport(planId, report);
} else {
if (MapUtils.isNotEmpty(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap())) {
testPlanApiCaseService.calculatePlanReport(new ArrayList<>(testPlanExecuteReportDTO.getTestPlanApiCaseIdAndReportIdMap().values()), report);
@ -1850,6 +1919,10 @@ public class TestPlanService {
if (MapUtils.isNotEmpty(testPlanExecuteReportDTO.getTestPlanLoadCaseIdAndReportIdMap())) {
testPlanLoadCaseService.calculatePlanReport(new ArrayList<>(testPlanExecuteReportDTO.getTestPlanLoadCaseIdAndReportIdMap().values()), report);
}
if (MapUtils.isNotEmpty(testPlanExecuteReportDTO.getTestPlanUiScenarioIdAndReportIdMap())) {
testPlanUiScenarioCaseService.calculatePlanReport(new ArrayList<>(testPlanExecuteReportDTO.getTestPlanUiScenarioIdAndReportIdMap().values()), report);
}
}
if (report.getExecuteCount() != 0 && report.getCaseCount() != null) {
@ -1950,6 +2023,8 @@ public class TestPlanService {
}
runModeConfig.setRetryEnable(testplanRunRequest.isRetryEnable());
runModeConfig.setRetryNum(testplanRunRequest.getRetryNum());
runModeConfig.setBrowser(testplanRunRequest.getBrowser());
runModeConfig.setHeadlessEnabled(testplanRunRequest.isHeadlessEnabled());
return runModeConfig;
}
@ -2242,4 +2317,15 @@ public class TestPlanService {
String testPlanId = testplanRunRequest.getTestPlanId();
updatePlan(testplanRunRequest, testPlanId);
}
public boolean haveUiCase(String id) {
if (StringUtils.isBlank(id)) {
return false;
}
TestPlanUiScenarioExample uiScenarioExample = new TestPlanUiScenarioExample();
uiScenarioExample.createCriteria().andTestPlanIdEqualTo(id);
List<TestPlanUiScenario> testPlanUiScenarios = testPlanUiScenarioMapper.selectByExample(uiScenarioExample);
return !CollectionUtils.isEmpty(testPlanUiScenarios);
}
}

View File

@ -0,0 +1,619 @@
package io.metersphere.track.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
import io.metersphere.base.mapper.TestPlanMapper;
import io.metersphere.base.mapper.TestPlanUiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanUiScenarioCaseMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ExecuteResult;
import io.metersphere.commons.constants.ProjectApplicationType;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.dto.*;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.service.ProjectApplicationService;
import io.metersphere.service.ProjectService;
import io.metersphere.track.dto.*;
import io.metersphere.track.request.testcase.TestPlanScenarioCaseBatchRequest;
import io.metersphere.dto.RunUiScenarioRequest;
import io.metersphere.dto.UiScenarioRequest;
import io.metersphere.track.dto.UiRunModeConfigDTO;
import io.metersphere.xpack.ui.service.UiAutomationService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanUiScenarioCaseService {
@Resource
UiAutomationService uiAutomationService;
@Resource
TestPlanUiScenarioMapper testPlanUiScenarioMapper;
@Resource
ExtTestPlanUiScenarioCaseMapper extTestPlanUiScenarioCaseMapper;
@Resource
ApiScenarioReportService apiScenarioReportService;
@Resource
ApiScenarioMapper apiScenarioMapper;
@Resource
private TestPlanMapper testPlanMapper;
@Resource
private ProjectService projectService;
@Resource
private ApiTestEnvironmentMapper apiTestEnvironmentMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
@Lazy
private TestPlanService testPlanService;
@Resource
private ProjectApplicationService projectApplicationService;
public List<UiScenarioDTO> list(TestPlanScenarioRequest request) {
request.setProjectId(null);
request.setOrders(ServiceUtils.getDefaultSortOrder(request.getOrders()));
List<UiScenarioDTO> apiTestCases = extTestPlanUiScenarioCaseMapper.list(request);
if (CollectionUtils.isEmpty(apiTestCases)) {
return apiTestCases;
}
buildProjectInfo(apiTestCases);
buildUserInfo(apiTestCases);
return apiTestCases;
}
public void buildProjectInfo(List<? extends UiScenarioDTO> apiTestCases) {
List<String> projectIds = apiTestCases.stream()
.map(UiScenarioDTO::getProjectId)
.collect(Collectors.toSet())
.stream().collect(Collectors.toList());
Map<String, Project> projectMap = projectService.getProjectByIds(projectIds).stream()
.collect(Collectors.toMap(Project::getId, project -> project));
apiTestCases.forEach(item -> {
Project project = projectMap.get(item.getProjectId());
if(project != null){
ProjectConfig config = projectApplicationService.getSpecificTypeValue(project.getId(), ProjectApplicationType.SCENARIO_CUSTOM_NUM.name());
boolean custom = config.getScenarioCustomNum();
if (custom) {
item.setCustomNum(item.getCustomNum());
}else {
item.setCustomNum(item.getNum().toString());
}
}else {
item.setCustomNum(item.getNum().toString());
}
});
}
public void buildUserInfo(List<? extends UiScenarioDTO> apiTestCases) {
List<String> userIds = new ArrayList();
userIds.addAll(apiTestCases.stream().map(UiScenarioDTO::getUserId).collect(Collectors.toList()));
userIds.addAll(apiTestCases.stream().map(UiScenarioDTO::getPrincipal).collect(Collectors.toList()));
if (!CollectionUtils.isEmpty(userIds)) {
Map<String, String> userMap = ServiceUtils.getUserNameMap(userIds);
apiTestCases.forEach(caseResult -> {
caseResult.setCreatorName(userMap.get(caseResult.getCreateUser()));
caseResult.setPrincipalName(userMap.get(caseResult.getPrincipal()));
});
}
}
public List<String> selectIds(TestPlanScenarioRequest request) {
request.setProjectId(null);
request.setOrders(ServiceUtils.getDefaultSortOrder(request.getOrders()));
List<String> idList = extTestPlanUiScenarioCaseMapper.selectIds(request);
return idList;
}
public Pager<List<UiScenarioDTO>> relevanceList(UiScenarioRequest request, int goPage, int pageSize) {
request.setNotInTestPlan(true);
if (testPlanService.isAllowedRepeatCase(request.getPlanId())) {
request.setNotInTestPlan(false);
}
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, uiAutomationService.list(request));
}
public int delete(String id) {
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria()
.andIdEqualTo(id);
return testPlanUiScenarioMapper.deleteByExample(example);
}
public void deleteApiCaseBath(TestPlanScenarioCaseBatchRequest request) {
List<String> ids = request.getIds();
if (request.getCondition() != null && request.getCondition().isSelectAll()) {
ids = this.selectIds(request.getCondition());
if (request.getCondition() != null && request.getCondition().getUnSelectIds() != null) {
ids.removeAll(request.getCondition().getUnSelectIds());
}
}
if (CollectionUtils.isEmpty(ids)) {
return;
}
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria()
.andIdIn(ids);
testPlanUiScenarioMapper.deleteByExample(example);
}
public List<MsExecResponseDTO> run(RunTestPlanScenarioRequest testPlanScenarioRequest) {
StringBuilder idStr = new StringBuilder();
List<String> planCaseIdList = testPlanScenarioRequest.getPlanCaseIds();
if (testPlanScenarioRequest.getCondition() != null && testPlanScenarioRequest.getCondition().isSelectAll()) {
planCaseIdList = this.selectIds(testPlanScenarioRequest.getCondition());
if (testPlanScenarioRequest.getCondition().getUnSelectIds() != null) {
planCaseIdList.removeAll(testPlanScenarioRequest.getCondition().getUnSelectIds());
}
}
testPlanScenarioRequest.setPlanCaseIds(planCaseIdList);
if (CollectionUtils.isEmpty(planCaseIdList)) {
MSException.throwException("未找到执行场景!");
}
RunModeConfigDTO config = testPlanScenarioRequest.getConfig();
if (config != null) {
String envType = config.getEnvironmentType();
String envGroupId = config.getEnvironmentGroupId();
Map<String, String> envMap = config.getEnvMap();
if ((StringUtils.equals(envType, EnvironmentType.JSON.toString()) && envMap != null && !envMap.isEmpty())
|| (StringUtils.equals(envType, EnvironmentType.GROUP.toString()) && StringUtils.isNotBlank(envGroupId))) {
// 更新场景用例环境信息运行时从数据库读取最新环境
this.setScenarioEnv(new ArrayList<>(), planCaseIdList, testPlanScenarioRequest.getConfig());
}
}
planCaseIdList.forEach(item -> {
idStr.append("\"").append(item).append("\"").append(",");
});
List<TestPlanUiScenario> testPlanApiScenarioList = extTestPlanUiScenarioCaseMapper.selectByIds(idStr.toString().substring(0, idStr.toString().length() - 1), "\"" + StringUtils.join(testPlanScenarioRequest.getPlanCaseIds(), ",") + "\"");
List<String> scenarioIds = new ArrayList<>();
Map<String, String> scenarioPlanIdMap = new LinkedHashMap<>();
for (TestPlanUiScenario apiScenario : testPlanApiScenarioList) {
scenarioIds.add(apiScenario.getUiScenarioId());
scenarioPlanIdMap.put(apiScenario.getId(), apiScenario.getUiScenarioId());
}
if (scenarioPlanIdMap.isEmpty()) {
MSException.throwException("未找到执行场景!");
}
RunUiScenarioRequest request = new RunUiScenarioRequest();
request.setIds(scenarioIds);
request.setReportId(testPlanScenarioRequest.getId());
request.setScenarioTestPlanIdMap(scenarioPlanIdMap);
request.setRunMode(ApiRunMode.UI_SCENARIO.name());
request.setId(testPlanScenarioRequest.getId());
request.setExecuteType(ExecuteType.Saved.name());
request.setTriggerMode(testPlanScenarioRequest.getTriggerMode());
request.setConfig(testPlanScenarioRequest.getConfig());
request.setProjectId(testPlanScenarioRequest.getProjectId());
UiRunModeConfigDTO configDTO = new UiRunModeConfigDTO();
BeanUtils.copyBean(configDTO, testPlanScenarioRequest.getConfig());
configDTO.setHeadlessEnabled(true);
request.setUiConfig(configDTO);
request.setPlanCaseIds(planCaseIdList);
request.setRequestOriginator("TEST_PLAN");
return uiAutomationService.run(request);
}
public void setScenarioEnv(List<TestPlanUiScenario> testPlanApiScenarios, List<String> planScenarioIds, RunModeConfigDTO runModeConfig) {
if (CollectionUtils.isEmpty(planScenarioIds)) return;
if (CollectionUtils.isEmpty(testPlanApiScenarios)) {
TestPlanUiScenarioExample testPlanApiScenarioExample = new TestPlanUiScenarioExample();
testPlanApiScenarioExample.createCriteria().andIdIn(planScenarioIds);
testPlanApiScenarios = testPlanUiScenarioMapper.selectByExampleWithBLOBs(testPlanApiScenarioExample);
}
if (CollectionUtils.isEmpty(planScenarioIds)) {
return;
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestPlanUiScenarioMapper mapper = sqlSession.getMapper(TestPlanUiScenarioMapper.class);
String environmentType = runModeConfig.getEnvironmentType();
String environmentGroupId = runModeConfig.getEnvironmentGroupId();
if (StringUtils.equals(environmentType, EnvironmentType.JSON.toString())) {
Map<String, String> envMap = runModeConfig.getEnvMap();
for (TestPlanUiScenario testPlanApiScenario : testPlanApiScenarios) {
String env = testPlanApiScenario.getEnvironment();
if (StringUtils.isBlank(env)) {
if (envMap != null && !envMap.isEmpty()) {
env = JSON.toJSONString(envMap);
}
}
Map<String, String> map = JSON.parseObject(env, Map.class);
if (map.isEmpty()) {
continue;
}
Set<String> set = map.keySet();
for (String s : set) {
if (StringUtils.isNotBlank(envMap.get(s))) {
map.put(s, envMap.get(s));
}
}
String envJsonStr = JSON.toJSONString(map);
if (!StringUtils.equals(envJsonStr, testPlanApiScenario.getEnvironment())) {
testPlanApiScenario.setEnvironmentType(EnvironmentType.JSON.toString());
testPlanApiScenario.setEnvironment(JSON.toJSONString(map));
mapper.updateByPrimaryKeyWithBLOBs(testPlanApiScenario);
}
}
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
}
if (StringUtils.equals(environmentType, EnvironmentType.GROUP.toString())) {
for (TestPlanUiScenario testPlanApiScenario : testPlanApiScenarios) {
testPlanApiScenario.setEnvironmentType(EnvironmentType.GROUP.toString());
testPlanApiScenario.setEnvironmentGroupId(environmentGroupId);
mapper.updateByPrimaryKeyWithBLOBs(testPlanApiScenario);
}
sqlSession.flushStatements();
}
}
public List<TestPlanUiScenario> getCasesByPlanId(String planId) {
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria().andTestPlanIdEqualTo(planId);
return testPlanUiScenarioMapper.selectByExample(example);
}
public List<String> getExecResultByPlanId(String planId) {
return extTestPlanUiScenarioCaseMapper.getExecResultByPlanId(planId);
}
public void deleteByPlanId(String planId) {
TestPlanScenarioCaseBatchRequest request = new TestPlanScenarioCaseBatchRequest();
List<String> ids = extTestPlanUiScenarioCaseMapper.getIdsByPlanId(planId);
request.setIds(ids);
deleteApiCaseBath(request);
}
public void deleteByRelevanceProjectIds(String planId, List<String> relevanceProjectIds) {
TestPlanScenarioCaseBatchRequest request = new TestPlanScenarioCaseBatchRequest();
request.setIds(extTestPlanUiScenarioCaseMapper.getNotRelevanceCaseIds(planId, relevanceProjectIds));
request.setPlanId(planId);
deleteApiCaseBath(request);
}
public void bathDeleteByScenarioIds(List<String> ids) {
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria().andUiScenarioIdIn(ids);
testPlanUiScenarioMapper.deleteByExample(example);
}
public void deleteByScenarioId(String id) {
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria().andUiScenarioIdEqualTo(id);
testPlanUiScenarioMapper.deleteByExample(example);
}
public void batchUpdateEnv(RelevanceScenarioRequest request) {
Map<String, String> envMap = request.getEnvMap();
String envType = request.getEnvironmentType();
String envGroupId = request.getEnvGroupId();
Map<String, List<String>> mapping = request.getMapping();
Set<String> set = mapping.keySet();
request.setIds(new ArrayList<>(set));
if (set.isEmpty()) {
return;
}
if (StringUtils.equals(envType, EnvironmentType.GROUP.name()) && StringUtils.isNotBlank(envGroupId)) {
set.forEach(id -> {
TestPlanUiScenario scenario = new TestPlanUiScenario();
scenario.setId(id);
scenario.setEnvironmentType(EnvironmentType.GROUP.name());
scenario.setEnvironmentGroupId(envGroupId);
testPlanUiScenarioMapper.updateByPrimaryKeySelective(scenario);
});
} else if (StringUtils.equals(envType, EnvironmentType.JSON.name())) {
set.forEach(id -> {
Map<String, String> newEnvMap = new HashMap<>(16);
if (envMap != null && !envMap.isEmpty()) {
List<String> list = mapping.get(id);
list.forEach(l -> {
newEnvMap.put(l, envMap.get(l));
});
}
if (!newEnvMap.isEmpty()) {
TestPlanUiScenario scenario = new TestPlanUiScenario();
scenario.setId(id);
scenario.setEnvironmentType(EnvironmentType.JSON.name());
scenario.setEnvironment(JSON.toJSONString(newEnvMap));
testPlanUiScenarioMapper.updateByPrimaryKeySelective(scenario);
}
});
}
}
public List<UiScenarioDTO> selectAllTableRows(TestPlanScenarioCaseBatchRequest request) {
List<String> ids = request.getIds();
if (request.getCondition() != null && request.getCondition().isSelectAll()) {
ids = this.selectIds(request.getCondition());
if (request.getCondition() != null && request.getCondition().getUnSelectIds() != null) {
ids.removeAll(request.getCondition().getUnSelectIds());
}
}
if (ids == null || ids.isEmpty()) {
return new ArrayList<>();
}
TestPlanScenarioRequest tableRequest = new TestPlanScenarioRequest();
tableRequest.setIds(ids);
return extTestPlanUiScenarioCaseMapper.list(tableRequest);
}
public String getLogDetails(String id) {
TestPlanUiScenario scenario = testPlanUiScenarioMapper.selectByPrimaryKey(id);
if (scenario != null) {
ApiScenarioWithBLOBs testCase = apiScenarioMapper.selectByPrimaryKey(scenario.getUiScenarioId());
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(scenario.getTestPlanId());
OperatingLogDetails details = new OperatingLogDetails(JSON.toJSONString(id), testPlan.getProjectId(), testCase.getName(), scenario.getCreateUser(), new LinkedList<>());
return JSON.toJSONString(details);
}
return null;
}
public String getLogDetails(List<String> ids) {
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria().andIdIn(ids);
List<TestPlanUiScenario> nodes = testPlanUiScenarioMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(nodes)) {
ApiScenarioExample scenarioExample = new ApiScenarioExample();
scenarioExample.createCriteria().andIdIn(nodes.stream().map(TestPlanUiScenario::getUiScenarioId).collect(Collectors.toList()));
List<ApiScenario> scenarios = apiScenarioMapper.selectByExample(scenarioExample);
if (CollectionUtils.isNotEmpty(scenarios)) {
List<String> names = scenarios.stream().map(ApiScenario::getName).collect(Collectors.toList());
OperatingLogDetails details = new OperatingLogDetails(JSON.toJSONString(ids), scenarios.get(0).getProjectId(), String.join(",", names), nodes.get(0).getCreateUser(), new LinkedList<>());
return JSON.toJSONString(details);
}
}
return null;
}
public TestPlanUiScenario get(String id) {
return testPlanUiScenarioMapper.selectByPrimaryKey(id);
}
public Boolean hasFailCase(String planId, List<String> automationIds) {
if (CollectionUtils.isEmpty(automationIds)) {
return false;
}
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria()
.andTestPlanIdEqualTo(planId)
.andUiScenarioIdIn(automationIds)
.andLastResultEqualTo("Fail");
return testPlanUiScenarioMapper.countByExample(example) > 0 ? true : false;
}
public Map<String, String> getScenarioCaseEnv(Map<String, String> map) {
Set<String> set = map.keySet();
HashMap<String, String> envMap = new HashMap<>(16);
if (set.isEmpty()) {
return envMap;
}
for (String projectId : set) {
String envId = map.get(projectId);
if (StringUtils.isBlank(envId)) {
continue;
}
Project project = projectService.getProjectById(projectId);
ApiTestEnvironmentWithBLOBs environment = apiTestEnvironmentMapper.selectByPrimaryKey(envId);
if (project == null || environment == null) {
continue;
}
String projectName = project.getName();
String envName = environment.getName();
if (StringUtils.isBlank(projectName) || StringUtils.isBlank(envName)) {
continue;
}
envMap.put(projectName, envName);
}
return envMap;
}
public void calculatePlanReport(String planId, TestPlanSimpleReportDTO report) {
List<PlanReportCaseDTO> planReportCaseDTOS = extTestPlanUiScenarioCaseMapper.selectForPlanReport(planId);
calculatePlanReport(report, planReportCaseDTOS);
}
public void calculatePlanReport(List<String> reportIds, TestPlanSimpleReportDTO report) {
List<PlanReportCaseDTO> planReportCaseDTOS = apiScenarioReportService.selectForPlanReport(reportIds);
calculatePlanReport(report, planReportCaseDTOS);
}
public void calculatePlanReportByScenarioList(List<TestPlanFailureUiScenarioDTO> scenarioList,TestPlanSimpleReportDTO report){
List<PlanReportCaseDTO> planReportCaseDTOS = new ArrayList<>();
for (TestPlanFailureUiScenarioDTO scenario : scenarioList) {
PlanReportCaseDTO dto = new PlanReportCaseDTO();
dto.setCaseId(scenario.getCaseId());
dto.setId(scenario.getId());
dto.setStatus(scenario.getStatus());
dto.setReportId(scenario.getReportId());
planReportCaseDTOS.add(dto);
}
calculatePlanReport(report, planReportCaseDTOS);
}
private void calculatePlanReport(TestPlanSimpleReportDTO report, List<PlanReportCaseDTO> planReportCaseDTOS) {
TestPlanUiResultReportDTO uiResult = report.getUiResult();
List<TestCaseReportStatusResultDTO> statusResult = new ArrayList<>();
Map<String, TestCaseReportStatusResultDTO> statusResultMap = new HashMap<>();
TestPlanUtils.buildStatusResultMap(planReportCaseDTOS, statusResultMap, report, "Success");
TestPlanUtils.addToReportCommonStatusResultList(statusResultMap, statusResult);
TestPlanScenarioStepCountDTO stepCount = new TestPlanScenarioStepCountDTO();
for (PlanReportCaseDTO item : planReportCaseDTOS) {
calculateScenarioResultDTO(item, stepCount);
}
int underwayStepsCounts = getUnderwayStepsCounts(stepCount.getUnderwayIds());
List<TestCaseReportStatusResultDTO> stepResult = new ArrayList<>();
getScenarioCaseReportStatusResultDTO(TestPlanTestCaseStatus.Failure.name(), stepCount.getScenarioStepError(), stepResult);
getScenarioCaseReportStatusResultDTO(TestPlanTestCaseStatus.Pass.name(), stepCount.getScenarioStepSuccess(), stepResult);
getScenarioCaseReportStatusResultDTO(ExecuteResult.ERROR_REPORT_RESULT.toString(), stepCount.getScenarioStepErrorReport(), stepResult);
getScenarioCaseReportStatusResultDTO(TestPlanTestCaseStatus.Underway.name(),
stepCount.getScenarioStepTotal() - stepCount.getScenarioStepSuccess() - stepCount.getScenarioStepError() - stepCount.getScenarioStepErrorReport() + underwayStepsCounts, stepResult);
uiResult.setUiScenarioData(statusResult);
uiResult.setUiScenarioStepData(stepResult);
report.setUiResult(uiResult);
}
private int getUnderwayStepsCounts(List<String> underwayIds) {
if (CollectionUtils.isNotEmpty(underwayIds)) {
List<Integer> underwayStepsCounts = extTestPlanUiScenarioCaseMapper.getUnderwaySteps(underwayIds);
return underwayStepsCounts.stream().filter(Objects::nonNull).reduce(0, Integer::sum);
}
return 0;
}
private void calculateScenarioResultDTO(PlanReportCaseDTO item,
TestPlanScenarioStepCountDTO stepCount) {
if (StringUtils.isNotBlank(item.getReportId())) {
APIScenarioReportResult apiScenarioReportResult = apiScenarioReportService.get(item.getReportId(),false);
if (apiScenarioReportResult != null) {
String content = apiScenarioReportResult.getContent();
if (StringUtils.isNotBlank(content)) {
JSONObject jsonObject = JSONObject.parseObject(content);
stepCount.setScenarioStepTotal(stepCount.getScenarioStepTotal() + jsonObject.getIntValue("scenarioStepTotal"));
stepCount.setScenarioStepSuccess(stepCount.getScenarioStepSuccess() + jsonObject.getIntValue("scenarioStepSuccess"));
stepCount.setScenarioStepError(stepCount.getScenarioStepError() + jsonObject.getIntValue("scenarioStepError"));
stepCount.setScenarioStepErrorReport(stepCount.getScenarioStepErrorReport() + jsonObject.getIntValue("scenarioStepErrorReport"));
stepCount.setScenarioStepUnExecute(stepCount.getScenarioStepUnExecute() + jsonObject.getIntValue("scenarioStepUnExecuteReport"));
}
}
} else {
stepCount.getUnderwayIds().add(item.getCaseId());
}
}
private void getScenarioCaseReportStatusResultDTO(String status, int count, List<TestCaseReportStatusResultDTO> scenarioCaseList) {
if (count > 0) {
TestCaseReportStatusResultDTO scenarioCase = new TestCaseReportStatusResultDTO();
scenarioCase.setStatus(status);
scenarioCase.setCount(count);
scenarioCaseList.add(scenarioCase);
}
}
public List<TestPlanFailureUiScenarioDTO> getAllCases(String planId) {
List<TestPlanFailureUiScenarioDTO> apiTestCases =
extTestPlanUiScenarioCaseMapper.getFailureList(planId, null);
return buildCases(apiTestCases);
}
public List<TestPlanFailureUiScenarioDTO> getAllCases(Map<String, String> idMap, Map<String, TestPlanFailureUiScenarioDTO> scenarioInfoDTOMap) {
String defaultStatus = "Fail";
Map<String, String> reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values());
Map<String, String> savedReportMap = new HashMap<>(idMap);
List<TestPlanFailureUiScenarioDTO> apiTestCases = new ArrayList<>();
for (TestPlanFailureUiScenarioDTO dto : scenarioInfoDTOMap.values()) {
String reportId = savedReportMap.get(dto.getId());
savedReportMap.remove(dto.getId());
dto.setReportId(reportId);
if (StringUtils.isNotEmpty(reportId)) {
String status = reportStatus.get(reportId);
if (status == null) {
status = defaultStatus;
} else {
if (StringUtils.equalsIgnoreCase(status, "Error")) {
status = "Fail";
}
}
dto.setLastResult(status);
dto.setStatus(status);
}
apiTestCases.add(dto);
}
return buildCases(apiTestCases);
}
public List<TestPlanFailureUiScenarioDTO> getFailureCases(String planId) {
List<TestPlanFailureUiScenarioDTO> apiTestCases =
extTestPlanUiScenarioCaseMapper.getFailureList(planId, "Fail");
return buildCases(apiTestCases);
}
public List<TestPlanFailureUiScenarioDTO> buildCases(List<TestPlanFailureUiScenarioDTO> apiTestCases) {
if (CollectionUtils.isEmpty(apiTestCases)) {
return apiTestCases;
}
buildProjectInfo(apiTestCases);
buildUserInfo(apiTestCases);
return apiTestCases;
}
public TestPlanUiScenario selectByReportId(String reportId) {
TestPlanUiScenarioExample example = new TestPlanUiScenarioExample();
example.createCriteria().andReportIdEqualTo(reportId);
List<TestPlanUiScenario> testPlanApiScenarios = testPlanUiScenarioMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(testPlanApiScenarios)) {
return testPlanApiScenarios.get(0);
}
return null;
}
public String getProjectIdById(String testPlanScenarioId) {
return extTestPlanUiScenarioCaseMapper.getProjectIdById(testPlanScenarioId);
}
public void initOrderField() {
ServiceUtils.initOrderField(TestPlanUiScenario.class, TestPlanUiScenarioMapper.class,
extTestPlanUiScenarioCaseMapper::selectPlanIds,
extTestPlanUiScenarioCaseMapper::getIdsOrderByUpdateTime);
}
/**
* 用例自定义排序
*
* @param request
*/
public void updateOrder(ResetOrderRequest request) {
ServiceUtils.updateOrderField(request, TestPlanUiScenario.class,
testPlanUiScenarioMapper::selectByPrimaryKey,
extTestPlanUiScenarioCaseMapper::getPreOrder,
extTestPlanUiScenarioCaseMapper::getLastOrder,
testPlanUiScenarioMapper::updateByPrimaryKeySelective);
}
public List<TestPlanFailureUiScenarioDTO> getErrorReportCases(String planId) {
List<TestPlanFailureUiScenarioDTO> apiTestCases =
extTestPlanUiScenarioCaseMapper.getFailureList(planId, ExecuteResult.ERROR_REPORT_RESULT.toString());
return buildCases(apiTestCases);
}
public List<TestPlanFailureUiScenarioDTO> getUnExecuteCases(String planId) {
List<TestPlanFailureUiScenarioDTO> apiTestCases =
extTestPlanUiScenarioCaseMapper.getFailureList(planId, "unExecute");
return buildCases(apiTestCases);
}
}

View File

@ -86,7 +86,8 @@
<!-- <ignoreColumn column="clean_load_report_expr"/>-->
<!-- <ignoreColumn column="repeatable"/>-->
<!-- </table>-->
<table tableName="test_plan_report"/>
<table tableName="test_plan_report_content"/>
<!-- <table tableName="scenario_execution_info"/>-->
<!--<table tableName="enterprise_test_report_send_record"/>-->
<!--<table tableName="test_case_review_api_case"/>
<table tableName="test_case_review_load"/>

View File

@ -19,6 +19,23 @@
@showPopover="showPopover"
ref="envPopover" class="env-popover"/>
</div>
<div style="margin-bottom: 10px;" v-if="haveUICase">
<span class="ms-mode-span">{{ $t("浏览器") }}</span>
<el-select
size="mini"
v-model="runConfig.browser"
style="margin-right: 30px; width: 100px"
>
<el-option
v-for="b in browsers"
:key="b.value"
:value="b.value"
:label="b.label"
></el-option>
</el-select>
</div>
<div>
<span class="ms-mode-span">{{ $t("run_mode.title") }}</span>
<el-radio-group v-model="runConfig.mode" @change="changeMode">
@ -29,7 +46,7 @@
<div class="ms-mode-div" v-if="runConfig.mode === 'serial'">
<el-row>
<el-col :span="6">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
<span class="ms-mode-pan">{{ $t("run_mode.other_config") }}</span>
</el-col>
<el-col :span="18">
<div v-if="testType === 'API'">
@ -107,6 +124,18 @@
</el-row>
</div>
<div>
<el-row>
<el-col :span="18" :offset="6">
<div style="margin-top: 10px" v-if="haveUICase">
<el-checkbox v-model="runConfig.headlessEnabled">
{{ $t("性能模式") }}
</el-checkbox>
</div>
</el-col>
</el-row>
</div>
<template v-slot:footer>
<div class="dialog-footer" v-if="showSave">
<el-button @click="close">{{ $t('commons.cancel') }}</el-button>
@ -151,6 +180,7 @@
environmentType: ENV_TYPE.JSON,
retryEnable: false,
retryNum: 1,
browser: "CHROME"
},
isHasLicense: hasLicense(),
projectEnvListMap: {},
@ -163,7 +193,17 @@
value: 'save',
label: this.$t('commons.save')
}],
value: 'confirmAndRun'
value: 'confirmAndRun',
browsers: [
{
label: this.$t("chrome"),
value: "CHROME",
},
{
label: this.$t("firefox"),
value: "FIREFOX",
}
],
};
},
props: {
@ -176,6 +216,11 @@
type: Boolean,
default: false
},
//ui ui
haveUICase: {
type: Boolean,
default: false
}
},
methods: {
open(testType) {

View File

@ -53,6 +53,21 @@
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
</el-radio-group>
</div>
<div style="margin-top: 10px;" v-if="haveUICase">
<span class="ms-mode-span">{{ $t("浏览器") }}</span>
<el-select
size="mini"
v-model="runConfig.browser"
style="margin-right: 30px; width: 100px"
>
<el-option
v-for="b in browsers"
:key="b.value"
:value="b.value"
:label="b.label"
></el-option>
</el-select>
</div>
<div class="ms-mode-div" v-if="runConfig.mode === 'serial'">
<el-row>
<el-col :span="3">
@ -127,7 +142,7 @@
</el-col>
</el-row>
</div>
<div class="ms-failure-div" v-if="runConfig.mode === 'serial'">
<div class="ms-failure-div" v-if="runConfig.mode === 'serial'" >
<el-row>
<el-col :span="18" :offset="3">
<div>
@ -136,6 +151,20 @@
</el-col>
</el-row>
</div>
<div v-if="haveUICase">
<el-row>
<el-col :span="3">
&nbsp;
</el-col>
<el-col :span="18">
<div style="margin-top: 10px">
<el-checkbox v-model="runConfig.headlessEnabled">
{{ $t("性能模式") }}
</el-checkbox>
</div>
</el-col>
</el-row>
</div>
<el-dialog width="60%" :title="$t('schedule.generate_expression')" :visible.sync="showCron"
:modal="false">
@ -197,7 +226,12 @@ export default {
default: false
},
planCaseIds: [],
type: String
type: String,
//ui ui
haveUICase: {
type: Boolean,
default: false
}
},
@ -260,11 +294,23 @@ export default {
resourcePoolId: null,
retryEnable: false,
retryNum: 1,
browser: "CHROME",
headlessEnabled: true
},
projectList: [],
testType: 'API',
planId: String,
projectIds: new Set(),
browsers: [
{
label: this.$t("chrome"),
value: "CHROME",
},
{
label: this.$t("firefox"),
value: "FIREFOX",
}
],
};
},
methods: {

View File

@ -200,6 +200,13 @@
:label="$t('test_track.plan.test_plan_api_scenario_count')"
min-width="200px">
</ms-table-column>
<ms-table-column
prop="testPlanUiScenarioCount"
:field="item"
:fields-width="fieldsWidth"
:label="$t('test_track.plan.test_plan_ui_scenario_count')"
min-width="200px">
</ms-table-column>
<ms-table-column
prop="testPlanLoadCaseCount"
:field="item"
@ -302,10 +309,10 @@
{{ $t('test_track.plan.plan_delete_tip') }}
</ms-delete-confirm>
<ms-test-plan-schedule-maintain ref="scheduleMaintain" @refreshTable="initTableData" :plan-case-ids="[]"
:type="'plan'"/>
:type="'plan'" :have-u-i-case="haveUICase"/>
<ms-test-plan-schedule-batch-switch ref="scheduleBatchSwitch" @refresh="refresh"/>
<plan-run-mode-with-env @handleRunBatch="_handleRun" ref="runMode" :plan-case-ids="[]" :type="'plan'"
:plan-id="currentPlanId" :show-save="true"/>
:plan-id="currentPlanId" :show-save="true" :have-u-i-case="haveUICase"/>
<test-plan-report-review ref="testCaseReportView"/>
<ms-task-center ref="taskCenter" :show-menu="false"/>
<el-dialog
@ -457,7 +464,8 @@ export default {
permission: ['PROJECT_TRACK_PLAN:READ+EDIT']
},
],
batchExecuteType:"serial"
batchExecuteType:"serial",
haveUICase: false
};
},
watch: {
@ -733,8 +741,11 @@ export default {
openReport(plan) {
this.$refs.testCaseReportView.open(plan);
},
scheduleTask(row) {
async scheduleTask(row) {
row.redirectFrom = "testPlan";
this.currentPlanId = row.id;
let r = await this.haveUIScenario();
this.haveUICase = r.data.data;
this.$refs.scheduleMaintain.open(row);
},
saveSortField(key, orders) {
@ -758,9 +769,11 @@ export default {
},
handleRun(row) {
this.currentPlanId = row.id;
this.$get("/test/plan/have/exec/case/" + row.id, res => {
this.$get("/test/plan/have/exec/case/" + row.id, async res => {
const haveExecCase = res.data;
if (haveExecCase) {
let r = await this.haveUIScenario();
this.haveUICase = r.data.data;
this.$refs.runMode.open('API');
} else {
this.$router.push('/track/plan/view/' + row.id);
@ -776,7 +789,9 @@ export default {
resourcePoolId,
envMap,
environmentType,
environmentGroupId
environmentGroupId,
browser,
headlessEnabled
} = config;
let param = {mode, reportType, onSampleError, runWithinResourcePool, resourcePoolId, envMap};
param.testPlanId = this.currentPlanId;
@ -788,6 +803,8 @@ export default {
param.requestOriginator = "TEST_PLAN";
param.retryEnable = config.retryEnable;
param.retryNum = config.retryNum;
param.browser = config.browser;
param.headlessEnabled = config.headlessEnabled;
if(config.isRun === true){
this.$refs.taskCenter.open();
this.result = this.$post('test/plan/run/', param, () => {
@ -826,6 +843,9 @@ export default {
return
}
},
haveUIScenario() {
return this.$get("/test/plan/have/ui/case/" + this.currentPlanId);
}
}
};

View File

@ -14,6 +14,7 @@
class="el-menu-demo header-menu" mode="horizontal" @select="handleSelect">
<el-menu-item index="functional">{{ $t('test_track.functional_test_case') }}</el-menu-item>
<el-menu-item index="api" v-modules="['api']">{{ $t('test_track.api_test_case') }}</el-menu-item>
<el-menu-item index="ui" v-modules="['ui']">{{ $t('test_track.ui_test_case') }}</el-menu-item>
<el-menu-item index="load" v-modules="['performance']">{{ $t('test_track.performance_test_case') }}</el-menu-item>
<el-menu-item index="report">{{ $t('test_track.report_statistics') }}</el-menu-item>
</el-menu>
@ -25,6 +26,8 @@
ref="testPlanFunctional"/>
<test-plan-api v-if="activeIndex === 'api'" :redirectCharType="redirectCharType" :clickType="clickType"
:plan-id="planId" :version-enable="versionEnable" :plan-status="currentPlan.status"/>
<test-plan-ui v-if="activeIndex === 'ui'" :redirectCharType="redirectCharType" :clickType="clickType"
:plan-id="planId" :version-enable="versionEnable" :plan-status="currentPlan.status"/>
<test-plan-load v-if="activeIndex === 'load'" :redirectCharType="redirectCharType" :clickType="clickType"
:plan-id="planId" :version-enable="versionEnable" :plan-status="currentPlan.status"/>
<test-plan-report-content class="plan-report" v-if="activeIndex === 'report'" :plan-id="planId" :version-enable="versionEnable"/>
@ -47,6 +50,7 @@ import MsMainContainer from "../../../common/components/MsMainContainer";
import MsTestPlanHeaderBar from "./comonents/head/TestPlanHeaderBar";
import TestPlanFunctional from "./comonents/functional/TestPlanFunctional";
import TestPlanApi from "./comonents/api/TestPlanApi";
import TestPlanUi from "./comonents/api/TestPlanUi";
import TestPlanLoad from "@/business/components/track/plan/view/comonents/load/TestPlanLoad";
import {getCurrentProjectID, hasLicense} from "@/common/js/utils";
import TestPlanReportContent from "@/business/components/track/plan/view/comonents/report/detail/TestPlanReportContent";
@ -62,7 +66,12 @@ export default {
TestPlanFunctional,
MsTestPlanHeaderBar,
MsMainContainer,
MsAsideContainer, MsContainer, NodeTree, SelectMenu, TestPlanLoad
MsAsideContainer,
MsContainer,
NodeTree,
SelectMenu,
TestPlanLoad,
TestPlanUi
},
data() {
return {

View File

@ -0,0 +1,294 @@
<template>
<div v-loading="result.loading">
<el-input :placeholder="$t('api_test.definition.request.select_case')" @blur="filterSearch"
@keyup.enter.native="filterSearch" class="search-input" size="small" v-model="condition.name"/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0"
@search="filterSearch"/>
<ms-table ref="scenarioTable"
v-loading="result.loading"
:data="tableData"
:condition="condition"
:page-size="pageSize"
:total="total"
:remember-order="true"
row-key="id"
:row-order-group-id="projectId"
@order="search"
@filter="filterSearch"
:disable-header-config="true"
:show-select-all="false"
@selectCountChange="selectCountChange">
<el-table-column v-if="!customNum" prop="num" label="ID" sortable="custom"
show-overflow-tooltip>
</el-table-column>
<el-table-column v-if="customNum" prop="customNum" label="ID" sortable="custom"
show-overflow-tooltip>
</el-table-column>
<el-table-column prop="name" :label="$t('api_test.automation.scenario_name')" sortable="custom" min-width="100px"
show-overflow-tooltip/>
<el-table-column prop="level" :label="$t('api_test.automation.case_level')" sortable="custom" min-width="100px"
show-overflow-tooltip>
<template v-slot:default="scope">
<priority-table-item :value="scope.row.level" ref="level"/>
</template>
</el-table-column>
<el-table-column prop="tagNames" :label="$t('api_test.automation.tag')" min-width="100">
<template v-slot:default="scope">
<ms-tag v-for="itemName in scope.row.tags" :key="itemName" type="success" effect="plain" :content="itemName"
style="margin-left: 0px; margin-right: 2px"/>
</template>
</el-table-column>
<el-table-column prop="userId" :label="$t('api_test.automation.creator')" show-overflow-tooltip sortable="custom" min-width="100px"/>
<el-table-column prop="updateTime" :label="$t('api_test.automation.update_time')" width="180" sortable="custom">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
<el-table-column prop="lastResult" :label="$t('api_test.automation.last_result')" sortable="custom">
<template v-slot:default="{row}">
<el-link type="success" @click="showReport(row)" v-if="row.lastResult === 'Success'">
{{ $t('api_test.automation.success') }}
</el-link>
<el-link type="danger" @click="showReport(row)" v-if="row.lastResult === 'Fail'">
{{ $t('api_test.automation.fail') }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="passRate" :label="$t('api_test.automation.passing_rate')"
show-overflow-tooltip/>
</ms-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
</div>
</template>
<script>
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTag from "../../../../../common/components/MsTag";
import MsApiReportDetail from "../../../../../api/automation/report/ApiReportDetail";
import MsTableMoreBtn from "../../../../../api/automation/scenario/TableMoreBtn";
import MsTestPlanList from "../../../../../api/automation/scenario/testplan/TestPlanList";
import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader";
import EnvPopover from "@/business/components/api/automation/scenario/EnvPopover";
import PriorityTableItem from "@/business/components/track/common/tableItems/planview/PriorityTableItem";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import {
TEST_PLAN_RELEVANCE_API_SCENARIO_CONFIGS
} from "@/business/components/common/components/search/search-components";
import {ENV_TYPE} from "@/common/js/constants";
import MsTable from "@/business/components/common/components/table/MsTable";
import {getVersionFilters} from "@/network/project";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
export default {
name: "RelevanceUiScenarioList",
components: {
MsTable,
PriorityTableItem,
EnvPopover,
TestPlanScenarioListHeader,
MsTablePagination,
MsTableMoreBtn,
ShowMoreBtn,
MsTableHeader,
MsTag,
MsApiReportDetail,
MsTestPlanList,
MsTableAdvSearchBar,
'VersionSelect': VersionSelect.default,
},
props: {
referenced: {
type: Boolean,
default: false,
},
selectNodeIds: Array,
projectId: String,
planId: String,
versionEnable: Boolean,
},
data() {
return {
result: {},
showConfigButtonWithOutPermission: false,
condition: {
components: TEST_PLAN_RELEVANCE_API_SCENARIO_CONFIGS
},
currentScenario: {},
schedule: {},
selectAll: false,
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
reportId: "",
infoDb: false,
selectRows: new Set(),
projectEnvMap: new Map(),
projectList: [],
projectIds: new Set(),
map: new Map(),
customNum: false,
environmentType: ENV_TYPE.JSON,
envGroupId: "",
versionFilters: [],
};
},
computed: {
ENV_TYPE() {
return ENV_TYPE;
}
},
watch: {
selectNodeIds() {
this.search();
},
projectId() {
this.condition.versionId = null;
this.search();
this.getVersionOptions();
},
},
created() {
this.getWsProjects();
this.getVersionOptions();
},
methods: {
filterSearch() {
this.currentPage = 1;
this.search();
},
search() {
this.projectEnvMap.clear();
this.projectIds.clear();
if (!this.projectId) {
return;
}
this.getProject(this.projectId);
this.selectRows = new Set();
this.loading = true;
if (this.condition.filters) {
this.condition.filters.status = ["Prepare", "Underway", "Completed"];
} else {
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
}
this.condition.moduleIds = this.selectNodeIds;
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
if (this.planId != null) {
this.condition.planId = this.planId;
}
this.condition.stepTotal = "testPlan";
let url = "/test/plan/uiScenario/case/relevance/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.tableData.forEach(item => {
if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags);
}
});
this.clear();
});
},
clear() {
this.selectRows.clear();
},
setProjectEnvMap(projectEnvMap) {
this.projectEnvMap = projectEnvMap;
},
setEnvGroup(id) {
this.envGroupId = id;
},
getWsProjects() {
this.$get("/project/getOwnerProjects", res => {
this.projectList = res.data;
});
},
getProject(projectId) {
if (projectId) {
this.$get('/project_application/get/config/' + projectId + "/SCENARIO_CUSTOM_NUM", result => {
let data = result.data;
if (data) {
this.customNum = data.scenarioCustomNum;
}
});
}
},
initProjectIds() {
this.projectIds.clear();
this.map.clear();
this.selectRows.forEach(row => {
this.$get('/api/automation/getApiScenarioProjectId/' + row.id, res => {
let data = res.data;
data.projectIds.forEach(d => this.projectIds.add(d));
this.map.set(row.id, data.projectIds);
});
});
},
changeVersion(currentVersion) {
this.condition.versionId = currentVersion || null;
this.search();
},
getVersionOptions() {
getVersionFilters(this.projectId, (data) => {
this.versionFilters = data;
});
},
filter(field) {
this.condition.filters = field || null;
this.search();
},
selectCountChange(data) {
this.selectRows = this.$refs.scenarioTable.selectRows;
this.initProjectIds();
this.$emit("selectCountChange", data);
},
showReport() {
}
}
};
</script>
<style scoped>
/deep/ .el-drawer__header {
margin-bottom: 0px;
}
.env-popover {
float: right;
margin-top: 10px;
}
.search-input {
float: right;
width: 250px;
margin-top: 10px;
margin-bottom: 20px;
margin-right: 20px;
}
.adv-search-bar {
float: right;
margin-top: 15px;
margin-right: 10px;
}
</style>

View File

@ -34,7 +34,7 @@
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
import MsApiModule from "../../../../../api/definition/components/module/ApiModule";
import {strMapToObj} from "../../../../../../../common/js/utils";
import {getCurrentProjectID, hasLicense, strMapToObj} from "../../../../../../../common/js/utils";
import ApiCaseSimpleList from "../../../../../api/definition/components/list/ApiCaseSimpleList";
import MsApiScenarioList from "../../../../../api/automation/scenario/ApiScenarioList";
import MsApiScenarioModule from "../../../../../api/automation/scenario/ApiScenarioModule";
@ -60,7 +60,8 @@ export default {
moduleOptions: {},
trashEnable: false,
currentRow: {},
projectId: ""
projectId: "",
versionFilters: [],
};
},
props: {
@ -176,7 +177,16 @@ export default {
},
setSelectCounts(data) {
this.$refs.baseRelevance.selectCounts = data;
}
},
getVersionOptions() {
if (hasLicense()) {
this.$get('/project/version/get-project-versions/' + getCurrentProjectID(), response => {
this.versionFilters = response.data.map(u => {
return {text: u.name, value: u.id};
});
});
}
},
}
};
</script>

View File

@ -0,0 +1,189 @@
<template>
<test-case-relevance-base
@setProject="setProject"
@save="saveCaseRelevance"
:plan-id="planId"
ref="baseRelevance">
<template v-slot:aside>
<ui-scenario-module
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
:relevance-project-id="projectId"
:is-read-only="true"
ref="nodeTree"/>
</template>
<relevance-ui-scenario-list
:select-node-ids="selectNodeIds"
:trash-enable="trashEnable"
:version-enable="versionEnable"
:plan-id="planId"
:project-id="projectId"
@selectCountChange="setSelectCounts"
ref="apiScenarioList"/>
</test-case-relevance-base>
</template>
<script>
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
import {strMapToObj} from "../../../../../../../common/js/utils";
import ApiCaseSimpleList from "../../../../../api/definition/components/list/ApiCaseSimpleList";
import MsApiScenarioList from "../../../../../api/automation/scenario/ApiScenarioList";
import UiScenarioModule from "@/business/components/xpack/ui/automation/scenario/UiScenarioModule";
import RelevanceUiScenarioList from "@/business/components/track/plan/view/comonents/api/RelevanceUiScenarioList";
import {ENV_TYPE} from "@/common/js/constants";
export default {
name: "TestCaseUiScenarioRelevance",
components: {
RelevanceUiScenarioList,
MsApiScenarioList,
ApiCaseSimpleList,
UiScenarioModule,
TestCaseRelevanceBase,
},
data() {
return {
showCasePage: true,
currentProtocol: null,
currentModule: null,
selectNodeIds: [],
moduleOptions: {},
trashEnable: false,
condition: {},
currentRow: {},
projectId: ""
};
},
props: {
planId: {
type: String
},
versionEnable: {
type: Boolean,
default: false
}
},
watch: {
planId() {
this.condition.planId = this.planId;
},
},
methods: {
open() {
this.$refs.baseRelevance.open();
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.clear();
this.$refs.apiScenarioList.search();
}
},
setProject(projectId) {
this.projectId = projectId;
},
refresh(data) {
this.$refs.apiScenarioList.search(data);
},
nodeChange(node, nodeIds, pNodes) {
this.selectNodeIds = nodeIds;
},
handleProtocolChange(protocol) {
this.currentProtocol = protocol;
},
setModuleOptions(data) {
this.moduleOptions = data;
},
postRelevance() {
let url = '/ui/automation/relevance';
const envMap = this.$refs.apiScenarioList.projectEnvMap;
let envType = this.$refs.apiScenarioList.environmentType;
let map = this.$refs.apiScenarioList.map;
let envGroupId = this.$refs.apiScenarioList.envGroupId;
if (envType === ENV_TYPE.JSON && (!envMap || envMap.size < 1)) {
this.$warning(this.$t("api_test.environment.select_environment"));
return false;
} else if (envType === ENV_TYPE.GROUP && !envGroupId) {
this.$warning(this.$t("api_test.environment.select_environment"));
return false;
}
let param = {};
param.planId = this.planId;
param.mapping = strMapToObj(map);
param.envMap = strMapToObj(envMap);
param.environmentType = envType;
param.envGroupId = envGroupId;
this.result = this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('refresh');
this.refresh();
this.autoCheckStatus();
this.$refs.baseRelevance.close();
});
},
async saveCaseRelevance() {
let selectIds = [];
let url = '/ui/automation/relevance';
let selectRows = this.$refs.apiScenarioList.selectRows;
const envMap = this.$refs.apiScenarioList.projectEnvMap;
let map = this.$refs.apiScenarioList.map;
let envGroupId = this.$refs.apiScenarioList.envGroupId;
selectRows.forEach(row => {
selectIds.push(row.id);
})
let param = {};
param.planId = this.planId;
param.mapping = strMapToObj(map);
param.envMap = strMapToObj(envMap);
param.envGroupId = envGroupId;
param.selectIds = selectIds;
this.result = this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('refresh');
this.refresh();
this.autoCheckStatus();
this.$refs.baseRelevance.close();
});
},
autoCheckStatus() { //
if (!this.planId) {
return;
}
this.$post('/test/plan/autoCheck/' + this.planId, (response) => {
});
},
setSelectCounts(data) {
this.$refs.baseRelevance.selectCounts = data;
}
}
};
</script>
<style scoped>
/deep/ .select-menu {
margin-bottom: 15px;
}
/deep/ .environment-select {
float: right;
margin-right: 10px;
}
/deep/ .module-input {
width: 243px;
}
</style>

View File

@ -0,0 +1,160 @@
<template>
<ms-test-plan-common-component>
<template v-slot:aside>
<ui-scenario-module
@nodeSelectEvent="nodeChange"
@refreshTable="refreshTable"
@setModuleOptions="setModuleOptions"
:is-read-only="true"
:plan-id="planId"
:plan-status="planStatus"
ref="scenarioNodeTree">
</ui-scenario-module>
</template>
<template v-slot:main>
<!--测试用例列表-->
<ms-test-plan-ui-scenario-list
:select-node-ids="selectNodeIds"
:trash-enable="trashEnable"
:version-enable="versionEnable"
:plan-id="planId"
:plan-status="planStatus"
:clickType="clickType"
@refresh="refreshTree"
@relevanceCase="openTestCaseRelevanceDialog"
ref="apiScenarioList"/>
</template>
<test-case-ui-scenario-relevance
@refresh="refresh"
:plan-id="planId"
:model="model"
:version-enable="versionEnable"
ref="scenarioCaseRelevance"/>
</ms-test-plan-common-component>
</template>
<script>
import NodeTree from "../../../../common/NodeTree";
import MsTestPlanCommonComponent from "../base/TestPlanCommonComponent";
import TestPlanApiCaseList from "./TestPlanApiCaseList";
import TestCaseApiRelevance from "./TestCaseApiRelevance";
import ApiCaseSimpleList from "../../../../../api/definition/components/list/ApiCaseSimpleList";
import MsApiModule from "../../../../../api/definition/components/module/ApiModule";
import MsTestPlanUiScenarioList from "./TestPlanUiScenarioList";
import UiScenarioModule from "@/business/components/xpack/ui/automation/scenario/UiScenarioModule";
import TestCaseUiScenarioRelevance
from "@/business/components/track/plan/view/comonents/api/TestCaseUiScenarioRelevance";
export default {
name: "TestPlanUi",
components: {
TestCaseUiScenarioRelevance,
MsTestPlanUiScenarioList,
UiScenarioModule,
MsApiModule,
ApiCaseSimpleList,
TestCaseApiRelevance,
TestPlanApiCaseList,
MsTestPlanCommonComponent,
NodeTree,
},
data() {
return {
result: {},
treeNodes: [],
currentRow: "",
trashEnable: false,
currentProtocol: null,
currentModule: null,
selectNodeIds: [],
moduleOptions: {},
model: 'scenario'
}
},
props: [
'planId',
'redirectCharType',
'clickType',
'versionEnable',
'planStatus'
],
mounted() {
this.checkRedirectCharType();
},
watch: {
model() {
this.selectNodeIds = [];
this.moduleOptions = {};
},
redirectCharType(){
if(this.redirectCharType=='scenario'){
this.model = 'scenario';
}else{
this.model = 'api';
}
}
},
methods: {
checkRedirectCharType(){
if(this.redirectCharType=='scenario'){
this.model = 'scenario';
}else{
this.model = 'api';
}
},
refresh() {
this.refreshTree();
this.refreshTable();
},
refreshTable() {
if (this.$refs.apiCaseList) {
this.$refs.apiCaseList.initTable();
}
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.search();
}
},
refreshTree() {
if (this.$refs.scenarioNodeTree) {
this.$refs.scenarioNodeTree.list();
}
},
nodeChange(node, nodeIds, pNodes) {
this.selectNodeIds = nodeIds;
},
handleProtocolChange(protocol) {
this.currentProtocol = protocol;
},
setModuleOptions(data) {
this.moduleOptions = data;
},
openTestCaseRelevanceDialog(model) {
if (model === 'scenario') {
this.$refs.scenarioCaseRelevance.open();
} else {
this.$refs.apiCaseRelevance.open();
}
},
}
}
</script>
<style scoped>
.model-change-radio {
height: 25px;
line-height: 25px;
margin: 5px 10px;
}
</style>

View File

@ -0,0 +1,626 @@
<template>
<div class="card-container">
<el-card class="card-content" v-loading="loading">
<template v-slot:header>
<test-plan-scenario-list-header
:condition="condition"
:projectId="projectId"
:plan-status="planStatus"
@refresh="filterSearch"
@relevanceCase="$emit('relevanceCase', 'scenario')"/>
</template>
<ms-table
:data="tableData"
:condition="condition"
:total="total"
:page-size.sync="pageSize"
:operators="operators"
:screen-height="screenHeight"
:batch-operators="buttons"
@handlePageChange="search"
:fields.sync="fields"
:field-key="tableHeaderKey"
:enable-order-drag="enableOrderDrag"
row-key="id"
:row-order-func="editTestPlanScenarioCaseOrder"
:row-order-group-id="planId"
@order="search"
@filter="filterSearch"
ref="table">
<span v-for="(item) in fields" :key="item.key">
<ms-table-column
v-if="item.id == 'num'"
:fields-width="fieldsWidth"
sortable
prop="customNum"
min-width="80px"
label="ID"/>
<ms-table-column :field="item"
:fields-width="fieldsWidth"
prop="name"
:label="$t('api_test.automation.scenario_name')" min-width="120px"
sortable/>
<ms-table-column :field="item"
:fields-width="fieldsWidth"
prop="level" :label="$t('api_test.automation.case_level')" min-width="120px"
column-key="level"
sortable
:filters="apiscenariofilters.LEVEL_FILTERS">
<template v-slot:default="scope">
<priority-table-item :value="scope.row.level" ref="level"/>
</template>
</ms-table-column>
<ms-table-column
:field="item"
:fields-width="fieldsWidth"
prop="envs"
:label="$t('commons.environment')"
min-width="150">
<template v-slot:default="{row}">
<div v-if="row.envs">
<span v-for="(k, v, index) in row.envs" :key="index">
<span v-if="index===0 || index===1">
<span class="project-name" :title="v">{{v}}</span>:
<el-tag type="success" size="mini" effect="plain">
{{k}}
</el-tag>
<br/>
</span>
<el-popover
placement="top"
width="350"
trigger="click">
<div v-for="(k, v, index) in row.envs" :key="index">
<span class="plan-case-env">{{v}}:
<el-tag type="success" size="mini" effect="plain">{{k}}</el-tag><br/>
</span>
</div>
<el-link v-if="index === 2" slot="reference" type="info" :underline="false" icon="el-icon-more"/>
</el-popover>
</span>
</div>
</template>
</ms-table-column>
<ms-table-column :field="item"
:fields-width="fieldsWidth"
prop="tagNames" :label="$t('api_test.automation.tag')"
min-width="100px">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:content="itemName" style="margin-left: 0px; margin-right: 2px"/>
</template>
</ms-table-column>
<ms-table-column :field="item"
:fields-width="fieldsWidth"
prop="createUser"
:label="$t('api_test.automation.creator')"
min-width="100px">
<template v-slot:default="scope">
{{scope.row.creatorName}}
</template>
</ms-table-column>
<ms-table-column
v-if="item.id == 'maintainer'"
prop="userId"
:fields-width="fieldsWidth"
:label="$t('custom_field.case_maintainer')"
min-width="120">
<template v-slot:default="scope">
{{scope.row.principalName}}
</template>
</ms-table-column>
<ms-table-column
:field="item"
:fields-width="fieldsWidth"
prop="principal"
:label="$t('custom_field.case_maintainer')"
min-width="120"/>
<ms-update-time-column :field="item" :fields-width="fieldsWidth"/>
<ms-create-time-column :field="item" :fields-width="fieldsWidth"/>
<ms-table-column :field="item"
:fields-width="fieldsWidth"
prop="stepTotal" :label="$t('api_test.automation.step')"
min-width="80px"/>
<ms-table-column :field="item"
:fields-width="fieldsWidth"
prop="lastResult" min-width="100px"
:filters="apiscenariofilters.RESULT_FILTERS"
:label="$t('api_test.automation.last_result')">
<template v-slot:default="{row}">
<el-link type="success" @click="showReport(row)" v-if="row.lastResult === 'Success'">
{{ $t('api_test.automation.success') }}
</el-link>
<el-link type="danger" @click="showReport(row)" v-if="row.lastResult === 'Fail'">
{{ $t('api_test.automation.fail') }}
</el-link>
<el-link type="danger" @click="showReport(row)" v-if="row.lastResult === 'Error'">
{{ $t('api_test.automation.fail') }}
</el-link>
<el-link style="color: #F6972A" @click="showReport(row)" v-if="row.lastResult === 'errorReportResult'">
{{ $t('error_report_library.option.name') }}
</el-link>
</template>
</ms-table-column>
<ms-table-column :field="item"
:fields-width="fieldsWidth"
prop="passRate" min-width="80px"
:label="$t('api_test.automation.passing_rate')"/>
</span>
</ms-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
<div>
<!-- 执行结果 -->
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="true" :modal="false"
size="90%">
<ms-api-report-detail @invisible="runVisible = false" @refresh="search" :infoDb="infoDb" :report-id="reportId" :currentProjectId="projectId"/>
</el-drawer>
</div>
</el-card>
<!-- 批量编辑 -->
<batch-edit :dialog-title="$t('test_track.case.batch_edit_case')" :type-arr="typeArr" :value-arr="valueArr"
:select-row="this.$refs.table ? this.$refs.table.selectRows : new Set()" ref="batchEdit" @batchEdit="batchEdit"/>
<!-- <ui-run-mode-->
<!-- :type="'apiScenario'"-->
<!-- :plan-case-ids="planCaseIds"-->
<!-- @close="search"-->
<!-- @handleRunBatch="handleRunBatch"-->
<!-- ref="runMode"/>-->
<!-- <ms-plan-run-mode-->
<!-- :type="'apiScenario'"-->
<!-- :plan-case-ids="planCaseIds"-->
<!-- @close="search"-->
<!-- @handleRunBatch="handleRunBatch"-->
<!-- ref="runMode"/>-->
<ui-run-mode @handleRunBatch="handleRunBatch" ref="runMode"/>
<ms-task-center ref="taskCenter" :show-menu="false"/>
</div>
</template>
<script>
import MsTableHeader from "@/business/components/common/components/MsTableHeader";
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import MsTag from "../../../../../common/components/MsTag";
import {getCurrentProjectID, getUUID, hasLicense, strMapToObj} from "@/common/js/utils";
import MsApiReportDetail from "../../../../../api/automation/report/ApiReportDetail";
import MsTableMoreBtn from "../../../../../api/automation/scenario/TableMoreBtn";
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
import MsTestPlanList from "../../../../../api/automation/scenario/testplan/TestPlanList";
import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader";
import MsPlanRunMode from "@/business/components/track/plan/common/PlanRunModeWithEnv";
import {
initCondition,
buildBatchParam, getCustomTableHeader, getCustomTableWidth
} from "../../../../../../../common/js/tableUtils";
import {ENV_TYPE, TEST_PLAN_SCENARIO_CASE} from "@/common/js/constants";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import BatchEdit from "@/business/components/track/case/components/BatchEdit";
import PriorityTableItem from "@/business/components/track/common/tableItems/planview/PriorityTableItem";
import {API_SCENARIO_FILTERS} from "@/common/js/table-constants";
import MsTaskCenter from "../../../../../task/TaskCenter";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsUpdateTimeColumn from "@/business/components/common/components/table/MsUpdateTimeColumn";
import MsCreateTimeColumn from "@/business/components/common/components/table/MsCreateTimeColumn";
import {editTestPlanScenarioCaseOrder} from "@/network/test-plan";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const UiRunMode = requireComponent.keys().length > 0 ? requireComponent("./ui/automation/scenario/component/UiRunMode.vue") : {};
export default {
name: "MsTestPlanUiScenarioList",
components: {
MsCreateTimeColumn,
MsUpdateTimeColumn,
MsTableColumn,
MsTable,
PriorityTableItem,
HeaderLabelOperate,
TestPlanScenarioListHeader,
MsTablePagination,
MsTableMoreBtn,
MsTableHeader,
MsTag,
MsApiReportDetail,
MsScenarioExtendButtons,
MsTestPlanList,
BatchEdit,
"UiRunMode" : UiRunMode.default,
MsTaskCenter,
MsPlanRunMode
},
props: {
referenced: {
type: Boolean,
default: false,
},
selectNodeIds: Array,
reviewId: String,
planId: String,
planStatus: String,
clickType: String,
versionEnable: Boolean,
},
data() {
return {
type: TEST_PLAN_SCENARIO_CASE,
tableHeaderKey:"TEST_PLAN_SCENARIO_CASE",
fields: getCustomTableHeader('TEST_PLAN_SCENARIO_CASE'),
fieldsWidth: getCustomTableWidth('TEST_PLAN_SCENARIO_CASE'),
screenHeight: 'calc(100vh - 250px)',//
tableLabel: [],
loading: false,
condition: {},
currentScenario: {},
schedule: {},
selectAll: false,
tableData: [],
currentPage: 1,
selectDataCounts: 0,
pageSize: 10,
total: 0,
reportId: "",
status: 'default',
infoDb: false,
runVisible: false,
runData: [],
enableOrderDrag: true,
operators: [
{
tip: this.$t('api_test.run'), icon: "el-icon-video-play",
exec: this.execute,
class: this.planStatus==='Archived'?'disable-run':'run-button',
isDisable: this.planStatus==='Archived',
permissions: ['PROJECT_TRACK_PLAN:READ+RUN']
},
{
tip: this.$t('test_track.plan_view.cancel_relevance'), icon: "el-icon-unlock",
exec: this.remove,
type: 'danger',
isDisable: this.planStatus==='Archived',
permissions: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']
}
],
buttons: [
{
name: this.$t('test_track.case.batch_unlink'), handleClick: this.handleDeleteBatch, isDisable: this.planStatus==='Archived', permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_DELETE']
},
{
name: this.$t('api_test.automation.batch_execute'), handleClick: this.handleBatchExecute, isDisable: this.planStatus==='Archived', permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_RUN']
},
{
name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleBatchEdit, isDisable: this.planStatus==='Archived', permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_EDIT']
}
],
typeArr: [
{id: 'projectEnv', name: this.$t('api_test.definition.request.run_env')},
],
valueArr: {
projectEnv: []
},
planCaseIds: [],
apiscenariofilters:{},
versionFilters: [],
}
},
computed: {
projectId() {
return getCurrentProjectID();
},
editTestPlanScenarioCaseOrder() {
return editTestPlanScenarioCaseOrder;
}
},
created() {
this.apiscenariofilters = API_SCENARIO_FILTERS();
this.search();
this.getVersionOptions();
},
watch: {
selectNodeIds() {
this.condition.selectAll = false;
this.search();
},
planId() {
this.search();
}
},
methods: {
filterSearch() {
//
this.currentPage = 1;
this.search();
},
search() {
initCondition(this.condition,this.condition.selectAll);
this.loading = true;
this.condition.moduleIds = this.selectNodeIds;
if (this.clickType) {
if (this.status == 'default') {
this.condition.status = this.clickType;
} else {
this.condition.status = null;
}
this.status = 'all';
}
this.enableOrderDrag = (this.condition.orders && this.condition.orders.length) > 0 ? false : true;
if (this.planId) {
this.condition.planId = this.planId;
let url = "/test/plan/uiScenario/case/list/" + this.currentPage + "/" + this.pageSize;
this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.tableData.forEach(item => {
if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags);
}
});
this.tableData.forEach(item => {
try {
let envs;
const type = item.environmentType;
if (type === ENV_TYPE.GROUP && item.environmentGroupId) {
this.$get("/environment/group/project/map/name/" + item.environmentGroupId, res => {
let data = res.data;
if (data) {
envs = new Map(Object.entries(data));
this.$set(item, 'envs', res.data);
}
})
} else if (type === ENV_TYPE.JSON) {
envs = JSON.parse(item.environment);
if (envs) {
this.$post("/test/plan/uiScenario/case/env", envs, res => {
this.$set(item, 'envs', res.data);
});
}
}
} catch (error) {
this.$set(item, 'envs', {});
}
})
this.loading = false;
});
}
if (this.reviewId) {
this.condition.reviewId = this.reviewId;
let url = "/test/case/review/uiScenario/case/list/" + this.currentPage + "/" + this.pageSize;
this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.tableData.forEach(item => {
if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags);
}
});
this.loading = false;
});
}
},
reductionApi(row) {
row.scenarioDefinition = null;
let rows = [row];
this.$post("/api/automation/reduction", rows, response => {
this.$success(this.$t('commons.save_success'));
this.search();
})
},
handleBatchExecute() {
let rows = this.orderBySelectRows(this.$refs.table.selectRows);
this.planCaseIds = [];
rows.forEach(row => {
this.planCaseIds.push(row.id);
})
this.$refs.runMode.open();
},
orderBySelectRows(rows){
let selectIds = Array.from(rows).map(row => row.id);
let array = [];
for(let i in this.tableData){
if(selectIds.indexOf(this.tableData[i].id)!==-1){
array.push(this.tableData[i]);
}
}
return array;
},
handleRunBatch(config){
let rows = this.orderBySelectRows(this.$refs.table.selectRows);
if (this.reviewId) {
let param = {config : config,planCaseIds:[]};
rows.forEach(row => {
this.buildExecuteParam(param,row);
});
this.$post("/test/case/review/uiScenario/case/run", param, response => {
this.$message(this.$t('commons.run_message'));
this.$refs.taskCenter.open();
});
}
if (this.planId) {
let selectParam = buildBatchParam(this);
let param = {config: config, planCaseIds: []};
param.ids = rows.map(r => r.id);
rows.forEach(row => {
this.buildExecuteParam(param, row);
});
param.condition = selectParam.condition;
param.triggerMode = "BATCH";
param.requestOriginator = "TEST_PLAN";
this.$post("/test/plan/uiScenario/case/run", param, response => {
this.$message(this.$t('commons.run_message'));
this.$refs.taskCenter.open();
this.search();
}, () => {
this.search();
});
}
},
execute(row) {
this.infoDb = false;
let param ={planCaseIds: []};
this.reportId = "";
this.buildExecuteParam(param,row);
param.triggerMode = "MANUAL";
param.requestOriginator = "TEST_PLAN";
param.config = {
mode: "serial"
};
if (this.planId) {
this.$post("/test/plan/uiScenario/case/run", param, response => {
this.runVisible = true;
if (response.data && response.data.length > 0) {
this.reportId = response.data[0].reportId;
}
});
}
if (this.reviewId) {
this.$post("/test/case/review/uiScenario/case/run", param, response => {
this.runVisible = true;
this.reportId = response.data;
});
}
},
buildExecuteParam(param,row) {
// param.id = row.id;
param.id = getUUID();
param.planScenarioId = row.id;
param.projectId = row.projectId;
param.planCaseIds.push(row.id);
return param;
},
showReport(row) {
this.runVisible = true;
this.infoDb = true;
this.reportId = row.reportId;
},
remove(row) {
if (this.planId) {
this.$get('/test/plan/uiScenario/case/delete/' + row.id, () => {
this.$success(this.$t('test_track.cancel_relevance_success'));
this.$emit('refresh');
this.search();
});
}
if (this.reviewId) {
this.$get('/test/case/review/uiScenario/case/delete/' + row.id, () => {
this.$success(this.$t('test_track.cancel_relevance_success'));
this.$emit('refresh');
this.search();
});
}
return;
},
handleDeleteBatch() {
this.$alert(this.$t('test_track.plan_view.confirm_cancel_relevance') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let param = buildBatchParam(this);
param.ids = this.$refs.table.selectIds;
if (this.planId) {
param.planId = this.planId;
this.$post('/test/plan/uiScenario/case/batch/delete', param, () => {
this.$refs.table.selectRows.clear();
this.search();
this.$success(this.$t('test_track.cancel_relevance_success'));
this.$emit('refresh');
});
}
if (this.reviewId) {
param.reviewId = this.reviewId;
this.$post('/test/case/review/uiScenario/case/batch/delete', param, () => {
this.$refs.table.selectRows.clear();
this.search();
this.$success(this.$t('test_track.cancel_relevance_success'));
this.$emit('refresh');
});
}
}
}
});
},
handleBatchEdit() {
if (this.condition != null && this.condition.selectAll) {
let selectAllRowParams = buildBatchParam(this);
selectAllRowParams.ids = this.$refs.table.selectIds;
this.$post('/test/plan/uiScenario/case/selectAllTableRows', selectAllRowParams, response => {
let dataRows = response.data;
this.$refs.batchEdit.open(dataRows.size);
this.$refs.batchEdit.setScenarioSelectRows(dataRows, "planScenario");
});
} else {
this.$refs.batchEdit.open(this.$refs.table.selectRows.size);
this.$refs.batchEdit.setScenarioSelectRows(this.$refs.table.selectRows, "planScenario");
}
},
batchEdit(form) {
let param = {};
param.mapping = strMapToObj(form.map);
param.envMap = strMapToObj(form.projectEnvMap);
param.environmentType = form.environmentType;
param.envGroupId = form.envGroupId;
if (this.planId) {
this.$post('/test/plan/uiScenario/case/batch/update/env', param, () => {
this.$success(this.$t('commons.save_success'));
this.search();
});
}
},
getVersionOptions() {
if (hasLicense()) {
this.$get('/project/version/get-project-versions/' + getCurrentProjectID(), response => {
this.versionFilters = response.data.map(u => {
return {text: u.name, value: u.id};
});
});
}
},
}
}
</script>
<style scoped>
/*/deep/ .el-drawer__header {*/
/* margin-bottom: 0px;*/
/*}*/
.plan-case-env {
display: inline-block;
padding: 0 0;
max-width: 350px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 2px;
margin-left: 5px;
}
.project-name {
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 80px;
vertical-align: middle;
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<ms-table-header
:condition="condition"
@search="$emit('refresh')"
:show-create="false"
:tip="$t('commons.search_by_id_name_tag')">
<template v-slot:title>
场景用例
</template>
<template v-slot:button>
<ms-table-button v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" icon="el-icon-connection"
:content="$t('test_track.plan_view.relevance_test_case')" :disabled="planStatus==='Archived'"
@click="$emit('relevanceCase')"/>
</template>
</ms-table-header>
</template>
<script>
import MsTableHeader from "../../../../../common/components/MsTableHeader";
import MsTableButton from "../../../../../common/components/MsTableButton";
import MsEnvironmentSelect from "../../../../../api/definition/components/case/MsEnvironmentSelect";
export default {
name: "TestPlanUiScenarioListHeader",
components: {
MsEnvironmentSelect, MsTableButton, MsTableHeader
},
props: ['condition', 'isReadOnly', 'projectId', 'planStatus'],
methods: {}
};
</script>
<style scoped>
/deep/ .environment-select {
margin-right: 10px;
}
</style>

View File

@ -13,6 +13,8 @@
:is-template="isTemplate" :report="report" :plan-id="planId"/>
<test-plan-load-report v-if="loadEnable" :is-db="isDb" :share-id="shareId" :is-share="isShare"
:is-template="isTemplate" :report="report" :plan-id="planId"/>
<test-plan-ui-report v-if="uiEnable" :is-db="false" :share-id="shareId" :is-share="isShare"
:is-template="isTemplate" :report="report" :plan-id="planId"/>
</el-card>
</ms-main-container>
<test-plan-report-navigation-bar
@ -29,12 +31,14 @@
import TestPlanFunctionalReport
from "@/business/components/track/plan/view/comonents/report/detail/TestPlanFunctionalReport";
import {
getExportReport,
getShareTestPlanReport,
getShareTestPlanReportContent,
getTestPlanReport,
getTestPlanReportContent
} from "@/network/test-plan";
import TestPlanApiReport from "@/business/components/track/plan/view/comonents/report/detail/TestPlanApiReport";
import TestPlanUiReport from "@/business/components/track/plan/view/comonents/report/detail/TestPlanUiReport";
import TestPlanLoadReport from "@/business/components/track/plan/view/comonents/report/detail/TestPlanLoadReport";
import TestPlanReportContainer
from "@/business/components/track/plan/view/comonents/report/detail/TestPlanReportContainer";
@ -46,7 +50,6 @@ import TestPlanReportNavigationBar
from "@/business/components/track/plan/view/comonents/report/detail/TestPlanReportNavigationBar";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
export default {
name: "TestPlanReportContent",
components: {
@ -60,6 +63,7 @@ export default {
TestPlanLoadReport,
TestPlanApiReport,
TestPlanFunctionalReport,
TestPlanUiReport,
},
props: {
planId: String,
@ -121,6 +125,11 @@ export default {
let disable = this.report.config && this.report.config.load.enable === false;
return !disable && this.report.loadResult
&& this.report.loadResult.caseData && this.report.loadResult.caseData.length > 0;
},
uiEnable() {
let disable = this.report.config && this.report.config.ui.enable === false;
return !disable && this.report.uiResult
&& this.report.uiResult.uiScenarioStepData && this.report.uiResult.uiScenarioStepData.length > 0;
}
},
methods: {
@ -246,7 +255,33 @@ export default {
name: this.$t('test_track.report.all_case'),
}
}
}
},
ui: {
enable: true,
name: this.$t('test_track.report.analysis_api'),
children: {
result: {
enable: true,
name: this.$t('test_track.report.test_result'),
},
failure: {
enable: true,
name: this.$t('test_track.report.fail_case'),
},
errorReport: {
enable: true,
name: this.$t('error_report_library.option.name'),
},
unExecute: {
enable: true,
name: this.$t('api_test.home_page.detail_card.unexecute'),
},
all: {
enable: true,
name: this.$t('test_track.report.all_case'),
}
}
},
};
if (dbConfig) {
this.mergeConfig(config, dbConfig);

View File

@ -0,0 +1,206 @@
<template>
<test-plan-report-container id="ui" :title="$t('test_track.report.analysis_ui')">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane v-if="resultEnable" :label="$t('test_track.report.test_result')" name="first">
<ui-result :api-result="report.uiResult"/>
</el-tab-pane>
<el-tab-pane v-if="failureEnable" name="second">
<template v-slot:label>
<tab-pane-count :title="$t('test_track.report.fail_case')" :count="failureSize"/>
</template>
<api-cases :is-db="isDb" :share-id="shareId" :is-share="isShare" :report="report" :is-template="isTemplate"
:plan-id="planId" @setSize="setFailureSize" :is-ui="true"/>
<el-button class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0) && isRerun" @click="rerun">
{{ $t('api_test.automation.rerun') }}
</el-button>
</el-tab-pane>
<el-tab-pane style="min-height: 500px" name="fourth" v-if="unExecuteEnable">
<template v-slot:label>
<tab-pane-count :title="$t('api_test.home_page.detail_card.unexecute')" :count="unExecuteSize"/>
</template>
<api-cases :is-db="isDb" :is-un-execute="true" :share-id="shareId" :is-share="isShare" :report="report"
:is-template="isTemplate" :plan-id="planId" @setSize="setUnExecuteSize" :is-ui="true"/>
<el-button class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0) && isRerun" @click="rerun">
{{ $t('api_test.automation.rerun') }}
</el-button>
</el-tab-pane>
<el-tab-pane style="min-height: 500px" name="fifth" v-if="allEnable">
<template v-slot:label>
<tab-pane-count :title="$t('test_track.report.all_case')" :count="allSize"/>
</template>
<api-cases :is-db="isDb" :is-all="true" :share-id="shareId" :is-share="isShare" :report="report"
:is-template="isTemplate" :plan-id="planId" @setSize="setAllSize" :is-ui="true"/>
<el-button class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0) && isRerun" @click="rerun">
{{ $t('api_test.automation.rerun') }}
</el-button>
</el-tab-pane>
</el-tabs>
</test-plan-report-container>
</template>
<script>
import MsFormDivider from "@/business/components/common/components/MsFormDivider";
import UiResult from "@/business/components/track/plan/view/comonents/report/detail/component/UiResult";
import TestPlanReportContainer
from "@/business/components/track/plan/view/comonents/report/detail/TestPlanReportContainer";
import ApiCases from "@/business/components/track/plan/view/comonents/report/detail/component/ApiCases";
import TabPaneCount from "@/business/components/track/plan/view/comonents/report/detail/component/TabPaneCount";
import {hasLicense} from "@/common/js/utils";
export default {
name: "TestPlanUiReport",
components: {TabPaneCount, ApiCases, TestPlanReportContainer, UiResult, MsFormDivider},
data() {
return {
activeName: 'first',
failureSize: 0,
errorReportSize: 0,
unExecuteSize: 0,
allSize: 0,
showRerunBtn: true,
};
},
created() {
this.showRerunBtn = !this.isShare && hasLicense();
},
props: [
'report', 'planId', 'isTemplate', 'isShare', 'shareId', 'isDb'
],
computed: {
resultEnable() {
let disable = this.report.config && this.report.config.ui.children.result.enable === false;
return !disable;
},
failureEnable() {
let disable = this.report.config && this.report.config.ui.children.failure.enable === false;
return !disable;
},
errorReportEnable() {
let disable = this.report.config && this.report.config.ui.children.errorReport && this.report.config.ui.children.errorReport.enable === false;
return !disable;
},
unExecuteEnable() {
let disable = this.report.config && this.report.config.ui.children.unExecute && this.report.config.ui.children.unExecute.enable === false;
return !disable;
},
allEnable() {
let disable = this.report.config && this.report.config.ui.children.all.enable === false;
return !disable;
},
isRerun() {
return ((this.report && this.report.apiFailureCases)
|| (this.report && this.report.unExecuteCases)
|| (this.report && this.report.scenarioFailureCases)
|| (this.report && this.report.unExecuteScenarios)
|| (this.report && this.report.loadFailureCases));
}
},
watch: {
resultEnable() {
this.initActiveName();
},
failureEnable() {
this.initActiveName();
},
errorReportEnable() {
this.initActiveName();
},
allEnable() {
this.initActiveName();
},
},
mounted() {
this.initActiveName();
},
methods: {
initActiveName() {
if (this.resultEnable) {
this.activeName = 'first';
} else if (this.failureEnable) {
this.activeName = 'second';
} else if (this.errorReportEnable) {
this.activeName = 'third';
} else if (this.allEnable) {
this.activeName = 'fourth';
}
},
setFailureSize(size) {
this.failureSize = size;
},
setErrorReportSize(size) {
this.errorReportSize = size;
},
setUnExecuteSize(size) {
this.unExecuteSize = size;
},
setAllSize(size) {
this.allSize = size;
},
handleClick(tab, event) {
},
rerun() {
let type = "TEST_PLAN";
let scenarios = [];
let cases = [];
let performanceCases = [];
let rerunObj = {
type: type,
reportId: this.report.id,
scenarios: scenarios,
cases: cases,
performanceCases: performanceCases
}
//
if (this.report && this.report.apiFailureCases) {
this.format(cases, this.report.apiFailureCases);
}
if (this.report && this.report.unExecuteCases) {
this.format(cases, this.report.unExecuteCases);
}
//
if (this.report && this.report.scenarioFailureCases) {
this.format(scenarios, this.report.scenarioFailureCases);
}
if (this.report && this.report.unExecuteScenarios) {
this.format(scenarios, this.report.unExecuteScenarios);
}
//
if (this.report && this.report.loadFailureCases) {
this.format(performanceCases, this.report.loadFailureCases);
}
this.$post('/ui/test/exec/rerun', rerunObj, res => {
if (res.data !== 'SUCCESS') {
this.$error(res.data);
} else {
this.$success(this.$t('api_test.automation.rerun_success'));
}
});
},
format(cases, datas) {
if (this.report && datas) {
datas.forEach(item => {
if (item) {
let obj = {id: item.id, reportId: item.reportId, userId: item.createUser};
cases.push(obj);
}
});
}
}
}
}
</script>
<style scoped>
.rerun-button {
position: absolute;
top: 10px;
right: 10px;
margin-right: 10px;
z-index: 1100;
background-color: #F2F9EF;
color: #87C45D;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div>
<el-tabs type="card">
<el-tab-pane>
<el-tab-pane v-if="!isUi">
<template v-slot:label>
<tab-pane-count :title="$t('commons.api_case')" :count="apiSize"/>
</template>
@ -12,7 +12,7 @@
<template v-slot:label>
<tab-pane-count :title="$t('commons.scenario_case')" :count="scenarioSize"/>
</template>
<api-scenario-failure-result :is-db="isDb" :is-all="isAll" :is-error-report="isErrorReport" :is-un-execute="isUnExecute" :share-id="shareId" :is-share="isShare"
<api-scenario-failure-result :is-ui="isUi" :is-db="isDb" :is-all="isAll" :is-error-report="isErrorReport" :is-un-execute="isUnExecute" :share-id="shareId" :is-share="isShare"
:report="report" :is-template="isTemplate" :plan-id="planId"
@setSize="setScenarioSize"/>
</el-tab-pane>
@ -47,7 +47,8 @@ export default {
isAll: Boolean,
isErrorReport: Boolean,
isUnExecute:Boolean,
isDb: Boolean
isDb: Boolean,
isUi: Boolean,
},
data() {
return {

View File

@ -83,7 +83,13 @@ import {
getSharePlanScenarioAllCase,
getSharePlanScenarioFailureCase,
getPlanScenarioErrorReportCase,
getSharePlanScenarioErrorReportCase, getPlanScenarioUnExecuteCase, getSharePlanScenarioUnExecuteCase,
getSharePlanScenarioErrorReportCase,
getPlanScenarioUnExecuteCase,
getSharePlanScenarioUnExecuteCase,
getPlanUiScenarioErrorReportCase,
getPlanUiScenarioFailureCase,
getPlanUiScenarioUnExecuteCase,
getPlanUiScenarioAllCase,
} from "@/network/test-plan";
import MsTable from "@/business/components/common/components/table/MsTable";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
@ -108,7 +114,8 @@ export default {
isAll: Boolean,
isErrorReport: Boolean,
isUnExecute: Boolean,
isDb: Boolean
isDb: Boolean,
isUi: Boolean,
},
data() {
return {
@ -159,6 +166,24 @@ export default {
this.scenarioCases = data;
});
}
} else if (this.isUi) {
if (this.isErrorReport) {
this.result = getPlanUiScenarioErrorReportCase(this.planId, (data) => {
this.scenarioCases = data;
});
} else if (this.isUnExecute) {
this.result = getPlanUiScenarioUnExecuteCase(this.planId, (data) => {
this.scenarioCases = data;
});
} else if (this.isAll) {
this.result = getPlanUiScenarioAllCase(this.planId, (data) => {
this.scenarioCases = data;
});
} else {
this.result = getPlanUiScenarioFailureCase(this.planId, (data) => {
this.scenarioCases = data;
});
}
} else {
if (this.isErrorReport) {
this.result = getPlanScenarioErrorReportCase(this.planId, (data) => {

View File

@ -0,0 +1,109 @@
<template>
<div>
<el-row >
<el-col :span="12" v-if="caseCharData && caseCharData.length > 0">
<ms-doughnut-pie-chart style="margin-right: 200px" :name="$t('api_test.home_page.ui_details_card.scenario_cases')" :data="caseCharData" ref="functionChar"/>
</el-col>
<el-col :span="12" v-if="scenarioCharData && scenarioCharData.length > 0">
<!-- <api-scenario-char-result :name="$t('test_track.plan.test_plan_api_scenario_count')" :data="scenarioCharData"/>-->
<api-scenario-char-result style="margin-top: -50px;" :name="$t('api_test.home_page.ui_details_card.step_count')" :data="stepCharData"/>
</el-col>
</el-row>
</div>
</template>
<script>
import MsPieChart from "@/business/components/common/components/MsPieChart";
import MsDoughnutPieChart from "@/business/components/common/components/MsDoughnutPieChart";
import ApiScenarioCharResult
from "@/business/components/track/plan/view/comonents/report/detail/component/ApiScenarioCharResult";
export default {
name: "UiResult",
components: {ApiScenarioCharResult, MsDoughnutPieChart, MsPieChart},
data() {
return {
caseDataMap: new Map([
["success", {name: this.$t('test_track.plan_view.pass'), itemStyle: {color: '#67C23A'}}],
["Success", {name: this.$t('test_track.plan_view.pass'), itemStyle: {color: '#67C23A'}}],
["Pass", {name: this.$t('test_track.plan_view.pass'), itemStyle: {color: '#67C23A'}}],
["error", {name: this.$t('test_track.plan_view.failure'), itemStyle: {color: '#F56C6C'}}],
["Error", {name: this.$t('test_track.plan_view.failure'), itemStyle: {color: '#F56C6C'}}],
["Fail", {name: this.$t('test_track.plan_view.failure'), itemStyle: {color: '#F56C6C'}}],
["Failure", {name: this.$t('test_track.plan_view.failure'), itemStyle: {color: '#F56C6C'}}],
["Prepare", {name: this.$t('api_test.home_page.detail_card.unexecute'), itemStyle: {color: '#909399'}}],
["Underway", {name: this.$t('api_test.home_page.detail_card.unexecute'), itemStyle: {color: '#909399'}}],
["errorReportResult", {name: this.$t('error_report_library.option.name'), itemStyle: {color: '#F6972A'}}],
]),
caseCharData: [],
scenarioCharData: [],
stepCharData: [],
isShow: true
}
},
props: {
apiResult: {
type: Object,
default() {
return {
caseData: [],
issueData: []
}
}
}
},
watch: {
apiResult() {
this.getCaseCharData();
}
},
created() {
this.getCaseCharData();
},
methods: {
getCaseCharData() {
let caseCharData = [];
if (this.apiResult.uiScenarioData) {
this.apiResult.uiScenarioData.forEach(item => {
let data = this.getDataByStatus(item.status);
data.value = item.count;
caseCharData.push(data);
});
}
this.caseCharData = caseCharData;
let uiScenarioData = [];
if (this.apiResult.uiScenarioData) {
this.apiResult.uiScenarioData.forEach(item => {
let data = this.getDataByStatus(item.status);
data.value = item.count;
uiScenarioData.push(data);
});
}
let stepCharData = [];
for (let i = 0; i < this.apiResult.uiScenarioStepData.length; i++) {
let stepItem = this.apiResult.uiScenarioStepData[i];
let data = this.getDataByStatus(stepItem.status);
data.value = stepItem.count;
stepCharData.push(data);
}
this.scenarioCharData = uiScenarioData;
this.stepCharData = stepCharData;
},
getDataByStatus(status) {
let tmp = this.caseDataMap.get(status);
if (!tmp) {
tmp = this.caseDataMap.get('Prepare');
}
let data = {};
Object.assign(data, tmp);
return data;
}
}
}
</script>
<style scoped>
</style>

View File

@ -139,6 +139,7 @@ export let CUSTOM_TABLE_HEADER = {
{id: 'testPlanTestCaseCount', key: 'g', label: 'test_track.plan.test_plan_test_case_count'},
{id: 'testPlanApiCaseCount', key: 'h', label: 'test_track.plan.test_plan_api_case_count'},
{id: 'testPlanApiScenarioCount', key: 'i', label: 'test_track.plan.test_plan_api_scenario_count'},
{id: 'testPlanUiScenarioCount', key: 'i', label: 'test_track.plan.test_plan_ui_scenario_count'},
{id: 'testPlanLoadCaseCount', key: 'j', label: 'test_track.plan.test_plan_load_case_count'},
{id: 'principalName', key: 'k', label: 'test_track.plan.plan_principal'},
],

View File

@ -1861,6 +1861,10 @@ export default {
title: "API",
this_week_add: "This week add:",
},
ui_details_card: {
scenario_cases: "UI Scenario",
step_count: "Step Count",
},
test_case_details_card: {
title: "Test case",
this_week_add: "This week add:",
@ -2039,6 +2043,7 @@ export default {
switch_project: "Project",
functional_test_case: "Functional Case",
api_test_case: "Api Case",
ui_test_case: "UI Case",
performance_test_case: "Performance Case",
scenario_test_case: "Scenario Case",
report_statistics: "Report Statistics",
@ -2238,6 +2243,7 @@ export default {
test_plan_test_case_count: "Track Case Count",
test_plan_api_case_count: "Api Case Count",
test_plan_api_scenario_count: "Scenario Case Count",
test_plan_ui_scenario_count: "Ui Scenario Case Count",
test_plan_load_case_count: "Load Case Count",
test_plan_component_case_count: "Component Case Count",
data_name: "Data Name",
@ -2498,6 +2504,7 @@ export default {
report_summary: "Summary",
analysis_functional: "Analysis Functional",
analysis_api: "Analysis Api",
analysis_ui: "Analysis Ui",
analysis_load: "Analysis Performance",
valid_for_24_hours: "Valid for 24 hours",
configuration: "Config",

View File

@ -1868,6 +1868,10 @@ export default {
title: "接口",
this_week_add: "本周新增:",
},
ui_details_card: {
scenario_cases: "UI场景用例",
step_count: "步骤数",
},
test_case_details_card: {
title: "用例",
this_week_add: "本周新增:",
@ -2046,6 +2050,7 @@ export default {
switch_project: "切换项目",
functional_test_case: "功能测试用例",
api_test_case: "接口测试用例",
ui_test_case: "UI 测试用例",
performance_test_case: "性能测试用例",
scenario_test_case: "场景测试用例",
report_statistics: "报告统计",
@ -2237,6 +2242,7 @@ export default {
test_plan_test_case_count: "功能用例数",
test_plan_api_case_count: "接口用例数",
test_plan_api_scenario_count: "场景用例数",
test_plan_ui_scenario_count: "UI 场景用例数",
test_plan_load_case_count: "性能用例数",
test_plan_component_case_count: "步骤用例数",
data_name: "数据名称",
@ -2507,6 +2513,7 @@ export default {
report_summary: "报告总结",
analysis_functional: "功能用例统计分析",
analysis_api: "接口用例统计分析",
analysis_ui: "UI 用例统计分析",
analysis_load: "性能用例统计分析",
valid_for_24_hours: "24小时有效",
configuration: "配置",

View File

@ -1865,6 +1865,10 @@ export default {
title: "接口",
this_week_add: "本周新增:",
},
ui_details_card: {
scenario_cases: "UI場景用例",
step_count: "步驟數",
},
test_case_details_card: {
title: "用例",
this_week_add: "本周新增:",
@ -2043,6 +2047,7 @@ export default {
switch_project: "切換項目",
functional_test_case: "功能測試用例",
api_test_case: "接口測試用例",
ui_test_case: "UI 測試用例",
performance_test_case: "性能測試用例",
scenario_test_case: "場景測試用例",
report_statistics: "報告統計",
@ -2231,6 +2236,7 @@ export default {
test_plan_test_case_count: "功能用例數",
test_plan_api_case_count: "接口用例數",
test_plan_api_scenario_count: "場景用例數",
test_plan_ui_scenario_count: "UI 場景用例數",
test_plan_load_case_count: "性能用例數",
test_plan_component_case_count: "步驟用例數",
data_name: "數據名稱",
@ -2501,6 +2507,7 @@ export default {
report_summary: "報告總結",
analysis_functional: "功能用例統計分析",
analysis_api: "接口用例統計分析",
analysis_ui: "UI 用例統計分析",
analysis_load: "性能用例統計分析",
valid_for_24_hours: "24小時有效",
configuration: "配置",

View File

@ -171,3 +171,20 @@ export function getPlanStageOption(callback) {
export function saveTestPlanReport(planId, callback) {
return planId ? baseGet('/test/plan/report/saveTestPlanReport/' + planId + '/MANUAL', callback) : {};
}
export function getPlanUiScenarioFailureCase(planId, callback) {
return planId ? baseGet('/test/plan/uiScenario/case/list/failure/' + planId, callback) : {};
}
export function getPlanUiScenarioErrorReportCase(planId, callback) {
return planId ? baseGet('/test/plan/uiScenario/case/list/errorReport/' + planId, callback) : {};
}
export function getPlanUiScenarioUnExecuteCase(planId, callback) {
return planId ? baseGet('/test/plan/uiScenario/case/list/unExecute/' + planId, callback) : {};
}
export function getPlanUiScenarioAllCase(planId, callback) {
return planId ? baseGet('/test/plan/uiScenario/case/list/all/' + planId, callback) : {};
}