feat(接口测试): 接口测试样式优化

--story=1007743 --user=宋天阳 接口测试首页数据统计优化
https://www.tapd.cn/55049933/s/1193399
This commit is contained in:
song-tianyang 2022-05-26 15:46:25 +08:00 committed by f2c-ci-robot[bot]
parent 74b0d0493e
commit 83b8b90669
51 changed files with 2059 additions and 338 deletions

View File

@ -6,13 +6,15 @@ import io.metersphere.api.dto.*;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.api.dto.datacount.request.ScheduleInfoRequest;
import io.metersphere.api.dto.datacount.response.ApiDataCountDTO;
import io.metersphere.api.dto.datacount.response.ExecutedCaseInfoDTO;
import io.metersphere.api.dto.datacount.response.TaskInfoResult;
import io.metersphere.api.dto.datacount.response.*;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
import io.metersphere.api.service.*;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.ApiDefinition;
import io.metersphere.base.domain.ApiDefinitionExecResultExpand;
import io.metersphere.base.domain.ApiTest;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.ExecuteResult;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.BaseQueryRequest;
@ -22,6 +24,7 @@ import io.metersphere.dto.ScheduleDao;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.ScheduleService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -229,6 +232,36 @@ public class APITestController {
apiCountResult.setTcpCountStr("TCP&nbsp;&nbsp;<br/><br/>" + apiCountResult.getTcpApiDataCountNumber());
apiCountResult.setSqlCountStr("SQL&nbsp;&nbsp;<br/><br/>" + apiCountResult.getSqlApiDataCountNumber());
//计算用例的通过率
List<ExecuteResultCountDTO> apiCaseExecResultList = apiTestCaseService.selectExecuteResultByProjectId(projectId);
long unexecuteCount = 0;
long executionFailedCount = 0;
long executionPassCount = 0;
long fakeErrorCount = 0;
for (ExecuteResultCountDTO execResult : apiCaseExecResultList) {
if (StringUtils.isEmpty(execResult.getExecResult())) {
unexecuteCount += execResult.getCount();
} else if (StringUtils.equalsIgnoreCase(execResult.getExecResult(), ExecuteResult.API_SUCCESS.toString())) {
executionPassCount += execResult.getCount();
} else if (StringUtils.equalsAnyIgnoreCase(execResult.getExecResult(), ExecuteResult.ERROR_REPORT_RESULT.toString(), ExecuteResult.ERROR_REPORT.toString())) {
fakeErrorCount += execResult.getCount();
} else {
executionFailedCount += execResult.getCount();
}
}
apiCountResult.setUnexecuteCount(unexecuteCount);
apiCountResult.setExecutionFailedCount(executionFailedCount);
apiCountResult.setExecutionPassCount(executionPassCount);
apiCountResult.setFakeErrorCount(fakeErrorCount);
if (unexecuteCount + executedCountNumber + executionPassCount > 0) {
//通过率
float coverageRageNumber = (float) executionPassCount * 100 / (unexecuteCount + executedCountNumber + executionPassCount);
DecimalFormat df = new DecimalFormat("0.0");
apiCountResult.setPassRage(df.format(coverageRageNumber) + "%");
} else {
apiCountResult.setPassRage("0%");
}
return apiCountResult;
}
@ -263,9 +296,15 @@ public class APITestController {
return apiCountResult;
}
/**
* 接口覆盖率统计
*
* @param projectId
* @return
*/
@GetMapping("/countApiCoverage/{projectId}")
public String countApiCoverage(@PathVariable String projectId) {
String returnStr = "0%";
public CoverageDTO countApiCoverage(@PathVariable String projectId) {
CoverageDTO coverage = new CoverageDTO();
/**
* 接口覆盖率
* 接口有案例/被场景引用 所有的接口
@ -273,34 +312,40 @@ public class APITestController {
long effectiveApiCount = apiDefinitionService.countEffectiveByProjectId(projectId);
long sourceIdCount = apiDefinitionService.countQuotedApiByProjectId(projectId);
try {
if(sourceIdCount != 0){
if (sourceIdCount != 0) {
coverage.setCoverate(sourceIdCount);
coverage.setNotCoverate(effectiveApiCount - sourceIdCount);
float coverageRageNumber = (float) sourceIdCount * 100 / effectiveApiCount;
DecimalFormat df = new DecimalFormat("0.0");
returnStr = df.format(coverageRageNumber) + "%";
coverage.setRateOfCoverage(df.format(coverageRageNumber) + "%");
}
}catch (Exception e){
} catch (Exception e) {
LogUtil.error(e);
}
return returnStr;
return coverage;
}
@GetMapping("/countInterfaceCoverage/{projectId}")
public String countInterfaceCoverage(@PathVariable String projectId) {
String returnStr = "0%";
/**
* 场景覆盖率统计
*
* @param projectId
* @return
*/
@GetMapping("/countScenarioCoverage/{projectId}")
public CoverageDTO countScenarioCoverage(@PathVariable String projectId) {
CoverageDTO coverage = new CoverageDTO();
/**
* 接口覆盖率
* 复制的接口定义/复制或引用的单接口用例/ 添加的自定义请求 url 路径与现有的接口定义一致的请求
*/
Map<String,List<String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId);
Map<String, Map<String, String>> scenarioUrlList = apiAutomationService.selectScenarioUseUrlByProjectId(projectId);
List<ApiDefinition> allEffectiveApiIdList = apiDefinitionService.selectEffectiveIdByProjectId(projectId);
try {
float intetfaceCoverageRageNumber = apiAutomationService.countInterfaceCoverage(scenarioUrlList, allEffectiveApiIdList);
DecimalFormat df = new DecimalFormat("0.0");
returnStr = df.format(intetfaceCoverageRageNumber) + "%";
}catch (Exception e){
coverage = apiAutomationService.countInterfaceCoverage(projectId, scenarioUrlList, allEffectiveApiIdList);
} catch (Exception e) {
LogUtil.error(e);
}
return returnStr;
return coverage;
}
@GetMapping("/scheduleTaskInfoCount/{projectId}")
@ -348,6 +393,7 @@ public class APITestController {
dataDTO.setCaseName(selectData.getCaseName());
dataDTO.setTestPlan(selectData.getTestPlan());
dataDTO.setFailureTimes(selectData.getFailureTimes());
dataDTO.setTestPlanId(selectData.getTestPlanId());
dataDTO.setCaseType(selectData.getCaseType());
dataDTO.setId(selectData.getId());
dataDTO.setTestPlanDTOList(selectData.getTestPlanDTOList());
@ -361,7 +407,7 @@ public class APITestController {
}
@PostMapping("/runningTask/{projectID}")
public List<TaskInfoResult> runningTask(@PathVariable String projectID,@RequestBody BaseQueryRequest request) {
public List<TaskInfoResult> runningTask(@PathVariable String projectID, @RequestBody BaseQueryRequest request) {
List<TaskInfoResult> resultList = scheduleService.findRunningTaskInfoByProjectID(projectID, request);
int dataIndex = 1;
for (TaskInfoResult taskInfo :

View File

@ -1,13 +1,9 @@
package io.metersphere.api.dto.automation;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class ApiScenarioRequest extends BaseQueryRequest {
@ -20,7 +16,9 @@ public class ApiScenarioRequest extends BaseQueryRequest {
private boolean recent = false;
private boolean isSelectThisWeedData;
private long createTime = 0;
private long scheduleCreateTime = 0;
private String executeStatus;
private String selectDataType;
private boolean notInTestPlan;
private String reviewId;
private String versionId;

View File

@ -18,6 +18,7 @@ public class ExecutedCaseInfoResult {
private String caseName;
//所属测试计划
private String testPlan;
private String testPlanId;
//失败次数
private Long failureTimes;
//案例类型

View File

@ -2,8 +2,10 @@ package io.metersphere.api.dto.datacount.response;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.commons.constants.ExecuteResult;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
@ -85,6 +87,10 @@ public class ApiDataCountDTO {
* 执行通过
*/
private long executionPassCount = 0;
/**
* 执行误报
*/
private long fakeErrorCount = 0;
/**
* 失败
*/
@ -116,16 +122,15 @@ public class ApiDataCountDTO {
*/
private String interfaceCoverage = " 0%";
public ApiDataCountDTO(){}
/**
* 对Protocal视角对查询结果进行统计
*
* @param countResultList 查询参数
*/
public void countProtocal(List<ApiDataCountResult> countResultList){
public void countProtocal(List<ApiDataCountResult> countResultList) {
for (ApiDataCountResult countResult :
countResultList) {
switch (countResult.getGroupField().toUpperCase()){
switch (countResult.getGroupField().toUpperCase()) {
case RequestType.DUBBO:
this.rpcApiDataCountNumber += countResult.getCountNumber();
break;
@ -148,19 +153,20 @@ public class ApiDataCountDTO {
/**
* 对Status视角对查询结果进行统计
*
* @param countResultList 查询参数
*/
public void countStatus(List<ApiDataCountResult> countResultList){
public void countStatus(List<ApiDataCountResult> countResultList) {
for (ApiDataCountResult countResult :
countResultList) {
if("Underway".equals(countResult.getGroupField())){
if (StringUtils.equalsIgnoreCase(countResult.getGroupField(), "Underway")) {
//运行中
this.runningCount+= countResult.getCountNumber();
}else if("Completed".equals(countResult.getGroupField())){
this.runningCount += countResult.getCountNumber();
} else if (StringUtils.equalsIgnoreCase(countResult.getGroupField(), "Completed")) {
//已完成
this.finishedCount+= countResult.getCountNumber();
}else if("Prepare".equals(countResult.getGroupField())){
this.notStartedCount+= countResult.getCountNumber();
this.finishedCount += countResult.getCountNumber();
} else if (StringUtils.equalsIgnoreCase(countResult.getGroupField(), "Prepare")) {
this.notStartedCount += countResult.getCountNumber();
}
}
}
@ -168,35 +174,39 @@ public class ApiDataCountDTO {
public void countApiCoverage(List<ApiDataCountResult> countResultList) {
for (ApiDataCountResult countResult : countResultList) {
if("coverage".equals(countResult.getGroupField())){
this.coverageCount+= countResult.getCountNumber();
}else if("uncoverage".equals(countResult.getGroupField())){
this.uncoverageCount+= countResult.getCountNumber();
if (StringUtils.equalsIgnoreCase(countResult.getGroupField(), "coverage")) {
this.coverageCount += countResult.getCountNumber();
} else if (StringUtils.equalsIgnoreCase(countResult.getGroupField(), "uncoverage")) {
this.uncoverageCount += countResult.getCountNumber();
}
}
}
public void countRunResult(List<ApiDataCountResult> countResultByRunResult) {
for (ApiDataCountResult countResult : countResultByRunResult) {
if("notRun".equals(countResult.getGroupField())){
this.unexecuteCount+= countResult.getCountNumber();
}else if("Fail".equals(countResult.getGroupField())){
this.executionFailedCount+= countResult.getCountNumber();
}else {
this.executionPassCount+= countResult.getCountNumber();
if ("notRun".equals(countResult.getGroupField())) {
this.unexecuteCount += countResult.getCountNumber();
} else if ("Fail".equals(countResult.getGroupField())) {
this.executionFailedCount += countResult.getCountNumber();
} else if (StringUtils.equalsAnyIgnoreCase(countResult.getGroupField(), ExecuteResult.ERROR_REPORT_RESULT.toString(), ExecuteResult.ERROR_REPORT.toString())) {
this.fakeErrorCount += countResult.getCountNumber();
} else {
this.executionPassCount += countResult.getCountNumber();
}
}
}
public void countScheduleExecute(List<ApiDataCountResult> allExecuteResult) {
for (ApiDataCountResult countResult : allExecuteResult) {
if("Success".equals(countResult.getGroupField())){
this.successCount+= countResult.getCountNumber();
this.executedCount+= countResult.getCountNumber();
}else if("Error".equals(countResult.getGroupField())||"Fail".equals(countResult.getGroupField())){
this.failedCount+= countResult.getCountNumber();
this.executedCount+= countResult.getCountNumber();
if (StringUtils.equalsIgnoreCase(countResult.getGroupField(), "success")) {
this.successCount += countResult.getCountNumber();
this.executedCount += countResult.getCountNumber();
} else if (StringUtils.equalsAnyIgnoreCase(countResult.getGroupField(), ExecuteResult.SCENARIO_ERROR.toString(), "Fail")) {
this.failedCount += countResult.getCountNumber();
this.executedCount += countResult.getCountNumber();
} else if (StringUtils.equalsAnyIgnoreCase(countResult.getGroupField(), ExecuteResult.ERROR_REPORT_RESULT.toString())) {
this.fakeErrorCount += countResult.getCountNumber();
this.executedCount += countResult.getCountNumber();
}
}
}

View File

@ -0,0 +1,12 @@
package io.metersphere.api.dto.datacount.response;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CoverageDTO {
public String rateOfCoverage = "0%";
public long coverate = 0;
public long notCoverate = 0;
}

View File

@ -0,0 +1,11 @@
package io.metersphere.api.dto.datacount.response;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ExecuteResultCountDTO {
private String execResult;
private long count;
}

View File

@ -18,6 +18,7 @@ public class ExecutedCaseInfoDTO {
private String caseName;
//所属测试计划
private String testPlan;
private String testPlanId;
//失败次数
private Long failureTimes;
//案例类型

View File

@ -20,7 +20,9 @@ public class ApiDefinitionRequest extends BaseQueryRequest {
private boolean isSelectThisWeedData = false;
private long createTime = 0;
private String status;
private String apiCoverage;
private String apiCaseCoverage;
private String scenarioCoverage;
private String reviewId;
private String refId;
private String versionId;

View File

@ -50,4 +50,7 @@ public class ApiTestCaseRequest extends BaseQueryRequest {
* 查询排除一些接口
*/
private List<String> notInIds;
//页面跳转时附带的过滤条件
private String redirectFilter;
}

View File

@ -703,7 +703,46 @@ public class MockApiUtils {
}
}
public static boolean isUrlInList(String url, List<String> urlList) {
public static boolean isUrlMatch(String url, String compareUrl) {
String urlSuffix = url;
if (urlSuffix.startsWith("/")) {
urlSuffix = urlSuffix.substring(1);
}
String[] urlParams = urlSuffix.split("/");
if (StringUtils.equalsAny(compareUrl, url, "/" + url)) {
return true;
} else {
if (StringUtils.isEmpty(compareUrl)) {
return false;
}
if (compareUrl.startsWith("/")) {
compareUrl = compareUrl.substring(1);
}
if (StringUtils.isNotEmpty(compareUrl)) {
String[] pathArr = compareUrl.split("/");
if (pathArr.length == urlParams.length) {
boolean isFetch = true;
for (int i = 0; i < urlParams.length; i++) {
String pathItem = pathArr[i];
String urlItem = urlParams[i];
if (!(pathItem.startsWith("{") && pathItem.endsWith("}")) && !(urlItem.startsWith("{") && urlItem.endsWith("}"))) {
if (!StringUtils.equals(pathArr[i], urlParams[i])) {
isFetch = false;
break;
}
}
}
if (isFetch) {
return true;
}
}
}
}
return false;
}
public static boolean isUrlInList(String url, Collection<String> urlList) {
if (CollectionUtils.isEmpty(urlList)) {
return false;
}

View File

@ -12,6 +12,7 @@ import io.metersphere.api.dto.automation.parse.ApiScenarioImportUtil;
import io.metersphere.api.dto.automation.parse.ScenarioImport;
import io.metersphere.api.dto.automation.parse.ScenarioImportParserFactory;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.datacount.response.CoverageDTO;
import io.metersphere.api.dto.definition.ApiTestCaseInfo;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.*;
@ -74,6 +75,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
@ -234,7 +236,11 @@ public class ApiAutomationService {
Map<String, Date> weekFirstTimeAndLastTime = DateUtils.getWeedFirstTimeAndLastTime(new Date());
Date weekFirstTime = weekFirstTimeAndLastTime.get("firstTime");
if (weekFirstTime != null) {
request.setCreateTime(weekFirstTime.getTime());
if (StringUtils.equalsIgnoreCase(request.getSelectDataType(), "SCHEDULE")) {
request.setScheduleCreateTime(weekFirstTime.getTime());
} else {
request.setCreateTime(weekFirstTime.getTime());
}
}
}
}
@ -1684,20 +1690,51 @@ public class ApiAutomationService {
* @param allEffectiveApiList 接口集合id / path 必须有数据
* @return
*/
public float countInterfaceCoverage(Map<String, List<String>> scenarioUrlMap, List<ApiDefinition> allEffectiveApiList) {
public CoverageDTO countInterfaceCoverage(String projectId, Map<String, Map<String, String>> scenarioUrlMap, List<ApiDefinition> allEffectiveApiList) {
CoverageDTO coverage = new CoverageDTO();
if (MapUtils.isEmpty(scenarioUrlMap) || CollectionUtils.isEmpty(allEffectiveApiList)) {
return 0;
return coverage;
}
ProjectApplication urlRepeatableConfig = projectApplicationService.getProjectApplication(projectId, ProjectApplicationType.URL_REPEATABLE.name());
boolean isUrlRepeatable = BooleanUtils.toBoolean(urlRepeatableConfig.getTypeValue());
int containsCount = 0;
for (ApiDefinition model : allEffectiveApiList) {
List<String> scenarioUrlList = scenarioUrlMap.get(model.getMethod());
boolean matchedUrl = MockApiUtils.isUrlInList(model.getPath(), scenarioUrlList);
if (matchedUrl) {
containsCount++;
if (StringUtils.equalsIgnoreCase(model.getProtocol(), "http")) {
Map<String, String> stepIdAndUrlMap = scenarioUrlMap.get(model.getMethod());
if (stepIdAndUrlMap != null) {
if (isUrlRepeatable) {
String url = stepIdAndUrlMap.get(model.getId());
if (StringUtils.isNotEmpty(url)) {
boolean matchedUrl = MockApiUtils.isUrlMatch(model.getPath(), url);
if (matchedUrl) {
containsCount++;
}
}
} else {
Collection<String> scenarioUrlList = scenarioUrlMap.get(model.getMethod()).values();
boolean matchedUrl = MockApiUtils.isUrlInList(model.getPath(), scenarioUrlList);
if (matchedUrl) {
containsCount++;
}
}
}
} else {
Map<String, String> stepIdAndUrlMap = scenarioUrlMap.get("MS_NOT_HTTP");
if (stepIdAndUrlMap != null && stepIdAndUrlMap.containsKey(model.getId())) {
containsCount++;
}
}
}
coverage.setCoverate(containsCount);
coverage.setNotCoverate(allEffectiveApiList.size() - containsCount);
float coverageRageNumber = (float) containsCount * 100 / allEffectiveApiList.size();
return coverageRageNumber;
DecimalFormat df = new DecimalFormat("0.0");
coverage.setRateOfCoverage(df.format(coverageRageNumber) + "%");
return coverage;
}
public ScenarioEnv getApiScenarioProjectId(String id) {
@ -2063,7 +2100,7 @@ public class ApiAutomationService {
List<ApiScenario> apiScenarios = apiScenarioMapper.selectByExample(example);
List<String> scenarioIds = apiScenarios.stream().map(ApiScenario::getId).collect(toList());
scenarioExecutionInfoService.deleteByScenarioIdList(scenarioIds);
apiScenarioMapper.deleteByExample(example);
scheduleService.deleteByResourceId(refId, ScheduleGroup.API_SCENARIO_TEST.name());
checkAndSetLatestVersion(refId);
@ -2157,17 +2194,25 @@ public class ApiAutomationService {
}
}
public Map<String, List<String>> selectScenarioUseUrlByProjectId(String projectId) {
/**
* 获取当前项目的场景下引用的接口路径和id
*
* @param projectId
* @return <get/post, <step-id,url>>
*/
public Map<String, Map<String, String>> selectScenarioUseUrlByProjectId(String projectId) {
List<ApiScenarioReferenceId> list = apiScenarioReferenceIdService.selectUrlByProjectId(projectId);
Map<String, List<String>> returnMap = new HashMap<>();
Map<String, Map<String, String>> returnMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(list)) {
list.forEach(item -> {
if (returnMap.containsKey(item.getMethod())) {
returnMap.get(item.getMethod()).add(item.getUrl());
String method = item.getMethod() == null ? "MS_NOT_HTTP" : item.getMethod();
if (returnMap.containsKey(method)) {
returnMap.get(method).put(item.getReferenceId(), item.getUrl());
} else {
List<String> urlList = new ArrayList<>();
urlList.add(item.getUrl());
returnMap.put(item.getMethod(), urlList);
Map<String, String> urlMap = new HashMap() {{
this.put(item.getReferenceId(), item.getUrl());
}};
returnMap.put(method, urlMap);
}
});
}

View File

@ -18,8 +18,6 @@ import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.ApiCaseExecutionInfoService;
import io.metersphere.service.ApiExecutionInfoService;
import io.metersphere.track.dto.PlanReportCaseDTO;
import io.metersphere.track.dto.TestPlanDTO;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.request.testcase.TrackCount;
import io.metersphere.track.service.TestCaseReviewApiCaseService;
import io.metersphere.track.service.TestPlanTestCaseService;
@ -325,16 +323,19 @@ public class ApiDefinitionExecResultService {
reportResult.setUserId(String.valueOf(dto.getExtendedParameters().get("userId")));
}
String status = item.isSuccess() ? "success" : "error";
String triggerMode = "";
if (reportResult != null) {
status = reportResult.getStatus();
triggerMode = reportResult.getTriggerMode();
}
if (MapUtils.isNotEmpty(expandDTO.getAttachInfoMap())) {
status = expandDTO.getStatus();
}
if (StringUtils.equalsAny(dto.getRunMode(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(dto.getTestId());
if (apiCase != null) {
apiCaseExecutionInfoService.insertExecutionInfo(apiCase.getApiCaseId(), status);
apiCaseExecutionInfoService.insertExecutionInfo(apiCase.getId(), status, triggerMode);
apiCase.setStatus(status);
apiCase.setUpdateTime(System.currentTimeMillis());
testPlanApiCaseMapper.updateByPrimaryKeySelective(apiCase);
@ -414,7 +415,7 @@ public class ApiDefinitionExecResultService {
if (startTime == null) {
return new ArrayList<>(0);
} else {
List<ExecutedCaseInfoResult> list = extApiDefinitionExecResultMapper.findFaliureCaseInfoByProjectIDAndExecuteTimeAndLimitNumber(projectId, startTime.getTime());
List<ExecutedCaseInfoResult> list = extApiDefinitionExecResultMapper.findFaliureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(projectId, startTime.getTime());
List<ExecutedCaseInfoResult> returnList = new ArrayList<>(limitNumber);
@ -423,17 +424,17 @@ public class ApiDefinitionExecResultService {
//开始遍历查询TestPlan信息 --> 提供前台做超链接
ExecutedCaseInfoResult item = list.get(i);
QueryTestPlanRequest planRequest = new QueryTestPlanRequest();
planRequest.setProjectId(projectId);
if ("scenario".equals(item.getCaseType())) {
planRequest.setScenarioId(item.getTestCaseID());
} else if ("apiCase".equals(item.getCaseType())) {
planRequest.setApiId(item.getTestCaseID());
} else if ("load".equals(item.getCaseType())) {
planRequest.setLoadId(item.getTestCaseID());
}
List<TestPlanDTO> dtoList = extTestPlanMapper.selectTestPlanByRelevancy(planRequest);
item.setTestPlanDTOList(dtoList);
// QueryTestPlanRequest planRequest = new QueryTestPlanRequest();
// planRequest.setProjectId(projectId);
// if ("scenario".equals(item.getCaseType())) {
// planRequest.setScenarioId(item.getTestCaseID());
// } else if ("apiCase".equals(item.getCaseType())) {
// planRequest.setApiId(item.getTestCaseID());
// } else if ("load".equals(item.getCaseType())) {
// planRequest.setLoadId(item.getTestCaseID());
// }
// List<TestPlanDTO> dtoList = extTestPlanMapper.selectTestPlanByRelevancy(planRequest);
// item.setTestPlanDTOList(dtoList);
returnList.add(item);
} else {
break;

View File

@ -310,7 +310,7 @@ public class ApiScenarioReportService {
testPlanApiScenarioMapper.updateByPrimaryKeySelective(testPlanApiScenario);
//增加场景的运行记录
scenarioExecutionInfoService.insertExecutionInfo(testPlanApiScenario.getApiScenarioId(), status);
scenarioExecutionInfoService.insertExecutionInfo(testPlanApiScenario.getId(), status, report.getTriggerMode());
// 更新场景状态
ApiScenario scenario = apiScenarioMapper.selectByPrimaryKey(testPlanApiScenario.getApiScenarioId());
@ -434,7 +434,7 @@ public class ApiScenarioReportService {
// 更新报告
apiScenarioReportMapper.updateByPrimaryKey(report);
//场景集合报告按照集合报告的结果作为场景的最后执行结果
scenarioExecutionInfoService.insertExecutionInfoByScenarioIds(report.getScenarioId(), report.getStatus());
scenarioExecutionInfoService.insertExecutionInfoByScenarioIds(report.getScenarioId(), report.getStatus(), report.getTriggerMode());
}
}

View File

@ -9,6 +9,7 @@ import io.metersphere.api.dto.ApiCaseEditRequest;
import io.metersphere.api.dto.DeleteCheckResult;
import io.metersphere.api.dto.JmxInfoDTO;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.datacount.response.ExecuteResultCountDTO;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsTestPlan;
@ -1186,4 +1187,7 @@ public class ApiTestCaseService {
return null;
}
public List<ExecuteResultCountDTO> selectExecuteResultByProjectId(String projectId) {
return extApiTestCaseMapper.selectExecuteResultByProjectId(projectId);
}
}

View File

@ -184,7 +184,7 @@ public class TestResultService {
} else {
ApiScenarioWithBLOBs apiScenario = apiScenarioMapper.selectByPrimaryKey(scenarioReport.getScenarioId());
if (apiScenario != null) {
scenarioExecutionInfoService.insertExecutionInfo(scenarioReport.getScenarioId(), scenarioReport.getStatus());
scenarioExecutionInfoService.insertExecutionInfo(scenarioReport.getScenarioId(), scenarioReport.getStatus(), scenarioReport.getTriggerMode());
environment = apiScenarioReportService.getEnvironment(apiScenario);
userName = apiAutomationService.getUser(apiScenario.getUserId());
principal = apiAutomationService.getUser(apiScenario.getPrincipal());

View File

@ -11,6 +11,8 @@ public class ApiCaseExecutionInfo implements Serializable {
private String result;
private String triggerMode;
private Long createTime;
private static final long serialVersionUID = 1L;

View File

@ -314,6 +314,76 @@ public class ApiCaseExecutionInfoExample {
return (Criteria) this;
}
public Criteria andTriggerModeIsNull() {
addCriterion("trigger_mode is null");
return (Criteria) this;
}
public Criteria andTriggerModeIsNotNull() {
addCriterion("trigger_mode is not null");
return (Criteria) this;
}
public Criteria andTriggerModeEqualTo(String value) {
addCriterion("trigger_mode =", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotEqualTo(String value) {
addCriterion("trigger_mode <>", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeGreaterThan(String value) {
addCriterion("trigger_mode >", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeGreaterThanOrEqualTo(String value) {
addCriterion("trigger_mode >=", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeLessThan(String value) {
addCriterion("trigger_mode <", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeLessThanOrEqualTo(String value) {
addCriterion("trigger_mode <=", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeLike(String value) {
addCriterion("trigger_mode like", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotLike(String value) {
addCriterion("trigger_mode not like", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeIn(List<String> values) {
addCriterion("trigger_mode in", values, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotIn(List<String> values) {
addCriterion("trigger_mode not in", values, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeBetween(String value1, String value2) {
addCriterion("trigger_mode between", value1, value2, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotBetween(String value1, String value2) {
addCriterion("trigger_mode not between", value1, value2, "triggerMode");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;

View File

@ -11,6 +11,8 @@ public class ScenarioExecutionInfo implements Serializable {
private String result;
private String triggerMode;
private Long createTime;
private static final long serialVersionUID = 1L;

View File

@ -314,6 +314,76 @@ public class ScenarioExecutionInfoExample {
return (Criteria) this;
}
public Criteria andTriggerModeIsNull() {
addCriterion("trigger_mode is null");
return (Criteria) this;
}
public Criteria andTriggerModeIsNotNull() {
addCriterion("trigger_mode is not null");
return (Criteria) this;
}
public Criteria andTriggerModeEqualTo(String value) {
addCriterion("trigger_mode =", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotEqualTo(String value) {
addCriterion("trigger_mode <>", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeGreaterThan(String value) {
addCriterion("trigger_mode >", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeGreaterThanOrEqualTo(String value) {
addCriterion("trigger_mode >=", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeLessThan(String value) {
addCriterion("trigger_mode <", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeLessThanOrEqualTo(String value) {
addCriterion("trigger_mode <=", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeLike(String value) {
addCriterion("trigger_mode like", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotLike(String value) {
addCriterion("trigger_mode not like", value, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeIn(List<String> values) {
addCriterion("trigger_mode in", values, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotIn(List<String> values) {
addCriterion("trigger_mode not in", values, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeBetween(String value1, String value2) {
addCriterion("trigger_mode between", value1, value2, "triggerMode");
return (Criteria) this;
}
public Criteria andTriggerModeNotBetween(String value1, String value2) {
addCriterion("trigger_mode not between", value1, value2, "triggerMode");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;

View File

@ -5,6 +5,7 @@
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="source_id" jdbcType="VARCHAR" property="sourceId" />
<result column="result" jdbcType="VARCHAR" property="result" />
<result column="trigger_mode" jdbcType="VARCHAR" property="triggerMode" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
</resultMap>
<sql id="Example_Where_Clause">
@ -66,7 +67,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, source_id, `result`, create_time
id, source_id, `result`, trigger_mode, create_time
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiCaseExecutionInfoExample" resultMap="BaseResultMap">
select
@ -100,9 +101,9 @@
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiCaseExecutionInfo">
insert into api_case_execution_info (id, source_id, `result`,
create_time)
trigger_mode, create_time)
values (#{id,jdbcType=VARCHAR}, #{sourceId,jdbcType=VARCHAR}, #{result,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT})
#{triggerMode,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiCaseExecutionInfo">
insert into api_case_execution_info
@ -116,6 +117,9 @@
<if test="result != null">
`result`,
</if>
<if test="triggerMode != null">
trigger_mode,
</if>
<if test="createTime != null">
create_time,
</if>
@ -130,6 +134,9 @@
<if test="result != null">
#{result,jdbcType=VARCHAR},
</if>
<if test="triggerMode != null">
#{triggerMode,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
@ -153,6 +160,9 @@
<if test="record.result != null">
`result` = #{record.result,jdbcType=VARCHAR},
</if>
<if test="record.triggerMode != null">
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
@ -166,6 +176,7 @@
set id = #{record.id,jdbcType=VARCHAR},
source_id = #{record.sourceId,jdbcType=VARCHAR},
`result` = #{record.result,jdbcType=VARCHAR},
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -180,6 +191,9 @@
<if test="result != null">
`result` = #{result,jdbcType=VARCHAR},
</if>
<if test="triggerMode != null">
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
@ -190,6 +204,7 @@
update api_case_execution_info
set source_id = #{sourceId,jdbcType=VARCHAR},
`result` = #{result,jdbcType=VARCHAR},
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
</update>

View File

@ -5,6 +5,7 @@
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="source_id" jdbcType="VARCHAR" property="sourceId" />
<result column="result" jdbcType="VARCHAR" property="result" />
<result column="trigger_mode" jdbcType="VARCHAR" property="triggerMode" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
</resultMap>
<sql id="Example_Where_Clause">
@ -66,7 +67,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, source_id, `result`, create_time
id, source_id, `result`, trigger_mode, create_time
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ScenarioExecutionInfoExample" resultMap="BaseResultMap">
select
@ -100,9 +101,9 @@
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ScenarioExecutionInfo">
insert into scenario_execution_info (id, source_id, `result`,
create_time)
trigger_mode, create_time)
values (#{id,jdbcType=VARCHAR}, #{sourceId,jdbcType=VARCHAR}, #{result,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT})
#{triggerMode,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ScenarioExecutionInfo">
insert into scenario_execution_info
@ -116,6 +117,9 @@
<if test="result != null">
`result`,
</if>
<if test="triggerMode != null">
trigger_mode,
</if>
<if test="createTime != null">
create_time,
</if>
@ -130,6 +134,9 @@
<if test="result != null">
#{result,jdbcType=VARCHAR},
</if>
<if test="triggerMode != null">
#{triggerMode,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
@ -153,6 +160,9 @@
<if test="record.result != null">
`result` = #{record.result,jdbcType=VARCHAR},
</if>
<if test="record.triggerMode != null">
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
@ -166,6 +176,7 @@
set id = #{record.id,jdbcType=VARCHAR},
source_id = #{record.sourceId,jdbcType=VARCHAR},
`result` = #{record.result,jdbcType=VARCHAR},
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -180,6 +191,9 @@
<if test="result != null">
`result` = #{result,jdbcType=VARCHAR},
</if>
<if test="triggerMode != null">
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
@ -190,6 +204,7 @@
update scenario_execution_info
set source_id = #{sourceId,jdbcType=VARCHAR},
`result` = #{result,jdbcType=VARCHAR},
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
</update>

View File

@ -30,6 +30,8 @@ public interface ExtApiDefinitionExecResultMapper {
List<ExecutedCaseInfoResult> findFaliureCaseInfoByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("startTimestamp") long startTimestamp);
List<ExecutedCaseInfoResult> findFaliureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("startTimestamp") long startTimestamp);
String selectExecResult(String resourceId);
ApiDefinitionExecResultWithBLOBs selectPlanApiMaxResultByTestIdAndType(String resourceId, String type);

View File

@ -46,6 +46,64 @@
WHERE integrated_report_id = #{0}
</select>
<select id="findFaliureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber"
resultType="io.metersphere.api.dto.datacount.ExecutedCaseInfoResult">
SELECT *
FROM (SELECT testCase.testPlanCaseID AS testPlanCaseID,
testCase.id AS id,
testCase.testCaseName AS caseName,
testCase.testPlanName AS testPlan,
testCase.testPlanId AS testPlanId,
caseErrorCountData.dataCountNumber AS failureTimes,
'apiCase' AS caseType
FROM (SELECT testPlanCase.id AS testPlanCaseID,
apiCase.id AS id,
apiCase.`name` AS testCaseName,
testPlan.id AS testPlanId,
testPlan.`name` AS testPlanName
FROM api_test_case apiCase
INNER JOIN test_plan_api_case testPlanCase ON testPlanCase.api_case_id = apiCase.id
INNER JOIN test_plan testPlan ON testPlan.id = testPlanCase.test_plan_id
WHERE (
apiCase.`status` IS NULL
OR apiCase.`status` != 'Trash'
AND apiCase.project_id = #{projectId})) testCase
INNER JOIN (SELECT executionInfo.source_id AS sourceId,
COUNT(executionInfo.id) AS dataCountNumber
FROM api_case_execution_info executionInfo
INNER JOIN test_plan_api_case testPlanCase
ON executionInfo.source_id = testPlanCase.id
WHERE executionInfo.`result` = 'error'
AND executionInfo.create_time > #{startTimestamp}
GROUP BY source_id) caseErrorCountData
ON caseErrorCountData.sourceId = testCase.testPlanCaseID
UNION
SELECT scene.id AS testCaseID,
scene.id AS id,
scene.`name` AS caseName,
apiScene.testPlanName AS testPlan,
apiScene.testPlanId AS testPlanId,
count(executionInfo.id) AS failureTimes,
'scenario' AS caseType
FROM scenario_execution_info executionInfo
INNER JOIN (SELECT testPlanScenario.id,
testPlanScenario.api_scenario_id,
testPlan.id AS testPlanId,
testPlan.`name` AS testPlanName
FROM test_plan_api_scenario testPlanScenario
INNER JOIN test_plan testPlan ON testPlan.id = testPlanScenario.test_plan_id) apiScene
ON apiScene.id = executionInfo.source_id
INNER JOIN api_scenario scene ON scene.id = apiScene.api_scenario_id
WHERE scene.project_id = #{projectId}
AND scene.`status` != 'Trash'
AND ( executionInfo.result = 'Error' OR executionInfo.result = 'Fail' )
AND executionInfo.create_time >= #{startTimestamp}
GROUP BY
scene.id) showTable
ORDER BY showTable.failureTimes DESC
</select>
<select id="findFaliureCaseInfoByProjectIDAndExecuteTimeAndLimitNumber"
resultType="io.metersphere.api.dto.datacount.ExecutedCaseInfoResult">
SELECT *

View File

@ -646,10 +646,10 @@
</select>
<select id="selectEffectiveIdByProjectId" resultType="io.metersphere.base.domain.ApiDefinition">
select id, path, method
select id, path, method, protocol
from api_definition
WHERE project_id = #{0}
AND status != 'Trash' AND protocol = 'HTTP' AND latest = 1
AND status != 'Trash' AND latest = 1
</select>
<select id="moduleCount" resultType="java.lang.Integer">
@ -766,6 +766,27 @@
</when>
</choose>
<include refid="filter"/>
<if test="request.apiCoverage == 'uncoverage' ">
and
api_definition.id not in (SELECT api_definition_id FROM api_test_case)
and
api_definition.id not in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') AND reference_id is not null
)
</if>
<if test="request.apiCoverage == 'coverage' ">
and
(
api_definition.id in (SELECT api_definition_id FROM api_test_case)
or
api_definition.id in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null
)
)
</if>
<if test="request.apiCaseCoverage == 'uncoverage' ">
and api_definition.id not in
(SELECT api_definition_id FROM api_test_case)
@ -774,6 +795,20 @@
and api_definition.id in
(SELECT api_definition_id FROM api_test_case)
</if>
<if test="request.scenarioCoverage == 'uncoverage' ">
and api_definition.id not in
(
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null
)
</if>
<if test="request.scenarioCoverage == 'coverage' ">
and api_definition.id in
(
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null
)
</if>
<include refid="queryVersionCondition">
<property name="versionTable" value="api_definition"/>
</include>
@ -836,6 +871,26 @@
</when>
</choose>
<include refid="filter"/>
<if test="request.apiCoverage == 'uncoverage' ">
and
api_definition.id not in (SELECT api_definition_id FROM api_test_case)
and
api_definition.id not in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') AND reference_id is not null
)
</if>
<if test="request.apiCoverage == 'coverage' ">
and
(
api_definition.id in (SELECT api_definition_id FROM api_test_case)
or
api_definition.id in (
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash')
)
)
</if>
<if test="request.apiCaseCoverage == 'uncoverage' ">
and api_definition.id not in
(SELECT api_definition_id FROM api_test_case)
@ -844,6 +899,20 @@
and api_definition.id in
(SELECT api_definition_id FROM api_test_case)
</if>
<if test="request.scenarioCoverage == 'uncoverage' ">
and api_definition.id not in
(
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null
)
</if>
<if test="request.scenarioCoverage == 'coverage' ">
and api_definition.id in
(
SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in
(SELECT id FROM api_scenario WHERE `status` is null or `status` != 'Trash') and reference_id is not null
)
</if>
<include refid="queryVersionCondition">
<property name="versionTable" value="api_definition"/>
</include>

View File

@ -244,6 +244,14 @@
<if test="request.createTime >0 ">
AND api_scenario.create_time >= #{request.createTime}
</if>
<if test="request.scheduleCreateTime >0 ">
AND api_scenario.id IN
(
SELECT resource_id FROM `schedule`
WHERE `group` = 'API_SCENARIO_TEST'
AND create_time >= #{request.scheduleCreateTime}
)
</if>
<if test="request.ids != null and request.ids.size() > 0">
AND api_scenario.id in
<foreach collection="request.ids" item="itemId" separator="," open="(" close=")">
@ -330,15 +338,39 @@
<if test="request.filters == null || request.filters.size() == 0 ">
and (api_scenario.status is null or api_scenario.status != 'Trash')
</if>
<if test="request.executeStatus == 'unExecute'">
<if test="request.executeStatus == 'unExecute' and request.selectDataType != 'schedule' ">
and api_scenario.last_result IS NULL
</if>
<if test="request.executeStatus == 'executeFailed'">
<if test="request.executeStatus == 'executeFailed' and request.selectDataType != 'schedule' ">
and api_scenario.last_result = 'Fail'
</if>
<if test="request.executeStatus == 'executePass'">
<if test="request.executeStatus == 'executePass' and request.selectDataType != 'schedule' ">
and api_scenario.last_result = 'Success'
</if>
<if test="request.executeStatus == 'fakeError' and request.selectDataType != 'schedule' ">
and api_scenario.last_result = 'errorReportResult'
</if>
<if test="request.executeStatus == 'notSuccess' and request.selectDataType != 'schedule' ">
and api_scenario.last_result IN ('Fail','errorReportResult')
</if>
<if test="request.executeStatus == 'executeFailed' and request.selectDataType == 'schedule' ">
AND api_scenario.id IN
(SELECT source_id FROM scenario_execution_info WHERE trigger_mode = 'SCHEDULE' AND result = 'Error')
</if>
<if test="request.executeStatus == 'executePass' and request.selectDataType == 'schedule' ">
AND api_scenario.id IN
(SELECT source_id FROM scenario_execution_info WHERE trigger_mode = 'SCHEDULE' AND result = 'Success')
</if>
<if test="request.executeStatus == 'fakeError' and request.selectDataType == 'schedule' ">
AND api_scenario.id IN
(SELECT source_id FROM scenario_execution_info WHERE trigger_mode = 'SCHEDULE' AND result =
'errorReportResult')
</if>
<if test="request.executeStatus == 'notSuccess' and request.selectDataType == 'schedule' ">
AND api_scenario.id IN
(SELECT source_id FROM scenario_execution_info WHERE trigger_mode = 'SCHEDULE' AND result IN
('errorReportResult','Error'))
</if>
<if test="request.notInTestPlan">
and api_scenario.id not in (
select pc.api_scenario_id
@ -679,6 +711,12 @@
<if test="request.executeStatus == 'executePass'">
and api_scenario.last_result = 'Success'
</if>
<if test="request.executeStatus == 'fakeError'">
and api_scenario.last_result = 'errorReportResult'
</if>
<if test="request.executeStatus == 'notSuccess'">
and api_scenario.last_result IN ('Fail','errorReportResult')
</if>
<if test="request.notInTestPlan == true ">
and api_scenario.id not in (
select pc.api_scenario_id

View File

@ -2,9 +2,13 @@
<!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.ExtApiScenarioReferenceIdMapper">
<select id="selectUrlByProjectId" resultType="io.metersphere.base.domain.ApiScenarioReferenceId">
SELECT method,url from api_scenario_reference_id WHERE api_scenario_id in (
SELECT id from api_scenario WHERE project_id = #{0}
) AND url IS NOT NULL AND method IS NOT NULL;
SELECT method, url, reference_id
from api_scenario_reference_id
WHERE api_scenario_id in (SELECT id
from api_scenario
WHERE project_id = #{0}
AND latest = 1)
AND reference_id IS NOT NULL;
</select>
</mapper>

View File

@ -169,7 +169,7 @@
s_r.trigger_mode,
s_r.execute_type,
s_r.report_type
FROM api_scenario_report s_r
FROM api_scenario_report s_r
<where>
<if test="request.combine != null">
<include refid="listCombine">
@ -241,32 +241,32 @@
<select id="idList" resultType="java.lang.String">
select r.id from (
SELECT s_r.name AS test_name,
s_r.end_time,
s_r.user_id,
s_r.name,
s_r.id,
s_r.project_id,
s_r.create_time,
s_r.update_time,
s_r.status,
s_r.trigger_mode,
s_r.execute_type,
s_r.report_type
SELECT s_r.name AS test_name,
s_r.end_time,
s_r.user_id,
s_r.name,
s_r.id,
s_r.project_id,
s_r.create_time,
s_r.update_time,
s_r.status,
s_r.trigger_mode,
s_r.execute_type,
s_r.report_type
FROM api_scenario_report s_r
union all
select a_r.name as test_name,
a_r.end_time,
a_r.user_id,
a_r.name,
a_r.id,
a_r.project_id,
a_r.create_time,
a_r.create_time as update_time,
a_r.status,
a_r.trigger_mode,
'Saved' as execute_type,
'API_INDEPENDENT' as report_type
a_r.end_time,
a_r.user_id,
a_r.name,
a_r.id,
a_r.project_id,
a_r.create_time,
a_r.create_time as update_time,
a_r.status,
a_r.trigger_mode,
'Saved' as execute_type,
'API_INDEPENDENT' as report_type
from api_definition_exec_result a_r
where a_r.integrated_report_id is null or a_r.integrated_report_id = 'null'
) r
@ -357,27 +357,24 @@
<select id="countByProjectIdAndCreateAndByScheduleInThisWeek" resultType="java.lang.Long">
SELECT count(ar.id) AS countNumber
FROM api_scenario_report ar
INNER JOIN (
SELECT acitem.`name`, acitem.id
FROM api_scenario acitem
INNER JOIN `schedule` sc ON acitem.id = sc.resource_id and latest = 1
) ac on ar.scenario_id = ac.id
WHERE ar.project_id = #{projectId}
AND ar.trigger_mode = 'SCHEDULE'
AND ar.create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
FROM scenario_execution_info ar
WHERE trigger_mode = 'SCHEDULE'
AND source_id IN (SELECT id
FROM api_scenario
WHERE project_id = #{projectId}
AND latest = 1)
AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
</select>
<select id="countByProjectIdGroupByExecuteResult" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
SELECT count(ar.id) AS countNumber, ar.status AS groupField
FROM api_scenario_report ar
INNER JOIN (
SELECT acitem.`name`, acitem.id
FROM api_scenario acitem
INNER JOIN `schedule` sc ON acitem.id = sc.resource_id and latest = 1
) ac on ar.scenario_id = ac.id
WHERE ar.project_id = #{projectId}
AND ar.trigger_mode = 'SCHEDULE'
SELECT count(id) AS countNumber, result AS groupField
FROM scenario_execution_info ar
WHERE trigger_mode = 'SCHEDULE'
AND source_id IN (SELECT id
FROM api_scenario
WHERE project_id = #{projectId}
AND latest = 1)
GROUP BY groupField;
</select>
<select id="selectLastReportByIds" resultType="io.metersphere.base.domain.ApiScenarioReport">
@ -410,7 +407,7 @@
and scenario_id = #{scenarioId}
and id != #{nowId}
ORDER BY create_time desc
LIMIT 5, 1
LIMIT 5, 1
</select>
<select id="countByApiScenarioId" resultType="io.metersphere.dto.ApiReportCountDTO">
@ -429,7 +426,8 @@
and t.execute_type != 'Debug'
and t.execute_type != 'Marge'
and t.project_id = #{projectId}
and t.`STATUS` in ('running', 'waiting')
and t.`STATUS` in ('running'
, 'waiting')
</select>
@ -455,8 +453,9 @@
</foreach>
</update>
<select id="findByProjectIds" resultType="io.metersphere.base.domain.ApiScenarioReport" parameterType="java.lang.String">
select actuator ,id from api_scenario_report where status in ("running","starting","waiting") and project_id in
<select id="findByProjectIds" resultType="io.metersphere.base.domain.ApiScenarioReport"
parameterType="java.lang.String">
select actuator ,id from api_scenario_report where status in ("running","starting","waiting") and project_id in
<foreach collection="request.projects" item="id" separator="," open="(" close=")">
#{id}
</foreach>

View File

@ -1,6 +1,7 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.datacount.response.ExecuteResultCountDTO;
import io.metersphere.api.dto.definition.*;
import io.metersphere.base.domain.ApiDefinition;
import io.metersphere.base.domain.ApiTestCase;
@ -80,4 +81,6 @@ public interface ExtApiTestCaseMapper {
int toBeUpdateCase(@Param("ids") List<String> ids, @Param("toBeUpdate") Boolean toBeUpdate);
int countById(String resourceID);
List<ExecuteResultCountDTO> selectExecuteResultByProjectId(String projectId);
}

View File

@ -428,6 +428,21 @@
#{nodeId}
</foreach>
</if>
<if test="request.redirectFilter == 'unexecuteCount' ">
and (t1.status IS NULL or t1.status = '')
</if>
<if test="request.redirectFilter == 'executionPassCount' ">
and t1.status = 'success'
</if>
<if test="request.redirectFilter == 'executionFailedCount' ">
and t1.status = 'error'
</if>
<if test="request.redirectFilter == 'fakeErrorCount' ">
and t1.status = 'errorReportResult'
</if>
<if test="request.redirectFilter == 'notSuccessCount' ">
and t1.status IN ('error','errorReportResult')
</if>
<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">
@ -913,4 +928,17 @@
from api_test_case
where id = #{0}
</select>
<select id="selectExecuteResultByProjectId"
resultType="io.metersphere.api.dto.datacount.response.ExecuteResultCountDTO">
SELECT status AS execResult, count(id) AS `count`
FROM api_test_case
WHERE project_id = #{0}
AND (`status` IS NULL OR `status` != 'Trash')
AND api_definition_id IN (SELECT id
FROM api_definition
WHERE project_id = #{0}
AND latest = 1)
GROUP BY `status`
</select>
</mapper>

View File

@ -2,7 +2,7 @@ package io.metersphere.commons.constants;
public enum ExecuteResult {
//误报状态
ERROR_REPORT_RESULT("errorReportResult"),
ERROR_REPORT_RESULT("errorReportResult"), ERROR_REPORT("errorReport"),
//停止状态
STOP("STOP"),
//接口执行状态(兼容旧数据)

View File

@ -30,8 +30,8 @@ public class ProjectApplicationController {
}
@GetMapping("/get/{projectId}/{type}")
public ProjectApplication getProjectApplication(@PathVariable String projectId,@PathVariable String type) {
return projectApplicationService.getProjectApplication(projectId,type);
public ProjectApplication getProjectApplication(@PathVariable String projectId, @PathVariable String type) {
return projectApplicationService.getProjectApplication(projectId, type);
}
@GetMapping("/get/config/{projectId}")

View File

@ -23,13 +23,14 @@ public class ApiCaseExecutionInfoService {
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Lazy
public void insertExecutionInfo(String apiCaseId, String result) {
public void insertExecutionInfo(String apiCaseId, String result, String triggerMode) {
if (StringUtils.isNotEmpty(apiCaseId) && StringUtils.isNotEmpty(result)) {
ApiCaseExecutionInfo executionInfo = new ApiCaseExecutionInfo();
executionInfo.setResult(result);
executionInfo.setSourceId(apiCaseId);
executionInfo.setId(UUID.randomUUID().toString());
executionInfo.setCreateTime(System.currentTimeMillis());
executionInfo.setTriggerMode(triggerMode);
apiCaseExecutionInfoMapper.insert(executionInfo);
}
}

View File

@ -50,23 +50,24 @@ public class ApiExecutionInfoService {
} else {
boolean isApiCase = extApiTestCaseMapper.countById(resourceID) > 0;
if (isApiCase) {
this.insertApiCaseExecutionInfo(resourceID, result.getStatus());
this.insertApiCaseExecutionInfo(resourceID, result.getStatus(), result.getTriggerMode());
} else {
String apiCaseIdInTestPlan = extTestPlanApiCaseMapper.getApiTestCaseIdById(resourceID);
if (StringUtils.isNotEmpty(apiCaseIdInTestPlan)) {
this.insertApiCaseExecutionInfo(apiCaseIdInTestPlan, result.getStatus());
this.insertApiCaseExecutionInfo(resourceID, result.getStatus(), result.getTriggerMode());
}
}
}
}
}
private void insertApiCaseExecutionInfo(String resourceID, String status) {
private void insertApiCaseExecutionInfo(String resourceID, String status, String triggerMode) {
ApiCaseExecutionInfo info = new ApiCaseExecutionInfo();
info.setId(UUID.randomUUID().toString());
info.setSourceId(resourceID);
info.setCreateTime(System.currentTimeMillis());
info.setResult(status);
info.setTriggerMode(triggerMode);
apiCaseExecutionInfoMapper.insert(info);
}

View File

@ -22,34 +22,29 @@ public class ScenarioExecutionInfoService {
private ScenarioExecutionInfoMapper scenarioExecutionInfoMapper;
@Lazy
public void insertExecutionInfo(String scenarioId, String result) {
public void insertExecutionInfo(String scenarioId, String result, String triggerMode) {
if (StringUtils.isNotEmpty(scenarioId) && StringUtils.isNotEmpty(result)) {
ScenarioExecutionInfo executionInfo = new ScenarioExecutionInfo();
executionInfo.setResult(result);
executionInfo.setSourceId(scenarioId);
executionInfo.setId(UUID.randomUUID().toString());
executionInfo.setCreateTime(System.currentTimeMillis());
executionInfo.setTriggerMode(triggerMode);
scenarioExecutionInfoMapper.insert(executionInfo);
}
}
public void insertExecutionInfoByScenarioIds(String scenarioIdJsonString, String status) {
public void insertExecutionInfoByScenarioIds(String scenarioIdJsonString, String status, String triggerMode) {
try {
List<String> scenarioIdList = JSONArray.parseArray(scenarioIdJsonString, String.class);
for (String scenarioId : scenarioIdList) {
this.insertExecutionInfo(scenarioId, status);
this.insertExecutionInfo(scenarioId, status, triggerMode);
}
} catch (Exception e) {
LogUtil.error("解析场景ID的JSON" + scenarioIdJsonString + "失败!", e);
}
}
public void deleteByScenarioId(String resourceId) {
ScenarioExecutionInfoExample example = new ScenarioExecutionInfoExample();
example.createCriteria().andSourceIdEqualTo(resourceId);
scenarioExecutionInfoMapper.deleteByExample(example);
}
public void deleteByScenarioIdList(List<String> resourceIdList) {
if (CollectionUtils.isNotEmpty(resourceIdList)) {
ScenarioExecutionInfoExample example = new ScenarioExecutionInfoExample();

View File

@ -9,12 +9,12 @@
<!-- 此处指定生成针对MyBatis3的DAO -->
<context id="mysql" targetRuntime="MyBatis3">
<!-- 字段带`,解决列表跟关键字冲突问题 -->
<property name="autoDelimitKeywords" value="true" />
<property name="beginningDelimiter" value="`" />
<property name="endingDelimiter" value="`" />
<property name="autoDelimitKeywords" value="true"/>
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
<!-- Lombok插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.LombokPlugin">
<!-- @Data 默认开启,同时插件会对子类自动附加@EqualsAndHashCode(callSuper = true)@ToString(callSuper = true) -->
@ -71,22 +71,23 @@
<!--<table tableName="test_plan"/>-->
<!--<table tableName="api_scenario_report"/>-->
<!--<table tableName="test_case_review"/>-->
<!-- <table tableName="project">-->
<!-- <ignoreColumn column="custom_num"/>-->
<!-- <ignoreColumn column="scenario_custom_num"/>-->
<!-- <ignoreColumn column="mock_tcp_port"/>-->
<!-- <ignoreColumn column="is_mock_tcp_open"/>-->
<!-- <ignoreColumn column="api_quick"/>-->
<!-- <ignoreColumn column="case_public"/>-->
<!-- <ignoreColumn column="clean_track_report"/>-->
<!-- <ignoreColumn column="clean_track_report_expr"/>-->
<!-- <ignoreColumn column="clean_api_report"/>-->
<!-- <ignoreColumn column="clean_api_report_expr"/>-->
<!-- <ignoreColumn column="clean_load_report"/>-->
<!-- <ignoreColumn column="clean_load_report_expr"/>-->
<!-- <ignoreColumn column="repeatable"/>-->
<!-- </table>-->
<table tableName="api_test_case"/>
<!-- <table tableName="project">-->
<!-- <ignoreColumn column="custom_num"/>-->
<!-- <ignoreColumn column="scenario_custom_num"/>-->
<!-- <ignoreColumn column="mock_tcp_port"/>-->
<!-- <ignoreColumn column="is_mock_tcp_open"/>-->
<!-- <ignoreColumn column="api_quick"/>-->
<!-- <ignoreColumn column="case_public"/>-->
<!-- <ignoreColumn column="clean_track_report"/>-->
<!-- <ignoreColumn column="clean_track_report_expr"/>-->
<!-- <ignoreColumn column="clean_api_report"/>-->
<!-- <ignoreColumn column="clean_api_report_expr"/>-->
<!-- <ignoreColumn column="clean_load_report"/>-->
<!-- <ignoreColumn column="clean_load_report_expr"/>-->
<!-- <ignoreColumn column="repeatable"/>-->
<!-- </table>-->
<table tableName="api_case_execution_info"/>
<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"/>
@ -110,7 +111,7 @@
<!-- 表名和关键字冲突-->
<!-- <table tableName="group" delimitIdentifiers="true"></table>-->
<!-- <table tableName="group" delimitIdentifiers="true"></table>-->
</context>
</generatorConfiguration>

View File

@ -176,6 +176,9 @@ export default {
sessionStorage.setItem(PROJECT_ID, projectId);
}
},
activated() {
this.selectNodeIds = [];
},
mounted() {
this.getProject();
this.getTrashCase();
@ -707,7 +710,13 @@ export default {
gotoTurn(resource, workspaceId, isTurnSpace) {
let automationData = this.$router.resolve({
name: 'ApiAutomation',
params: {redirectID: getUUID(), dataType: "scenario", dataSelectRange: 'edit:' + resource.id, projectId: resource.projectId, workspaceId: workspaceId}
params: {
redirectID: getUUID(),
dataType: "scenario",
dataSelectRange: 'edit:' + resource.id,
projectId: resource.projectId,
workspaceId: workspaceId
}
});
if (isTurnSpace) {
window.open(automationData.href, '_blank');

View File

@ -310,7 +310,15 @@
</template>
<script>
import {downloadFile, getCurrentProjectID, getUUID, hasLicense, hasPermission, objToStrMap, strMapToObj} from "@/common/js/utils";
import {
downloadFile,
getCurrentProjectID,
getUUID,
hasLicense,
hasPermission,
objToStrMap,
strMapToObj
} from "@/common/js/utils";
import {API_SCENARIO_CONFIGS} from "@/business/components/common/components/search/search-components";
import {API_SCENARIO_LIST} from "../../../../../common/js/constants";
@ -430,6 +438,7 @@ export default {
schedule: {},
tableData: [],
selectDataRange: 'all',
selectDataType: 'all',
currentPage: 1,
pageSize: 10,
total: 0,
@ -722,20 +731,27 @@ export default {
//
this.condition.selectThisWeedData = false;
this.condition.executeStatus = null;
this.isSelectThissWeekData();
this.condition.selectDataType = this.selectDataType;
this.isRedirectFilter();
switch (this.selectDataRange) {
case 'thisWeekCount':
this.condition.selectThisWeedData = true;
break;
case 'unExecute':
case 'unexecuteCount':
this.condition.executeStatus = 'unExecute';
break;
case 'executeFailed':
case 'executionFailedCount':
this.condition.executeStatus = 'executeFailed';
break;
case 'executePass':
case 'fakeErrorCount':
this.condition.executeStatus = 'fakeError';
break;
case 'executionPassCount':
this.condition.executeStatus = 'executePass';
break;
case 'notSuccessCount':
this.condition.executeStatus = 'notSuccess';
break;
}
if (this.selectDataRange != null) {
let selectParamArr = this.selectDataRange.split(":");
@ -1153,9 +1169,16 @@ export default {
this.showReportId = row.reportId;
},
//
isSelectThissWeekData() {
let dataRange = this.$route.params.dataSelectRange;
this.selectDataRange = dataRange;
isRedirectFilter() {
this.selectDataRange = "all";
this.selectDataType = "all";
let routeParamObj = this.$route.params.paramObj;
if (routeParamObj) {
let dataRange = routeParamObj.dataSelectRange;
let dataType = routeParamObj.dataType;
this.selectDataRange = dataRange;
this.selectDataType = dataType;
}
},
changeSelectDataRangeAll() {
this.$emit("changeSelectDataRangeAll");

View File

@ -61,7 +61,6 @@
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="true"
:queryDataType="queryDataType"
:selectDataRange="selectDataRange"
:is-read-only="isReadOnly"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@ -81,7 +80,6 @@
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="true"
:queryDataType="queryDataType"
:is-read-only="isReadOnly"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@handleCase="handleCase"
@ -122,7 +120,6 @@
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="false"
:queryDataType="queryDataType"
:selectDataRange="selectDataRange"
:is-read-only="isReadOnly"
@runTest="runTest"
@ -146,7 +143,6 @@
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="false"
:queryDataType="queryDataType"
:is-read-only="isReadOnly"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@handleCase="handleCase"
@ -271,20 +267,12 @@ import MsEditCompleteContainer from "./components/EditCompleteContainer";
import MsEnvironmentSelect from "./components/case/MsEnvironmentSelect";
import {PROJECT_ID, WORKSPACE_ID} from "@/common/js/constants";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
export default {
name: "ApiDefinition",
computed: {
queryDataType: function () {
let routeParam = this.$route.params.dataType;
let redirectIDParam = this.$route.params.redirectID;
this.changeRedirectParam(redirectIDParam);
return routeParam;
},
isReadOnly() {
return false;
},
@ -367,29 +355,31 @@ export default {
},
activated() {
this.selectNodeIds = [];
let dataRange = this.$route.params.dataSelectRange;
if (dataRange && dataRange.length > 0) {
this.activeDom = 'middle';
}
let dataType = this.$route.params.dataType;
if (dataType) {
if (dataType === "api") {
this.activeDom = 'left';
} else {
let routeParamObj = this.$route.params.paramObj;
if (routeParamObj) {
let dataRange = routeParamObj.dataSelectRange;
if (dataRange && dataRange.length > 0) {
this.activeDom = 'middle';
}
}
if (this.$route.params.dataSelectRange) {
let item = JSON.parse(JSON.stringify(this.$route.params.dataSelectRange)).param;
if (item !== undefined) {
let type = item.taskGroup.toString();
if (type === "SWAGGER_IMPORT") {
this.handleTabsEdit(this.$t('api_test.api_import.timing_synchronization'), 'SCHEDULE');
this.param = item;
let dataType = routeParamObj.dataType;
if (dataType) {
if (dataType === "api") {
this.activeDom = 'left';
} else {
this.activeDom = 'middle';
}
}
if (routeParamObj.dataSelectRange) {
let item = JSON.parse(JSON.stringify(routeParamObj.dataSelectRange)).param;
if (item !== undefined) {
let type = item.taskGroup.toString();
if (type === "SWAGGER_IMPORT") {
this.handleTabsEdit(this.$t('api_test.api_import.timing_synchronization'), 'SCHEDULE');
this.param = item;
}
}
}
}
},
watch: {
@ -420,22 +410,29 @@ export default {
},
},
created() {
let workspaceId = this.$route.params.workspaceId;
if (workspaceId) {
sessionStorage.setItem(WORKSPACE_ID, workspaceId);
} else {
if (this.$route.query.workspaceId) {
workspaceId = this.$route.query.workspaceId;
let routeParamObj = this.$route.params.paramObj;
if (routeParamObj) {
let workspaceId = routeParamObj.workspaceId;
if (workspaceId) {
sessionStorage.setItem(WORKSPACE_ID, workspaceId);
} else {
if (this.$route.query.workspaceId) {
workspaceId = this.$route.query.workspaceId;
sessionStorage.setItem(WORKSPACE_ID, workspaceId);
}
}
}
let projectId = this.$route.params.projectId;
if (projectId) {
sessionStorage.setItem(PROJECT_ID, projectId);
} else {
if (this.$route.query.projectId) {
projectId = this.$route.query.projectId;
sessionStorage.setItem(PROJECT_ID, this.$route.query.projectId);
let projectId = routeParamObj.projectId;
if (projectId) {
sessionStorage.setItem(PROJECT_ID, projectId);
} else {
if (this.$route.query.projectId) {
projectId = this.$route.query.projectId;
sessionStorage.setItem(PROJECT_ID, projectId);
}
}
//
if (this.routeParamObj.caseId) {
this.activeDom = 'middle';
}
}
this.getEnv();
@ -714,16 +711,19 @@ export default {
this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug", id);
},
init() {
let dataRange = this.$route.params.dataSelectRange;
let dataType = this.$route.params.dataType;
if (dataRange) {
let selectParamArr = dataRange.split("edit:");
if (selectParamArr.length === 2) {
let scenarioId = selectParamArr[1];
if (dataType === 'api') {
this.$get('/api/definition/get/' + scenarioId, (response) => {
this.editApi(response.data);
});
let routeParamObj = this.$route.params.paramObj;
if (routeParamObj) {
let dataRange = routeParamObj.dataSelectRange;
let dataType = routeParamObj.dataType;
if (dataRange) {
let selectParamArr = dataRange.split("edit:");
if (selectParamArr.length === 2) {
let scenarioId = selectParamArr[1];
if (dataType === 'api') {
this.$get('/api/definition/get/' + scenarioId, (response) => {
this.editApi(response.data);
});
}
}
}
}
@ -872,7 +872,9 @@ export default {
this.nodeTree = data;
},
changeSelectDataRangeAll(tableType) {
this.$route.params.dataSelectRange = 'all';
if (this.$route.params.paramObj) {
this.$route.params.paramObj.dataSelectRange = 'all';
}
},
enableTrash(data) {
this.initApiTableOpretion = "trashEnable";

View File

@ -758,12 +758,15 @@ export default {
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
//
this.isSelectThisWeekData();
//
this.isRedirectFilter();
this.condition.selectThisWeedData = false;
this.condition.id = null;
this.condition.redirectFilter = null;
if (this.selectDataRange == 'thisWeekCount') {
this.condition.selectThisWeedData = true;
} else if (this.selectDataRange === 'executionPassCount' || this.selectDataRange === 'unexecuteCount' || this.selectDataRange === 'executionFailedCount' || this.selectDataRange === 'fakeErrorCount' || this.selectDataRange === 'notSuccessCount') {
this.condition.redirectFilter = this.selectDataRange;
} else if (this.selectDataRange != null) {
let selectParamArr = this.selectDataRange.split(":");
if (selectParamArr.length === 2) {
@ -1124,12 +1127,15 @@ export default {
}
},
//
isSelectThisWeekData() {
isRedirectFilter() {
this.selectDataRange = "all";
let routeParam = this.$route.params.dataSelectRange;
let dataType = this.$route.params.dataType;
if (dataType === 'apiTestCase') {
this.selectDataRange = routeParam;
let routeParamObj = this.$route.params.paramObj;
if (routeParamObj) {
let routeParam = routeParamObj.dataSelectRange;
let dataType = routeParamObj.dataType;
if (dataType === 'apiTestCase') {
this.selectDataRange = routeParam;
}
}
},
changeSelectDataRangeAll() {

View File

@ -617,16 +617,29 @@ export default {
this.getSelectDataRange();
this.condition.selectThisWeedData = false;
this.condition.apiCaseCoverage = null;
this.condition.apiCoverage = null;
switch (this.selectDataRange) {
case 'thisWeekCount':
this.condition.selectThisWeedData = true;
break;
case 'uncoverage':
case 'notCoverate':
this.condition.apiCoverage = 'uncoverage';
break;
case 'coverate':
this.condition.apiCoverage = 'coverage';
break;
case 'unCoverageTestCase':
this.condition.apiCaseCoverage = 'uncoverage';
break;
case 'coverage':
case 'coverageTestCase':
this.condition.apiCaseCoverage = 'coverage';
break;
case 'coverageScenario':
this.condition.scenarioCoverage = 'coverage';
break;
case 'unCoverageScenario':
this.condition.scenarioCoverage = 'uncoverage';
break;
case 'Prepare':
this.condition.filters.status = [this.selectDataRange];
break;
@ -895,16 +908,19 @@ export default {
},
//
getSelectDataRange() {
let dataRange = this.$route.params.dataSelectRange;
let dataType = this.$route.params.dataType;
this.selectDataRange = dataType === 'api' ? dataRange : "all";
if (this.selectDataRange &&
Object.prototype.toString.call(this.selectDataRange).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object'
&& this.selectDataRange.indexOf(":") !== -1) {
let selectParamArr = this.selectDataRange.split(":");
if (selectParamArr.length === 2) {
if (selectParamArr[0] === "apiList") {
this.condition.name = selectParamArr[1];
let routeParamObj = this.$route.params.paramObj;
if (routeParamObj) {
let dataRange = routeParamObj.dataSelectRange;
let dataType = routeParamObj.dataType;
this.selectDataRange = dataType === 'api' ? dataRange : "all";
if (this.selectDataRange &&
Object.prototype.toString.call(this.selectDataRange).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object'
&& this.selectDataRange.indexOf(":") !== -1) {
let selectParamArr = this.selectDataRange.split(":");
if (selectParamArr.length === 2) {
if (selectParamArr[0] === "apiList") {
this.condition.name = selectParamArr[1];
}
}
}
}

View File

@ -3,18 +3,20 @@
<ms-main-container v-loading="result.loading">
<el-row :gutter="10" style="margin-bottom: 5px; margin-top: -5px;">
<el-col :span="6" style="padding-left: 5px;padding-right: 0px">
<ms-api-info-card @redirectPage="redirectPage" :api-count-data="apiCountData"
:interface-coverage="apiCoverage"/>
<api-count-card @redirectPage="redirectPage" :api-count-data="apiCountData"
:api-coverage="apiCoverage"/>
</el-col>
<el-col :span="6" style="padding-left: 5px;padding-right: 0px">
<ms-test-case-info-card @redirectPage="redirectPage" :test-case-count-data="testCaseCountData"/>
<api-case-count-card @redirectPage="redirectPage" :test-case-count-data="testCaseCountData"
:is-xpack="isXpack"/>
</el-col>
<el-col :span="6" style="padding-left: 5px;padding-right: 0px">
<ms-scene-info-card @redirectPage="redirectPage" :scene-count-data="sceneCountData"
:interface-coverage="interfaceCoverage"/>
<scenario-count-card @redirectPage="redirectPage" :scene-count-data="sceneCountData" :is-xpack="isXpack"
:scenario-coverage="scenarioCoverage"/>
</el-col>
<el-col :span="6" style="padding-left: 5px;padding-right: 5px">
<ms-schedule-task-info-card :schedule-task-count-data="scheduleTaskCountData"/>
<schedule-task-count-card @redirectPage="redirectPage" :schedule-task-count-data="scheduleTaskCountData"
:is-xpack="isXpack"/>
</el-col>
</el-row>
@ -36,7 +38,8 @@
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="caseTitle">
<el-radio v-model="testTitleFirst" label="caseTitle">{{
$t('api_test.home_page.failed_case_list.title')}}
$t('api_test.home_page.failed_case_list.title')
}}
</el-radio>
</el-dropdown-item>
<el-dropdown-item command="taskTitle">
@ -67,7 +70,7 @@
<el-col :span="12" style="padding-left: 5px;padding-right: 5px">
<el-card class="table-card" v-loading="result.loading" body-style="padding:10px;">
<div v-if="testTitleSecond === 'caseTitle'">
<ms-api-failure-test-case-list @redirectPage="redirectPage" />
<ms-api-failure-test-case-list @redirectPage="redirectPage"/>
</div>
<div v-if="testTitleSecond === 'taskTitle'">
<ms-api-running-task-list :call-from="'api_test'" @redirectPage="redirectPage"/>
@ -128,27 +131,38 @@ import MsApiFailureTestCaseList from "./components/ApiFailureTestCaseList";
import MsFailureTestCaseList from "./components/FailureTestCaseList";
import MsRunningTaskList from "./components/RunningTaskList";
import MsApiRunningTaskList from "./components/ApiRunningTaskList";
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import {getCurrentProjectID, getUUID, hasLicense} from "@/common/js/utils";
import MsApiNewTestCaseList from "./components/ApiNewTestCaseList";
import ApiCountCard from "@/business/components/api/homepage/components/card/ApiCountCard";
import ApiCaseCountCard from "@/business/components/api/homepage/components/card/ApiCaseCountCard";
import ScenarioCountCard from "@/business/components/api/homepage/components/card/ScenarioCountCard";
import ScheduleTaskCountCard from "@/business/components/api/homepage/components/card/ScheduleTaskCountCard";
export default {
name: "ApiTestHomePage",
components: {
MsApiInfoCard, MsSceneInfoCard, MsScheduleTaskInfoCard, MsTestCaseInfoCard,
MsApiFailureTestCaseList, MsRunningTaskList,
MsMainContainer, MsContainer,MsFailureTestCaseList,MsApiRunningTaskList,MsApiNewTestCaseList
MsMainContainer, MsContainer, MsFailureTestCaseList, MsApiRunningTaskList, MsApiNewTestCaseList,
ApiCountCard, ApiCaseCountCard, ScenarioCountCard, ScheduleTaskCountCard
},
data() {
return {
isXpack: false,
values: [],
apiCountData: {},
sceneCountData: {},
testCaseCountData: {},
scheduleTaskCountData: {},
interfaceCoverage: "waitting...",
apiCoverage: "waitting...",
apiCoverage: {
rateOfCoverage: "waitting...",
},
scenarioCoverage: {
rateOfCoverage: "waitting...",
},
result: {},
testTitleFirst: " ",
testTitleSecond: " ",
@ -166,8 +180,8 @@ export default {
this.testTitleFirst = localStorage.getItem("titleFirst");
}
this.cardTitle.name = localStorage.getItem("cardTitle");
} else{
this.cardTitle.name=this.$t('api_test.home_page.failed_case_list.title');
} else {
this.cardTitle.name = this.$t('api_test.home_page.failed_case_list.title');
}
this.testTitleSecond = "taskTitle";
if (localStorage.getItem("cardTitleSecond")) {
@ -175,50 +189,50 @@ export default {
this.testTitleSecond = localStorage.getItem("titleSecond");
}
this.cardTitleSecond.name = localStorage.getItem("cardTitleSecond");
} else{
this.cardTitleSecond.name=this.$t('api_test.home_page.running_task_list.title');
} else {
this.cardTitleSecond.name = this.$t('api_test.home_page.running_task_list.title');
}
},
methods: {
handleCommand(cmd) {
if(cmd){
if (cmd) {
switch (cmd) {
case "caseTitle":
this.cardTitle.name=this.$t('api_test.home_page.failed_case_list.title');
localStorage.setItem("cardTitle" , this.cardTitle.name);
localStorage.setItem("titleFirst" , "caseTitle");
this.cardTitle.name = this.$t('api_test.home_page.failed_case_list.title');
localStorage.setItem("cardTitle", this.cardTitle.name);
localStorage.setItem("titleFirst", "caseTitle");
break;
case "taskTitle":
this.cardTitle.name = this.$t('api_test.home_page.running_task_list.title');
localStorage.setItem("cardTitle" , this.cardTitle.name);
localStorage.setItem("titleFirst" , "taskTitle");
localStorage.setItem("cardTitle", this.cardTitle.name);
localStorage.setItem("titleFirst", "taskTitle");
break;
case "newApiTitle":
this.cardTitle.name = this.$t('api_test.home_page.new_case_list.title');
localStorage.setItem("cardTitle" , this.cardTitle.name);
localStorage.setItem("titleFirst" , "newApiTitle");
localStorage.setItem("cardTitle", this.cardTitle.name);
localStorage.setItem("titleFirst", "newApiTitle");
break;
}
}
},
handleCommandSecond(cmd) {
if(cmd){
if (cmd) {
switch (cmd) {
case "caseTitle":
this.cardTitleSecond.name=this.$t('api_test.home_page.failed_case_list.title');
localStorage.setItem("cardTitleSecond" , this.cardTitleSecond.name);
localStorage.setItem("titleSecond" , "caseTitle");
this.cardTitleSecond.name = this.$t('api_test.home_page.failed_case_list.title');
localStorage.setItem("cardTitleSecond", this.cardTitleSecond.name);
localStorage.setItem("titleSecond", "caseTitle");
break;
case "taskTitle":
this.cardTitleSecond.name = this.$t('api_test.home_page.running_task_list.title');
localStorage.setItem("cardTitleSecond" , this.cardTitleSecond.name);
localStorage.setItem("titleSecond" , "taskTitle");
localStorage.setItem("cardTitleSecond", this.cardTitleSecond.name);
localStorage.setItem("titleSecond", "taskTitle");
break;
case "newApiTitle":
this.cardTitleSecond.name = this.$t('api_test.home_page.new_case_list.title');
localStorage.setItem("cardTitleSecond" , this.cardTitleSecond.name);
localStorage.setItem("titleSecond" , "newApiTitle");
localStorage.setItem("cardTitleSecond", this.cardTitleSecond.name);
localStorage.setItem("titleSecond", "newApiTitle");
break;
}
}
@ -230,6 +244,10 @@ export default {
});
},
search() {
this.isXpack = hasLicense();
this.searchData();
},
searchData() {
let selectProjectId = getCurrentProjectID();
this.$get("/api/apiCount/" + selectProjectId, response => {
this.apiCountData = response.data;
@ -238,14 +256,22 @@ export default {
this.$get("/api/testSceneInfoCount/" + selectProjectId, response => {
this.sceneCountData = response.data;
});
this.apiCoverage = "waitting...",
this.interfaceCoverage = "waitting...";
this.$get("/api/countInterfaceCoverage/" + selectProjectId, response => {
this.interfaceCoverage = response.data;
this.apiCoverage.rateOfCoverage = "waitting...";
this.scenarioCoverage.rateOfCoverage = "waitting...";
this.$get("/api/countScenarioCoverage/" + selectProjectId, response => {
let respData = response.data;
this.scenarioCoverage.rateOfCoverage = respData.rateOfCoverage;
this.scenarioCoverage.coverate = respData.coverate;
this.scenarioCoverage.notCoverate = respData.notCoverate;
});
this.$get("/api/countApiCoverage/" + selectProjectId, response => {
this.apiCoverage = response.data;
let respData = response.data;
this.apiCoverage.rateOfCoverage = respData.rateOfCoverage;
this.apiCoverage.coverate = respData.coverate;
this.apiCoverage.notCoverate = respData.notCoverate;
});
this.$get("/api/testCaseInfoCount/" + selectProjectId, response => {
@ -260,17 +286,20 @@ export default {
//api
//UUID
let uuid = getUUID();
let redirectObj = {
redirectID: uuid, dataType: dataType, dataSelectRange: selectType
};
switch (page) {
case "api":
this.$router.push({
name: 'ApiDefinition',
params: {redirectID: uuid, dataType: dataType, dataSelectRange: selectType}
params: {paramObj: redirectObj}
});
break;
case "scenario":
this.$router.push({
name: 'ApiAutomation',
params: {redirectID: uuid, dataType: dataType, dataSelectRange: selectType}
params: {paramObj: redirectObj}
});
break;
case "testPlanEdit":

View File

@ -28,10 +28,9 @@
</el-table-column>
<el-table-column prop="testPlan" :label="$t('api_test.home_page.failed_case_list.table_coloum.test_plan')">
<template v-slot:default="{row}">
<div v-for="(testPlan, index) in row.testPlanDTOList" :key="index">
<el-link type="info" @click="redirect('testPlanEdit',testPlan.id)"
v-if="testPlan.name === row.testPlan || row.caseType !== 'apiCase'">
{{ testPlan.name }};
<div>
<el-link type="info" @click="redirect('testPlanEdit',row.testPlanId)">
{{ row.testPlan }}
</el-link>
</div>
</template>

View File

@ -0,0 +1,308 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 5px;"
style="height: 350px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.test_case_count_card.title') }}
</span>
</div>
<!-- 数量统计 -->
<el-container>
<el-aside width="34%">
<count-rectangle-chart :content="testCaseCountData.allApiDataCountNumber"/>
</el-aside>
<el-main style="padding-left: 0px;padding-right: 0px">
<div style="width: 185px; float:right;margin:0 auto">
<el-row align="center" class="hidden-lg-and-down">
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="testCaseCountData.httpCountStr"></div>
</el-col>
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="testCaseCountData.rpcCountStr"></div>
</el-col>
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="testCaseCountData.tcpCountStr"></div>
</el-col>
<el-col :span="6" style="padding: 5px;">
<div class="count-info-div" v-html="testCaseCountData.sqlCountStr"></div>
</el-col>
</el-row>
<el-row align="right" class="hidden-xl-only">
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="testCaseCountData.httpCountStr"></div>
</el-col>
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="testCaseCountData.rpcCountStr"></div>
</el-col>
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="testCaseCountData.tcpCountStr"></div>
</el-col>
<el-col :span="6" style="padding: 5px;">
<div class="count-info-div" v-html="testCaseCountData.sqlCountStr"></div>
</el-col>
</el-row>
</div>
</el-main>
</el-container>
<!-- 本周新增 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 0px;">
<el-row>
<el-col>
{{ $t('api_test.home_page.test_case_details_card.this_week_add') }}
<el-link type="info" @click="redirectPage('thisWeekCount')" target="_blank" style="color: #000000">
{{ testCaseCountData.thisWeekAddedCount }}
</el-link>
{{ $t('api_test.home_page.unit_of_measurement') }}
</el-col>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">
<span class="default-property">
{{
$t('api_test.home_page.test_case_details_card.this_week_execute', [testCaseCountData.thisWeekExecutedCount])
}}
</span>
</el-col>
<el-col :span="8">
&nbsp;&nbsp;&nbsp;&nbsp;
</el-col>
<el-col :span="8">
<span class="main-property">
{{ $t('api_test.home_page.test_case_details_card.executed', [testCaseCountData.executedCount]) }}
</span>
</el-col>
</el-row>
</el-main>
</el-container>
<!-- 用例通过率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;">
<el-row>
<span style="float: left">
{{ $t('api_test.home_page.detail_card.rate.case_pase') + ":" }} &nbsp;&nbsp;
</span>
<span class="rows-count-number" style="font-size: 14px">
<b>
{{ testCaseCountData.passRage }}
</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.api_case_pass') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row v-if="isXpack">
<el-col :span="6">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.unexecute') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('unexecuteCount')" target="_blank">
<b>{{ testCaseCountData.unexecuteCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="6">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.execution_failed') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('executionFailedCount')"
target="_blank">
<b>{{ testCaseCountData.executionFailedCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="6">
<span class="default-property">
{{ $t('error_report_library.option.name') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('fakeErrorCount')" target="_blank">
<b>{{ testCaseCountData.fakeErrorCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="6">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.execution_pass') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('executionPassCount')"
target="_blank">
<b>{{ testCaseCountData.executionPassCount }}</b>
</el-link>
</span>
</el-col>
</el-row>
<el-row v-else>
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.unexecute') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('unexecuteCount')" target="_blank">
<b>{{ testCaseCountData.unexecuteCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.execution_failed') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('notSuccessCount')" target="_blank">
<b>{{ testCaseCountData.executionFailedCount + testCaseCountData.fakeErrorCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.execution_pass') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('executionPassCount')"
target="_blank">
<b>{{ testCaseCountData.executionPassCount }}</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
<!-- 接口覆盖率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;">
<el-row>
<span style="float: left">
{{ $t('api_test.home_page.detail_card.rate.interface_coverage') + ":" }}&nbsp;&nbsp;
</span>
<span class="rows-count-number" style="font-size: 14px">
<b>
{{ testCaseCountData.coverageRage }}
</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.coverage') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.uncoverage') }}
{{ "\xa0\xa0" }}
<el-link type="info" class="rows-count-number" @click="redirectPage('uncoverageCount')" target="_blank">
<b>{{ testCaseCountData.uncoverageCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
&nbsp;&nbsp;&nbsp;&nbsp;
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.coverage') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('coverageCount')" target="_blank">
<b>
{{ testCaseCountData.coverageCount }}
</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
</el-card>
</template>
<script>
import CountRectangleChart from "@/business/components/common/chart/CountRectangleChart";
export default {
name: "ApiCaseCountCard",
components: {CountRectangleChart},
data() {
return {
result: {},
loading: false,
}
},
props: {
testCaseCountData: {},
apiCaseCoverage: Object,
isXpack: Boolean,
},
methods: {
redirectPage(clickType) {
if (clickType === 'uncoverageCount') {
//
this.$emit("redirectPage", "api", "api", "unCoverageTestCase");
} else if (clickType === 'coverageCount') {
//
this.$emit("redirectPage", "api", "api", "coverageTestCase");
} else {
this.$emit("redirectPage", "api", "apiTestCase", clickType);
}
}
},
created() {
},
activated() {
}
}
</script>
<style scoped>
.el-aside {
line-height: 100px;
text-align: center;
}
.rows-count-number {
font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 12px;
color: var(--count_number);
}
.detail-container {
margin-top: 20px
}
.default-property {
font-size: 12px;
}
.main-property {
color: #F39021;
font-size: 12px
}
.el-card /deep/ .el-card__header {
border-bottom: 0px solid #EBEEF5;
}
.count-info-div {
margin: 3px;
}
.count-info-div >>> p {
font-size: 10px;
}
.info-tool-tip {
position: absolute;
top: 0;
}
</style>

View File

@ -0,0 +1,228 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 5px;"
style="height: 350px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.api_count_card.title') }}
</span>
</div>
<!-- 数值统计 -->
<el-container>
<el-aside width="34%">
<count-rectangle-chart :content="apiCountData.allApiDataCountNumber"/>
</el-aside>
<el-main style="padding-left: 0px;padding-right: 0px;">
<div style="width: 185px; float:right;margin:0 auto">
<el-row align="right">
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="apiCountData.httpCountStr"></div>
</el-col>
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="apiCountData.rpcCountStr"></div>
</el-col>
<el-col :span="6"
style="padding: 5px;border-right-style: solid;border-right-width: 1px;border-right-color: #ECEEF4;">
<div class="count-info-div" v-html="apiCountData.tcpCountStr"></div>
</el-col>
<el-col :span="6" style="padding: 5px;">
<div class="count-info-div" v-html="apiCountData.sqlCountStr"></div>
</el-col>
</el-row>
</div>
</el-main>
</el-container>
<el-container class="detail-container">
<!-- 本周新增 -->
<el-header style="height:20px;padding: 0px;margin-bottom: 0px;">
<el-row>
<el-col>
{{ $t('api_test.home_page.api_details_card.this_week_add') }}
<el-link type="info" @click="redirectPage('thisWeekCount')" target="_blank" style="color: #000000">
{{ apiCountData.thisWeekAddedCount }}
</el-link>
{{ $t('api_test.home_page.unit_of_measurement') }}
</el-col>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">&nbsp;</el-col>
</el-row>
</el-main>
</el-container>
<!-- 接口完成率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;">
<el-row>
<span style="float: left;">
{{ $t('api_test.home_page.detail_card.rate.api_completion') + ":" }}&nbsp;&nbsp;
</span>
<span class="rows-count-number" style="font-size:14px">
<b>
{{ apiCountData.completionRage }}
</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.completion') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.not_started') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('Prepare')" target="_blank">
<b>{{ apiCountData.notStartedCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.running') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('Underway')" target="_blank">
<b>{{ apiCountData.runningCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.finished') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('Completed')" target="_blank">
<b>{{ apiCountData.finishedCount }}</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
<!-- 接口覆蓋率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;">
<el-row>
<span style="float: left">
{{ $t('api_test.home_page.detail_card.rate.interface_coverage') + ":" }}&nbsp;&nbsp;
</span>
<span v-if="apiCoverage.rateOfCoverage === 'waitting...'">
<i class="el-icon-loading lading-icon"></i>
</span>
<span v-else class="rows-count-number" style="font-size: 14px">
<b>{{ apiCoverage.rateOfCoverage }}</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.api_coverage') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">
<span class="rows-count-number">
{{ $t('api_test.home_page.detail_card.uncoverage') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" type="info" @click="redirectPage('notCoverate')" target="_blank">
<b>
{{ apiCoverage.notCoverate }}
</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
&nbsp;&nbsp;&nbsp;&nbsp;
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.coverage') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('coverate')" target="_blank">
<b>
{{ apiCoverage.coverate }}
</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
</el-card>
</template>
<script>
import CountRectangleChart from "@/business/components/common/chart/CountRectangleChart";
export default {
name: "ApiCountCard",
components: {CountRectangleChart},
data() {
return {
result: {},
loading: false
}
},
props: {
apiCountData: {},
apiCoverage: Object,
},
methods: {
redirectPage(clickType) {
this.$emit("redirectPage", "api", "api", clickType);
}
}
}
</script>
<style scoped>
.el-aside {
line-height: 100px;
text-align: center;
}
.rows-count-number {
font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 12px;
color: var(--count_number);
}
.detail-container {
margin-top: 20px
}
.default-property {
font-size: 12px;
}
.main-property {
color: #F39021;
font-size: 12px
}
.el-card /deep/ .el-card__header {
border-bottom: 0px solid #EBEEF5;
}
.count-info-div {
margin: 3px;
}
.count-info-div >>> p {
font-size: 10px;
}
.info-tool-tip {
position: absolute;
top: 0;
}
</style>

View File

@ -0,0 +1,281 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 5px;"
style="height: 350px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.test_scene_count_card.title') }}
</span>
</div>
<!-- 数量统计 -->
<el-container>
<el-aside width="34%">
<count-rectangle-chart :content="sceneCountData.allApiDataCountNumber"/>
</el-aside>
<el-main style="padding-left: 0px;padding-right: 0px; margin-right: 5px">
<div style="width: 185px; float:right;margin:0 auto">
<el-row align="right">
<span style="text-align: right;display:block;">
{{
$t('api_test.home_page.test_scene_details_card.this_week_execute', [sceneCountData.thisWeekExecutedCount])
}}
</span>
</el-row>
<el-row align="right">
&nbsp;
</el-row>
<el-row align="right">
<span style="text-align: right;display:block;">
{{ $t('api_test.home_page.test_scene_details_card.executed', [sceneCountData.executedCount]) }}
</span>
</el-row>
</div>
</el-main>
</el-container>
<el-container class="detail-container">
<!-- 本周新增 -->
<el-header style="height:20px;padding: 0px;margin-bottom: 0px;">
<el-row>
<el-col>
{{ $t('api_test.home_page.api_details_card.this_week_add') }}
<el-link type="info" @click="redirectPage('thisWeekCount')" target="_blank" style="color: #000000">
{{ sceneCountData.thisWeekAddedCount }}
</el-link>
{{ $t('api_test.home_page.unit_of_measurement') }}
</el-col>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">&nbsp;</el-col>
</el-row>
</el-main>
</el-container>
<!-- 场景通过率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;">
<el-row>
<span style="float: left">
{{ $t('api_test.home_page.detail_card.rate.scenario_pase') + ":" }}&nbsp;&nbsp;
</span>
<span class="rows-count-number" style="font-size: 14px">
<b>
{{ sceneCountData.passRage }}
</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.pass') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row v-if="this.isXpack">
<el-col :span="6">
<span class="rows-count-number">
{{ $t('api_test.home_page.detail_card.unexecute') }}
{{ "\xa0\xa0" }}
<el-link type="info" @click="redirectPage('unexecuteCount')" target="_blank" style="color: #000000">
<b>{{ sceneCountData.unexecuteCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="6">
<span class="rows-count-number" style="float: left">
{{ $t('api_test.home_page.detail_card.execution_failed') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('executionFailedCount')" target="_blank">
<b>
{{ sceneCountData.executionFailedCount }}
</b>
</el-link>
</span>
</el-col>
<el-col :span="6">
<span class="rows-count-number" style="float: left">
{{ $t('error_report_library.option.name') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('fakeErrorCount')" target="_blank">
<b>
{{ sceneCountData.fakeErrorCount }}
</b>
</el-link>
</span>
</el-col>
<el-col :span="6">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.execution_pass') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('executionPassCount')" target="_blank">
<b>
{{ sceneCountData.executionPassCount }}
</b>
</el-link>
</span>
</el-col>
</el-row>
<el-row v-else>
<el-col :span="8">
<span class="rows-count-number">
{{ $t('api_test.home_page.detail_card.unexecute') }}
{{ "\xa0\xa0" }}
<el-link type="info" @click="redirectPage('unexecuteCount')" target="_blank" style="color: #000000">
<b>{{ sceneCountData.unexecuteCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="rows-count-number" style="float: left">
{{ $t('api_test.home_page.detail_card.execution_failed') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('notSuccessCount')" target="_blank">
<b>
{{ sceneCountData.executionFailedCount + sceneCountData.fakeErrorCount }}
</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.execution_pass') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('executionPassCount')" target="_blank">
<b>
{{ sceneCountData.executionPassCount }}
</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
<!-- 场景覆盖率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;">
<el-row>
<span style="float: left">
{{ $t('api_test.home_page.detail_card.rate.interface_coverage') + ":" }}&nbsp;&nbsp;
</span>
<span v-if="scenarioCoverage.rateOfCoverage === 'waitting...'">
<i class="el-icon-loading lading-icon"></i>
</span>
<span v-else class="rows-count-number" style="font-size: 14px">
<b>
{{ scenarioCoverage.rateOfCoverage }}
</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.interface_coverage') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.uncoverage') }}
{{ "\xa0\xa0" }}
<el-link type="info" class="rows-count-number" @click="redirectPage('notCoverate')" target="_blank">
<b>{{ scenarioCoverage.notCoverate }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
&nbsp;&nbsp;&nbsp;&nbsp;
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.coverage') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('coverate')" target="_blank">
<b>{{ scenarioCoverage.coverate }}</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
</el-card>
</template>
<script>
import CountRectangleChart from "@/business/components/common/chart/CountRectangleChart";
export default {
name: "ScenarioCountCard",
components: {CountRectangleChart},
data() {
return {
result: {},
loading: false
}
},
props: {
sceneCountData: {},
scenarioCoverage: Object,
isXpack: Boolean,
},
methods: {
redirectPage(clickType) {
if (clickType === "coverate") {
this.$emit("redirectPage", "api", "api", "coverageScenario");
} else if (clickType === "notCoverate") {
this.$emit("redirectPage", "api", "api", "unCoverageScenario");
} else {
this.$emit("redirectPage", "scenario", "scenario", clickType);
}
}
},
}
</script>
<style scoped>
.el-aside {
line-height: 100px;
text-align: center;
}
.rows-count-number {
font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 12px;
color: var(--count_number);
}
.detail-container {
margin-top: 20px
}
.default-property {
font-size: 12px;
}
.main-property {
color: #F39021;
font-size: 12px
}
.el-card /deep/ .el-card__header {
border-bottom: 0px solid #EBEEF5;
}
.count-info-div {
margin: 3px;
}
.count-info-div >>> p {
font-size: 10px;
}
.info-tool-tip {
position: absolute;
top: 0;
}
</style>

View File

@ -0,0 +1,215 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 5px;"
style="height: 350px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.schedule_task_count_card.title') }}
</span>
</div>
<!-- 数量统计 -->
<el-container>
<el-aside width="34%">
<count-rectangle-chart :content="scheduleTaskCountData.allApiDataCountNumber"/>
</el-aside>
<el-main style="padding-left: 0px;padding-right: 0px; margin-right: 5px">
<div style="width: 185px; float:right;margin:0 auto">
<el-row align="right">
<span style="text-align: right;display:block;">
{{
$t('api_test.home_page.test_scene_details_card.this_week_execute', [scheduleTaskCountData.thisWeekExecutedCount])
}}
</span>
</el-row>
<el-row align="right">
&nbsp;
</el-row>
<el-row align="right">
<span style="text-align: right;display:block;">
{{ $t('api_test.home_page.test_scene_details_card.executed', [scheduleTaskCountData.executedCount]) }}
</span>
</el-row>
</div>
</el-main>
</el-container>
<el-container class="detail-container">
<!-- 本周新增 -->
<el-header style="height:20px;padding: 0px;margin-bottom: 0px;">
<el-row>
<el-col>
{{ $t('api_test.home_page.api_details_card.this_week_add') }}
<el-link type="info" @click="redirectPage('thisWeekCount')" target="_blank" style="color: #000000">
{{ scheduleTaskCountData.thisWeekAddedCount }}
</el-link>
{{ $t('api_test.home_page.unit_of_measurement') }}
</el-col>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row>
<el-col :span="8">&nbsp;</el-col>
</el-row>
</el-main>
</el-container>
<!-- 任务成功率 -->
<el-container class="detail-container">
<el-header style="height:20px;padding: 0px;margin-bottom: 5px;">
<el-row>
<span style="float: left">
{{ $t('api_test.home_page.detail_card.rate.success') + ":" }}&nbsp;&nbsp;
</span>
<span class="rows-count-number" style="font-size: 14px">
<b>
{{ scheduleTaskCountData.successRage }}
</b>
<el-tooltip placement="top" class="info-tool-tip">
<div slot="content">{{ $t('api_test.home_page.formula.success') }}</div>
<el-button icon="el-icon-info" style="padding:0px;border: 0px"></el-button>
</el-tooltip>
</span>
</el-row>
</el-header>
<el-main style="padding:0px">
<el-row v-if="this.isXpack">
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.failed') }}
{{ "\xa0\xa0" }}
<el-link type="info" class="rows-count-number" @click="redirectPage('executionFailedCount')"
target="_blank">
<b>{{ scheduleTaskCountData.failedCount + scheduleTaskCountData.failedCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="default-property">
{{ $t('error_report_library.option.name') }}
{{ "\xa0\xa0" }}
<el-link type="info" class="rows-count-number" @click="redirectPage('fakeErrorCount')" target="_blank">
<b>{{ scheduleTaskCountData.fakeErrorCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.success') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('executionPassCount')" target="_blank">
<b>
{{ scheduleTaskCountData.successCount }}
</b>
</el-link>
</span>
</el-col>
</el-row>
<el-row v-else>
<el-col :span="8">
<span class="default-property">
{{ $t('api_test.home_page.detail_card.failed') }}
{{ "\xa0\xa0" }}
<el-link type="info" class="rows-count-number" @click="redirectPage('notSuccessCount')" target="_blank">
<b>{{ scheduleTaskCountData.failedCount + scheduleTaskCountData.fakeErrorCount }}</b>
</el-link>
</span>
</el-col>
<el-col :span="8">
&nbsp;&nbsp;&nbsp;&nbsp;
</el-col>
<el-col :span="8">
<span class="main-property" style="float: left">
{{ $t('api_test.home_page.detail_card.success') }}
{{ "\xa0\xa0" }}
<el-link class="rows-count-number" @click="redirectPage('executionPassCount')" target="_blank">
<b>
{{ scheduleTaskCountData.successCount }}
</b>
</el-link>
</span>
</el-col>
</el-row>
</el-main>
</el-container>
</el-card>
</template>
<script>
import 'element-ui/lib/theme-chalk/display.css';
import CountRectangleChart from "@/business/components/common/chart/CountRectangleChart";
export default {
name: "MsScheduleTaskInfoCard",
components: {CountRectangleChart},
data() {
return {
result: {},
apiCountData: {},
loading: false
}
},
props: {
scheduleTaskCountData: {},
isXpack: Boolean,
},
methods: {
redirectPage(clickType) {
this.$emit("redirectPage", "scenario", "schedule", clickType);
}
},
created() {
},
activated() {
}
}
</script>
<style scoped>
.el-aside {
line-height: 100px;
text-align: center;
}
.rows-count-number {
font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 12px;
color: var(--count_number);
}
.detail-container {
margin-top: 20px
}
.default-property {
font-size: 12px;
}
.main-property {
color: #F39021;
font-size: 12px
}
.el-card /deep/ .el-card__header {
border-bottom: 0px solid #EBEEF5;
}
.count-info-div {
margin: 3px;
}
.count-info-div >>> p {
font-size: 10px;
}
.info-tool-tip {
position: absolute;
top: 0;
}
</style>

View File

@ -1,5 +1,3 @@
export default {
path: "/api",
name: "api",
@ -30,12 +28,12 @@ export default {
},
{
path: "definition/:redirectID?/:dataType?/:dataSelectRange?/:projectId?/:type?/:workspaceId?",
path: "definition",
name: "ApiDefinition",
component: () => import('@/business/components/api/definition/ApiDefinition'),
},
{
path: "automation/:redirectID?/:dataType?/:dataSelectRange?/:projectId?/:workspaceId?",
path: "automation",
name: "ApiAutomation",
component: () => import('@/business/components/api/automation/ApiAutomation'),
},

View File

@ -0,0 +1,49 @@
<template>
<div class="main-number-show">
<span class="count-number" :class="{'big_count-number': content < 10000}">
{{ content }}
</span>
<span style="color: #6C317C;">
{{ $t('api_test.home_page.unit_of_measurement') }}
</span>
</div>
</template>
<script>
export default {
name: "CountRectangleChart",
props: {
content: {
type: [Number, String]
}
}
}
</script>
<style scoped>
.main-number-show {
height: 62px;
line-height: 62px;
border-style: solid;
border-width: 2px;
border-color: var(--count_number);
background-color: #F1EAF1;
overflow: hidden;
text-overflow: ellipsis;
border-radius: 5%;
white-space: nowrap
}
.count-number {
font-family: 'ArialMT', 'Arial', sans-serif;
font-size: 23px;
color: var(--count_number);
position: relative;
}
.big_count-number {
font-size: 33px;
}
</style>

View File

@ -456,9 +456,9 @@ export default {
delete_all_version: 'All versions',
change_password_tips: 'Your password is the initial system password, please change it as soon as possible',
ui: 'UI TEST',
not_eligible_for_deletion:'Not Eligible For Deletion',
batch:'Batch',
change:'Change',
not_eligible_for_deletion: 'Not Eligible For Deletion',
batch: 'Batch',
change: 'Change',
follow_people: "Follow people",
default_module: {
test_case: 'default',
@ -489,8 +489,8 @@ export default {
expired: 'expired',
},
workstation: {
sync:'Synchronize',
ignore:'Ignore',
sync: 'Synchronize',
ignore: 'Ignore',
dash_board: 'My DashBoard',
upcoming: 'My Upcoming',
focus: 'My Focus',
@ -499,7 +499,7 @@ export default {
creation_issue: 'My Creation Issue',
creation_case_tip: 'No use case has been created yet, create it now',
creation_issue_tip: 'No defects have been created yet, create them now',
delNotSame:'Remove parameters in use cases that cannot correspond to API documentation',
delNotSame: 'Remove parameters in use cases that cannot correspond to API documentation',
table_name: {
track_case: 'Track Case',
track_plan: 'Track Plan',
@ -1812,9 +1812,10 @@ export default {
completion: "finished api / all api * 100%",
coverage: "apis whitch have test case / all apis * 100%",
pass: "scenarios whitch final execute is sucess / all scenarios * 100%",
api_case_pass: "api case whitch final execute is sucess / all api case *100%",
success: "execute success count number / all execute count number * 100%",
interface_coverage: "api whitch in scenario's step / all api * 100%",
api_coverage: "api whitch have case or in scenario's step / all api * 100%",
interface_coverage: "api whitch url in scenario's step / all api * 100%",
api_coverage: "api(URL) whitch have case or in scenario's step / all api * 100%",
review: "reviewed cases / all cases * 100%",
testplan_coverage: "relevance function cases / all function cases * 100%",
},
@ -1842,6 +1843,9 @@ export default {
failed: "Failure",
success: "Success",
rate: {
api_completion: "API Completion",
case_pase: "Case pass rate",
scenario_pase: "Scenario pass rate",
completion: "Completion rate",
coverage: "Coverage",
pass: "Pass rate",

View File

@ -458,9 +458,9 @@ export default {
delete_all_version: '全部版本',
change_password_tips: '您的密码是系统初始密码,请尽快修改密码',
ui: 'UI 测试',
not_eligible_for_deletion:'不符合删除条件',
batch:'批量',
change:'改变',
not_eligible_for_deletion: '不符合删除条件',
batch: '批量',
change: '改变',
follow_people: "关注人",
default_module: {
test_case: '未规划用例',
@ -491,8 +491,8 @@ export default {
expired: '已过期',
},
workstation: {
sync:'同步',
ignore:'忽略',
sync: '同步',
ignore: '忽略',
dash_board: '我的仪表盘',
upcoming: '我的待办',
focus: '我的关注',
@ -501,7 +501,7 @@ export default {
creation_issue: '我创建的缺陷',
creation_case_tip: '暂时还没有创建用例,马上创建',
creation_issue_tip: '暂时还没有创建缺陷,马上创建',
delNotSame:'删除用例中无法与API文档对应的参数',
delNotSame: '删除用例中无法与API文档对应的参数',
table_name: {
track_case: '功能用例',
track_plan: '测试计划',
@ -1819,9 +1819,10 @@ export default {
completion: "已完成的接口/接口总数*100%",
coverage: "有用例的接口/接口总数*100%",
pass: "最后一次执行成功的场景/场景总数*100%",
api_case_pass: "最后一次执行成功的用例/用例总数*100%",
success: "执行成功的次数/执行总次数*100%",
interface_coverage: "被场景步骤包含的接口/接口总数*100%",
api_coverage: "存在用例或被场景步骤包含的接口/接口总数*100%",
interface_coverage: "被场景步骤包含的接口(URL)数/接口总数*100%",
api_coverage: "接口URL用例或场景步骤/接口总数*100%",
review: "已评审的功能案例/所有功能案例 * 100%",
testplan_coverage: "关联的功能案例/所有功能案例 * 100%",
},
@ -1849,6 +1850,9 @@ export default {
failed: "失败",
success: "成功",
rate: {
api_completion: "接口完成率",
case_pase: "用例通过率",
scenario_pase: "场景通过率",
completion: "完成率",
coverage: "覆盖率",
pass: "通过率",

View File

@ -458,9 +458,9 @@ export default {
delete_all_version: '全部版本',
change_password_tips: '您的密碼是系統初始密碼,請盡快修改密碼',
ui: 'UI 測試',
not_eligible_for_deletion:'不符合删除條件',
batch:'批量',
change:'改变',
not_eligible_for_deletion: '不符合删除條件',
batch: '批量',
change: '改变',
follow_people: "關註人",
default_module: {
test_case: '未規劃用例',
@ -491,8 +491,8 @@ export default {
expired: '已過期',
},
workstation: {
sync:'同步',
ignore:'忽略',
sync: '同步',
ignore: '忽略',
dash_board: '我的儀表盤',
upcoming: '我的待辦',
focus: '我的關註',
@ -501,7 +501,7 @@ export default {
creation_issue: '我創建的缺陷',
creation_case_tip: '暫時還沒有創建用例,馬上創建',
creation_issue_tip: '暫時還沒有創建缺陷,馬上創建',
delNotSame:'刪除用例中無法與API文檔對應的參數',
delNotSame: '刪除用例中無法與API文檔對應的參數',
table_name: {
track_case: '功能用例',
track_plan: '測試計劃',
@ -1816,9 +1816,10 @@ export default {
completion: "已完成的接口/接口總數*100%",
coverage: "有用例的接口/接口總數*100%",
pass: "最後一次執行成功的場景/場景總數*100%",
api_case_pass: "最後一次執行成功的案例/案例總數*100%",
success: "執行成功的次數/執行總次數*100%",
interface_coverage: "被場景步驟包含的接口/接口總數*100%",
api_coverage: "存在用例或被場景步驟包含的接口/接口總數*100%",
interface_coverage: "被場景步驟包含的接口URL)數/接口總數*100%",
api_coverage: "接口URL用例或場景步驟/接口總數*100%",
review: "已評審的功能案例/所有功能案例 * 100%",
testplan_coverage: "關聯的功能案例/所有功能案例 * 100%",
},
@ -1846,6 +1847,9 @@ export default {
failed: "失敗",
success: "成功",
rate: {
api_completion: "接口完成率",
case_pase: "用例通過率",
scenario_pase: "場景通過率",
completion: "完成率",
coverage: "覆蓋率",
pass: "通過率",