merge: 合并dev最新修改

This commit is contained in:
BugKing 2021-11-26 15:40:44 +08:00
commit 7f0de8ca96
52 changed files with 512 additions and 267 deletions

View File

@ -196,7 +196,7 @@ public class ApiTestCaseController {
@PostMapping(value = "/jenkins/run")
@MsAuditLog(module = "api_definition_case", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class)
public String jenkinsRun(@RequestBody RunCaseRequest request) {
return apiTestCaseService.run(request);
return apiTestCaseService.jenkinsRun(request);
}
@GetMapping(value = "/jenkins/exec/result/{id}")

View File

@ -121,10 +121,8 @@ public class MsScenario extends MsTestElement {
});
this.setHeaders(headers);
}
if (element.get("environmentMap") != null) {
this.setEnvironmentMap((Map) element.get("environmentMap"));
}
this.setHashTree(sourceHashTree);
hashTree = sourceHashTree;
}
} catch (Exception ex) {

View File

@ -174,9 +174,9 @@ public class MsAssertions extends MsTestElement {
JSR223Assertion assertion = new JSR223Assertion();
assertion.setEnabled(this.isEnable());
if (StringUtils.isNotEmpty(assertionJSR223.getDesc())) {
assertion.setName("JSR223" + "==" + this.getName() + "==" + assertionJSR223.getDesc() + "==" + assertionJSR223.getScript());
assertion.setName("JSR223" + "==" + this.getName() + "==" + assertionJSR223.getDesc() + "&&" + assertionJSR223.getScript());
} else {
assertion.setName("JSR223" + "==" + this.getName() + "==" + "JSR223Assertion" + "==" + assertionJSR223.getScript());
assertion.setName("JSR223" + "==" + this.getName() + "==" + "JSR223Assertion" + "&&" + assertionJSR223.getScript());
}
assertion.setProperty(TestElement.TEST_CLASS, JSR223Assertion.class.getName());
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));

View File

@ -73,7 +73,7 @@ public class ApiJmeterFileService {
}
}
HashTree hashTree;
if (StringUtils.equalsAnyIgnoreCase(runMode, ApiRunMode.DEFINITION.name(), ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
if (StringUtils.equalsAnyIgnoreCase(runMode, ApiRunMode.DEFINITION.name(), ApiRunMode.JENKINS_API_PLAN.name(),ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
String testId = remoteTestId;
if (remoteTestId.contains(":")) {
//执行测试计划案例时会有拼接ID,ID为 planTestCaseId:测试计划报告ID

View File

@ -736,16 +736,20 @@ public class ApiTestCaseService {
return ids;
}
private ApiDefinitionExecResult addResult(String id, String status) {
private ApiDefinitionExecResult addResult(String resourceId, String status, String reportId) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
if (StringUtils.isEmpty(reportId)) {
apiResult.setId(UUID.randomUUID().toString());
} else {
apiResult.setId(reportId);
}
apiResult.setCreateTime(System.currentTimeMillis());
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setEndTime(System.currentTimeMillis());
apiResult.setTriggerMode(TriggerMode.BATCH.name());
apiResult.setActuator("LOCAL");
apiResult.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
apiResult.setResourceId(id);
apiResult.setResourceId(resourceId);
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setType(ApiRunMode.DEFINITION.name());
apiResult.setStatus(status);
@ -765,7 +769,7 @@ public class ApiTestCaseService {
ApiTestCaseMapper sqlSessionMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
for (ApiTestCaseWithBLOBs caseWithBLOBs : list) {
ApiDefinitionExecResult report = addResult(caseWithBLOBs.getId(), APITestStatus.Running.name());
ApiDefinitionExecResult report = addResult(caseWithBLOBs.getId(), APITestStatus.Running.name(), null);
report.setName(caseWithBLOBs.getName());
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
@ -792,6 +796,38 @@ public class ApiTestCaseService {
}
}
public String jenkinsRun(RunCaseRequest request) {
ApiTestCaseWithBLOBs caseWithBLOBs = null;
if (request.getBloBs() == null) {
caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
if (caseWithBLOBs == null) {
return null;
}
request.setBloBs(caseWithBLOBs);
} else {
caseWithBLOBs = request.getBloBs();
}
if (caseWithBLOBs == null) {
return null;
}
if (StringUtils.isBlank(request.getEnvironmentId())) {
request.setEnvironmentId(extApiTestCaseMapper.getApiCaseEnvironment(request.getCaseId()));
}
//提前生成报告
ApiDefinitionExecResult report = addResult(caseWithBLOBs.getId(), APITestStatus.Running.name(), request.getReportId());
report.setName(caseWithBLOBs.getName());
report.setTriggerMode(ApiRunMode.API.name());
report.setType(ApiRunMode.JENKINS.name());
apiDefinitionExecResultMapper.insert(report);
//更新接口案例的最后执行状态等信息
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
request.setReport(report);
return this.run(request);
}
public String run(RunCaseRequest request) {
ApiTestCaseWithBLOBs testCaseWithBLOBs = request.getBloBs();
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) {
@ -800,15 +836,13 @@ public class ApiTestCaseService {
//通过测试计划id查询环境
request.setReportId(request.getTestPlanId());
}
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS.name())) {
request.setReportId(request.getEnvironmentId());
}
// 多态JSON普通转换会丢失内容需要通过 ObjectMapper 获取
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
try {
HashTree jmeterHashTree = this.generateHashTree(request, testCaseWithBLOBs);
// 调用执行方法
jMeterService.runLocal(request.getReportId(),null, jmeterHashTree, null, request.getRunMode());
jMeterService.runLocal(request.getReportId(), null, jmeterHashTree, null, request.getRunMode());
} catch (Exception ex) {
ApiDefinitionExecResult result = MessageCache.caseExecResourceLock.get(request.getReportId());
@ -834,7 +868,7 @@ public class ApiTestCaseService {
request.setTestPlanId(testPlanID);
HashTree jmeterHashTree = this.generateHashTree(request, apiCaseBolbs);
// 调用执行方法
jMeterService.runLocal(id,null, jmeterHashTree, debugReportId, runMode);
jMeterService.runLocal(id, null, jmeterHashTree, debugReportId, runMode);
} catch (Exception ex) {
LogUtil.error(ex);
}
@ -1171,9 +1205,7 @@ public class ApiTestCaseService {
if (StringUtils.isBlank(environmentId)) {
return null;
}
// "environmentId"
try {
environmentId = environmentId.substring(1, environmentId.length() - 1);
return apiTestEnvironmentMapper.selectByPrimaryKey(environmentId);
} catch (Exception e) {
LogUtil.error("api case environmentId incorrect parsing. api case id: " + caseId);

View File

@ -252,14 +252,22 @@ public class MsResultService {
ResponseAssertionResult responseAssertionResult = new ResponseAssertionResult();
responseAssertionResult.setName(assertionResult.getName());
if (StringUtils.isNotEmpty(assertionResult.getName()) && assertionResult.getName().indexOf("==") != -1) {
String[] array = assertionResult.getName().split("==");
if (assertionResult.getName().indexOf("JSR223") != -1) {
String[] array = assertionResult.getName().split("==", 3);
if ("JSR223".equals(array[0])) {
responseAssertionResult.setName(array[1]);
responseAssertionResult.setContent(array[2]);
if (array.length > 3) {
responseAssertionResult.setScript(array[3]);
if (array[2].indexOf("&&") != -1) {
String[] content = array[2].split("&&");
responseAssertionResult.setContent(content[0]);
if (content.length > 1) {
responseAssertionResult.setScript(content[1]);
}
} else {
responseAssertionResult.setContent(array[2]);
}
}
} else {
String[] array = assertionResult.getName().split("==");
responseAssertionResult.setName(array[0]);
StringBuffer content = new StringBuffer();
for (int i = 1; i < array.length; i++) {

View File

@ -72,6 +72,7 @@ public class TestResultService {
reportTask.setTriggerMode(TriggerMode.API.name());
reportTask.setName(apiTestCaseWithBLOBs.getName());
reportTask.setExecutor(userName);
reportTask.setUserId(apiTestCaseWithBLOBs.getCreateUserId());
reportTask.setExecutionTime(DateUtils.getTimeString(apiTestCaseWithBLOBs.getCreateTime()));
reportTask.setEnvironment(name);
//测试计划用例定时jenkins
@ -105,18 +106,17 @@ public class TestResultService {
}
//报告内容
reportTask = new ApiTestReportVariable();
if (StringUtils.equalsAny(runMode, ApiRunMode.SCHEDULE_SCENARIO.name())) {
reportTask.setStatus(scenarioReport.getStatus());
reportTask.setId(scenarioReport.getId());
reportTask.setTriggerMode(scenarioReport.getTriggerMode());
reportTask.setName(scenarioReport.getName());
reportTask.setExecutor(userName);
reportTask.setUserId(scenarioReport.getUserId());
reportTask.setPrincipal(principal);
reportTask.setExecutionTime(DateUtils.getTimeString(scenarioReport.getUpdateTime()));
reportTask.setEnvironment(environment);
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
assert systemParameterService != null;
}
testResult.setTestId(scenarioReport.getScenarioId());
planScenarioId = scenarioReport.getTestPlanScenarioId();
}

View File

@ -30,5 +30,7 @@ public class CustomField implements Serializable {
private String options;
private String defaultValue;
private static final long serialVersionUID = 1L;
}

View File

@ -726,7 +726,7 @@
order by `order` desc limit 1;
</select>
<select id="getApiCaseEnvironment" resultType="java.lang.String">
select request -> '$.useEnvironment' from api_test_case where id = #{caseId}
select request ->> '$.useEnvironment' from api_test_case where id = #{caseId}
</select>
<update id="deleteToGc" parameterType="io.metersphere.api.dto.definition.ApiTestCaseRequest">
update api_test_case

View File

@ -35,4 +35,6 @@ public interface ExtProjectMapper {
long getProjectMemberSize(@Param("projectId") String projectId);
List<Project>getProjectByUserId(@Param("userId")String userId);
int getProjectPlanBugSize(@Param("projectId") String projectId);
}

View File

@ -244,4 +244,11 @@
<select id="getProjectByUserId" resultType="io.metersphere.base.domain.Project">
SELECT * from project where project.id in (SELECT user_group.source_id from user_group where user_group.user_id = #{userId})
</select>
<select id="getProjectPlanBugSize" resultType="java.lang.Integer">
select count(distinct(tci.issues_id)) from test_plan_test_case tptc
join test_case_issues tci on tptc.case_id = tci.test_case_id
join issues on tci.issues_id = issues.id
join test_plan on tptc.plan_id = test_plan.id
where test_plan.project_id = #{projectId} and (issues.status != 'closed' or issues.status is null);
</select>
</mapper>

View File

@ -214,21 +214,14 @@
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
<select id="listByMethod" resultType="io.metersphere.track.dto.TestCaseDTO">
SELECT id,name,project_id,"api" as type from api_test
<where>
<if test="request.projectId!=null">
and project_id=#{request.projectId}
</if>
</where>
UNION ALL
select id,name,project_id,"perform" as type from load_test
select id,name,project_id,'性能测试' as type from load_test
<where>
<if test="request.projectId!=null">
and project_id= #{request.projectId}
</if>
</where>
UNION ALL
select id,name,project_id,"scenario" as type from api_scenario
select id,name,project_id,'接口场景' as type from api_scenario
<where>
<if test="request.projectId!=null">
@ -237,7 +230,7 @@
</where>
and api_scenario.status!='Trash'
UNION ALL
select b.id,b.name,b.project_id,"definition" as type from api_test_case b
select b.id,b.name,b.project_id,'接口用例' as type from api_test_case b
inner join
api_definition a
on
@ -448,7 +441,7 @@
</select>
<select id="getTestPlanBug" resultType="int">
select count(tci.issues_id) from test_plan_test_case tptc join test_case_issues tci on tptc.case_id = tci.test_case_id join issues on tci.issues_id = issues.id
where tptc.plan_id = #{planId} and issues.status != 'closed';
where tptc.plan_id = #{planId} and (issues.status != 'closed' or issues.status is null);
</select>
<select id="getTestPlanCase" resultType="int">
select count(s)

View File

@ -115,7 +115,28 @@
parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
select DISTINCT test_plan.*, project.name as projectName,schedule.id as scheduleId,
(select name from user where user.id = test_plan.creator) as createUser,
IF(schedule.enable = true,true,false) as scheduleOpen
IF(schedule.enable = true,true,false) as scheduleOpen,
(select COUNT(*) from test_plan_test_case t
inner join test_case on t.case_id = test_case.id
left join test_case_node on test_case_node.id = test_case.node_id
inner join project on project.id = test_case.project_id
where test_case.status != 'Trash' and t.plan_id = test_plan.id) as testPlanTestCaseCount,
(select COUNT(*) from test_plan_api_case t
inner join api_test_case c on t.api_case_id = c.id
inner join api_definition a on c.api_definition_id = a.id
where t.test_plan_id = test_plan.id) as testPlanApiCaseCount,
(select COUNT(*) from test_plan_api_scenario t
inner join api_scenario c on t.api_scenario_id = c.id and c.status != 'Trash'
where t.test_plan_id = test_plan.id) as testPlanApiScenarioCount,
(select COUNT(*) from test_plan_load_case t
inner join load_test lt on t.load_case_id = lt.id
left join user u on lt.user_id = u.id
left join project p on lt.project_id = p.id
where t.test_plan_id = test_plan.id) as testPlanLoadCaseCount
from test_plan
LEFT JOIN schedule ON schedule.resource_id = test_plan.id
JOIN project on project.id = test_plan.project_id

View File

@ -24,7 +24,7 @@ public class IssueTemplateController {
private IssueTemplateService issueTemplateService;
@PostMapping("/add")
@MsAuditLog(module = "workspace_template_settings_issue", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#request.id)", msClass = IssueTemplateService.class)
@MsAuditLog(module = "workspace_template_settings_issue", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#request)", msClass = IssueTemplateService.class)
public void add(@RequestBody UpdateIssueTemplateRequest request) {
issueTemplateService.add(request);
}
@ -42,7 +42,7 @@ public class IssueTemplateController {
}
@PostMapping("/update")
@MsAuditLog(module = "workspace_template_settings_issue", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", content = "#msClass.getLogDetails(#request.id)", msClass = IssueTemplateService.class)
@MsAuditLog(module = "workspace_template_settings_issue", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id,#request.customFields)", content = "#msClass.getLogDetails(#request)", msClass = IssueTemplateService.class)
public void update(@RequestBody UpdateIssueTemplateRequest request) {
issueTemplateService.update(request);
}

View File

@ -101,6 +101,11 @@ public class SystemReference {
issueFieldColumns.put("title", "标题");
issueFieldColumns.put("content", "缺陷内容");
issueFieldColumns.put("description", "描述");
issueFieldColumns.put("scene", "使用场景");
issueFieldColumns.put("type", "属性类型");
issueFieldColumns.put("system", "系统字段");
issueFieldColumns.put("remark", "字段备注");
issueFieldColumns.put("defaultValue", "字段值");
projectColumns.put("name", "名称");
projectColumns.put("description", "描述");

View File

@ -1,5 +1,6 @@
package io.metersphere.notice.sender.impl;
import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.Notification;
import io.metersphere.commons.constants.NotificationConstants;
import io.metersphere.commons.utils.LogUtil;
@ -38,7 +39,7 @@ public class InSiteNoticeSender extends AbstractNoticeSender {
Map<String, Object> paramMap = noticeModel.getParamMap();
Notification notification = new Notification();
notification.setTitle(noticeModel.getSubject());
notification.setContent(context);
notification.setContent(JSON.toJSONString(paramMap));
notification.setOperator(noticeModel.getOperator());
notification.setOperation(noticeModel.getEvent());
notification.setResourceId((String) paramMap.get("id"));

View File

@ -76,7 +76,7 @@ public class PerformanceNoticeEvent implements LoadTestFinishEvent {
NoticeModel noticeModel = NoticeModel.builder()
.operator(loadTestReport.getUserId())
.successContext(successContext)
.successMailTemplate("PerformanceApiSuccessNotification")
.successMailTemplate("PerformanceSuccessNotification")
.failedContext(failedContext)
.failedMailTemplate("PerformanceFailedNotification")
.testId(loadTestReport.getTestId())

View File

@ -2,6 +2,8 @@ package io.metersphere.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.CustomFieldMapper;
import io.metersphere.base.mapper.CustomFieldTemplateMapper;
import io.metersphere.base.mapper.IssueTemplateMapper;
import io.metersphere.base.mapper.ext.ExtIssueTemplateMapper;
import io.metersphere.commons.constants.TemplateConstants;
@ -25,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@ -47,6 +50,12 @@ public class IssueTemplateService extends TemplateBaseService {
@Resource
ProjectService projectService;
@Resource
CustomFieldMapper customFieldMapper;
@Resource
CustomFieldTemplateMapper customFieldTemplateMapper;
public String add(UpdateIssueTemplateRequest request) {
checkExist(request);
IssueTemplate template = new IssueTemplate();
@ -222,13 +231,57 @@ public class IssueTemplateService extends TemplateBaseService {
return issueTemplateDao;
}
public String getLogDetails(String id) {
public String getLogDetails(String id, List<CustomFieldTemplate>newCustomFieldTemplates) {
List<DetailColumn> columns = new LinkedList<>();
IssueTemplate templateWithBLOBs = issueTemplateMapper.selectByPrimaryKey(id);
if (templateWithBLOBs != null) {
List<DetailColumn> columns = ReflexObjectUtil.getColumns(templateWithBLOBs, SystemReference.issueFieldColumns);
if(templateWithBLOBs==null){
return null;
}
CustomFieldTemplateExample example = new CustomFieldTemplateExample();
example.createCriteria().andTemplateIdEqualTo(templateWithBLOBs.getId());
example.createCriteria().andSceneEqualTo("ISSUE");
List<CustomFieldTemplate> customFieldTemplates = customFieldTemplateMapper.selectByExample(example);
if(newCustomFieldTemplates.size()>customFieldTemplates.size()){
for (int i = 0; i < newCustomFieldTemplates.size()-customFieldTemplates.size(); i++) {
CustomFieldTemplate customFieldTemplate = new CustomFieldTemplate();
customFieldTemplates.add(customFieldTemplate);
}
}
return getCustomFieldColums(columns, templateWithBLOBs, customFieldTemplates);
}
public String getLogDetails(UpdateIssueTemplateRequest request) {
List<DetailColumn> columns = new LinkedList<>();
IssueTemplate templateWithBLOBs = issueTemplateMapper.selectByPrimaryKey(request.getId());
if(templateWithBLOBs==null){
return null;
}
List<CustomFieldTemplate> newCustomFieldTemplates = request.getCustomFields();
CustomFieldTemplateExample example = new CustomFieldTemplateExample();
example.createCriteria().andTemplateIdEqualTo(templateWithBLOBs.getId());
example.createCriteria().andSceneEqualTo("ISSUE");
List<CustomFieldTemplate> customFieldTemplates = customFieldTemplateMapper.selectByExample(example);
if(newCustomFieldTemplates.size()<customFieldTemplates.size()){
for (int i = 0; i < customFieldTemplates.size()-newCustomFieldTemplates.size(); i++) {
CustomFieldTemplate customFieldTemplate = new CustomFieldTemplate();
newCustomFieldTemplates.add(customFieldTemplate);
}
}
return getCustomFieldColums(columns, templateWithBLOBs, newCustomFieldTemplates);
}
private String getCustomFieldColums(List<DetailColumn> columns, IssueTemplate templateWithBLOBs, List<CustomFieldTemplate> customFields) {
for (CustomFieldTemplate customFieldTemplate : customFields) {
CustomField customField = customFieldMapper.selectByPrimaryKey(customFieldTemplate.getFieldId());
customField.setDefaultValue(customFieldTemplate.getDefaultValue());
List<DetailColumn> columnsField = ReflexObjectUtil.getColumns(customField, SystemReference.issueFieldColumns);
columns.addAll(columnsField);
}
List<DetailColumn> columnIssues = ReflexObjectUtil.getColumns(templateWithBLOBs, SystemReference.issueFieldColumns);
columns.addAll(columnIssues);
OperatingLogDetails details = new OperatingLogDetails(JSON.toJSONString(templateWithBLOBs.getId()), null, templateWithBLOBs.getName(), templateWithBLOBs.getCreateUser(), columns);
return JSON.toJSONString(details);
}
return null;
}
}

View File

@ -745,4 +745,8 @@ public class ProjectService {
public long getProjectMemberSize(String id) {
return extProjectMapper.getProjectMemberSize(id);
}
public int getProjectBugSize(String projectId) {
return extProjectMapper.getProjectPlanBugSize(projectId);
}
}

View File

@ -12,4 +12,8 @@ public class TestPlanDTOWithMetric extends TestPlanDTO {
private Integer tested;
private Integer total;
private String createUser;
private Integer testPlanTestCaseCount;
private Integer testPlanApiCaseCount;
private Integer testPlanApiScenarioCount;
private Integer testPlanLoadCaseCount;
}

View File

@ -252,7 +252,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
protected String msImg2HtmlImg(String input, String endpoint) {
// ![中心主题.png](/resource/md/get/a0b19136_中心主题.png) -> <img src="xxx/resource/md/get/a0b19136_中心主题.png"/>
String regex = "(\\!\\[.*?\\]\\((.*)\\))";
String regex = "(\\!\\[.*?\\]\\((.*?)\\))";
Pattern pattern = Pattern.compile(regex);
if (StringUtils.isBlank(input)) {
return "";
@ -272,7 +272,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
}
protected String removeImage(String input) {
String regex = "(\\!\\[.*?\\]\\((.*)\\))";
String regex = "(\\!\\[.*?\\]\\((.*?)\\))";
if (StringUtils.isBlank(input)) {
return "";
}
@ -286,7 +286,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
protected String getImages(String input) {
String result = "";
String regex = "(\\!\\[.*?\\]\\((.*)\\))";
String regex = "(\\!\\[.*?\\]\\((.*?)\\))";
if (StringUtils.isBlank(input)) {
return result;
}
@ -299,7 +299,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
protected String htmlImg2MsImg(String input) {
// <img src="xxx/resource/md/get/a0b19136_中心主题.png"/> -> ![中心主题.png](/resource/md/get/a0b19136_中心主题.png)
String regex = "(<img\\s*src=\\\"(.*)\\\".*?>)";
String regex = "(<img\\s*src=\\\"(.*?)\\\".*?>)";
Pattern pattern = Pattern.compile(regex);
if (StringUtils.isBlank(input)) {
return "";
@ -321,7 +321,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
public List<File> getImageFiles(String input) {
List<File> files = new ArrayList<>();
String regex = "(\\!\\[.*?\\]\\((.*)\\))";
String regex = "(\\!\\[.*?\\]\\((.*?)\\))";
Pattern pattern = Pattern.compile(regex);
if (StringUtils.isBlank(input)) {
return new ArrayList<>();

View File

@ -391,7 +391,13 @@ public class TestPlanApiCaseService {
if (caseWithBLOBs != null) {
apiResult.setName(caseWithBLOBs.getName());
}
if(StringUtils.equalsIgnoreCase(request.getTriggerMode(),ApiRunMode.SCHEDULE_API_PLAN.name())) {
apiResult.setTriggerMode(TriggerMode.SCHEDULE.name());
}else if(StringUtils.equalsIgnoreCase(request.getTriggerMode(),ApiRunMode.JENKINS_API_PLAN.name())){
apiResult.setTriggerMode(TriggerMode.MANUAL.name());
}else {
apiResult.setTriggerMode(TriggerMode.BATCH.name());
}
apiResult.setActuator("LOCAL");
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
apiResult.setActuator(request.getConfig().getResourcePoolId());

View File

@ -9,6 +9,7 @@ import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.MathUtils;
import io.metersphere.performance.base.ChartsData;
import io.metersphere.service.ProjectService;
import io.metersphere.track.dto.TestPlanDTOWithMetric;
import io.metersphere.track.response.BugStatustics;
import io.metersphere.track.response.TestPlanBugCount;
@ -40,6 +41,8 @@ public class TrackService {
private TestPlanScenarioCaseService testPlanScenarioCaseService;
@Resource
private TestPlanLoadCaseService testPlanLoadCaseService;
@Resource
private ProjectService projectService;
public List<TrackCountResult> countPriority(String projectId) {
return extTestCaseMapper.countPriority(projectId);
@ -115,7 +118,6 @@ public class TrackService {
List<TestPlanBugCount> list = new ArrayList<>();
BugStatustics bugStatustics = new BugStatustics();
int index = 1;
int totalBugSize = 0;
int totalCaseSize = 0;
for (TestPlan plan : plans) {
int planBugSize = getPlanBugSize(plan.getId());
@ -137,12 +139,11 @@ public class TrackService {
double planPassRage = getPlanPassRage(plan.getId());
testPlanBug.setPassRage(planPassRage + "%");
list.add(testPlanBug);
totalBugSize += planBugSize;
totalCaseSize += planCaseSize;
}
int totalBugSize = projectService.getProjectBugSize(projectId);
bugStatustics.setList(list);
float rage =totalCaseSize == 0 ? 0 : (float) totalBugSize * 100 / totalCaseSize;
DecimalFormat df = new DecimalFormat("0.0");

View File

@ -33,37 +33,9 @@ alter table api_scenario
alter table api_scenario
add environment_group_id varchar(50) null;
DELIMITER $$
DROP PROCEDURE IF EXISTS proc_loop_test$$
CREATE PROCEDURE proc_loop_test()
BEGIN
DECLARE int_val INT DEFAULT 0;
DECLARE size INT DEFAULT 10;
DECLARE count_scenario INT DEFAULT 0;
SELECT COUNT(1) INTO count_scenario FROM api_scenario;
test_loop :
LOOP
IF (int_val > count_scenario / size)
THEN
UPDATE api_scenario
SET environment_json = api_scenario.scenario_definition -> '$.environmentMap'
WHERE api_scenario.id IN (SELECT id FROM (SELECT id FROM api_scenario LIMIT int_val, size) l);
#
LEAVE test_loop;
END IF;
UPDATE api_scenario
SET environment_json = api_scenario.scenario_definition -> '$.environmentMap'
WHERE api_scenario.id IN (SELECT id FROM (SELECT id FROM api_scenario LIMIT int_val, size) l);
SET int_val = int_val + size;
END LOOP;
END$$
DELIMITER ;
CALL proc_loop_test();
DROP PROCEDURE proc_loop_test;
update api_scenario
set environment_json = api_scenario.scenario_definition -> '$.environmentMap'
where api_scenario.environment_json is null;
update api_scenario set environment_type = 'JSON';

View File

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body style="text-align: left">
<div style="text-align: left">
<p>尊敬的用户:</p>
<p style="margin-left: 60px">您好:
</div>
<div style="margin-left: 100px">
<p>您所执行的 ${name} 性能测试已完成<br/>
请点击下面链接进入测试报告页面</p>
<a href="${url}/#/${type}/report/view/${id}">${url}/#/${type}/report/view/${id}</a>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body style="text-align: left">
<div style="margin-left: 100px">
${operator}执行性能测试成功: ${name}, 报告: ${reportUrl}
</div>
</body>
</html>

View File

@ -427,7 +427,7 @@ export default {
}
},
editScenario(row) {
const index = this.tabs.find(p => p.currentScenario.id === row.id);
const index = this.tabs.find(p => p.currentScenario.id === row.id && p.currentScenario.copy === row.copy);
if (!index) {
this.addTab({name: 'edit', currentScenario: row});
} else {
@ -486,6 +486,7 @@ export default {
/deep/ .el-tabs__header {
margin: 0 0 0px;
}
/deep/ .el-table__empty-block {
width: 100%;
min-width: 100%;

View File

@ -99,7 +99,7 @@ export function saveScenario(url, scenario, scenarioDefinition, _this, success)
success(response);
}
}, error => {
_this.$emit('errorRefresh', {});
_this.$emit('errorRefresh', error);
});
}

View File

@ -52,7 +52,6 @@
:fields-width="fieldsWidth"
min-width="120px">
<template slot-scope="scope">
<!--<span style="cursor:pointer" v-if="isReadOnly"> {{ scope.row.num }} </span>-->
<el-tooltip content="编辑">
<a style="cursor:pointer" @click="edit(scope.row)"> {{ scope.row.num }} </a>
</el-tooltip>
@ -66,7 +65,6 @@
:fields-width="fieldsWidth"
min-width="120px">
<template slot-scope="scope">
<!--<span style="cursor:pointer" v-if="isReadOnly"> {{ scope.row.customNum }} </span>-->
<el-tooltip content="编辑">
<a style="cursor:pointer" @click="edit(scope.row)"> {{ scope.row.customNum }} </a>
</el-tooltip>
@ -537,14 +535,6 @@ export default {
};
},
created() {
// if (!hasLicense()) {
// for (let i = 0; i < this.unTrashButtons.length; i++) {
// if (this.unTrashButtons[i].handleClick === this.generateGraph) {
// this.unTrashButtons.splice(i,1);
// break;
// }
// }
// }
scenario.$on('hide', id => {
this.hideStopBtn(id);
});

View File

@ -205,12 +205,14 @@
:project-list="projectList"
:env-map="projectEnvMap"
:env-group-id="envGroupId"
:environment-type="environmentType"
@remove="remove"
@copyRow="copyRow"
@suggestClick="suggestClick"
@refReload="refReload"
@runScenario="runDebug"
@stopScenario="stop"
@setDomain="setDomain"
@openScenario="openScenario"/>
</span>
</el-tree>
@ -528,7 +530,7 @@ export default {
currentUser: () => {
return getCurrentUser();
},
setDomain(flag) {
setDomain() {
if (this.projectEnvMap && this.projectEnvMap.size > 0) {
let scenario = {
id: this.currentScenario.id,
@ -1501,7 +1503,7 @@ export default {
this.initMessageSocket();
}
},
errorRefresh() {
errorRefresh(error) {
this.debug = false;
this.isTop = false;
this.debugLoading = false;

View File

@ -9,7 +9,7 @@
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-model="request.url"
style="width: 50%" size="small" @blur="urlChange" :disabled="request.disabled">
</el-input>
<el-checkbox v-if="isCustomizeReq" class="is-ref-environment" v-model="request.isRefEnvironment">
<el-checkbox v-if="isCustomizeReq" class="is-ref-environment" v-model="request.isRefEnvironment" @change="setDomain" :disabled="request.disabled">
{{ $t('api_test.request.refer_to_environment') }}
</el-checkbox>
</div>
@ -123,6 +123,9 @@ export default {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
setDomain() {
this.$emit("setDomain");
}
}
}
</script>

View File

@ -52,7 +52,7 @@
<!--请求内容-->
<template v-slot:request>
<legend style="width: 100%">
<customize-req-info :is-customize-req="isCustomizeReq" :request="request"/>
<customize-req-info :is-customize-req="isCustomizeReq" :request="request" @setDomain="setDomain"/>
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-api-request-form
v-if="request.protocol==='HTTP' || request.type==='HTTPSamplerProxy'"
@ -217,6 +217,9 @@ export default {
this.request.projectId = getCurrentProjectID();
}
this.request.customizeReq = this.isCustomizeReq;
if(this.request.num){
this.isShowNum = true;
}
//
this.getApiInfo();
if (this.request.protocol === 'HTTP') {
@ -447,91 +450,30 @@ export default {
}
this.reload();
this.sort();
} else {
this.request.referenced = "Deleted";
}
})
}
if(this.request.id && this.request.referenced === 'Copy'){
let requestResult = this.request.requestResult;
let enable = this.request.enable;
else if(this.request.id && this.request.referenced === 'Copy'){
if(this.request.refType==='CASE'){
this.$get("/api/testcase/get/" + this.request.id, response => {
if (response.data) {
let hashTree = [];
if (this.request.hashTree) {
hashTree = JSON.parse(JSON.stringify(this.request.hashTree));
}
Object.assign(this.request, JSON.parse(response.data.request));
this.request.name = response.data.name;
this.request.referenced = "Copy";
this.request.enable = enable;
if (response.data.path && response.data.path != null) {
this.request.path = response.data.path;
this.request.url = response.data.url;
}
if (response.data.method && response.data.method != null) {
this.request.method = response.data.method;
}
if (requestResult && Object.prototype.toString.call(requestResult) !== '[object Array]') {
this.request.requestResult = [requestResult];
} else {
this.request.requestResult = requestResult;
}
if(response.data.num){
this.request.num = response.data.num;
this.isShowNum = true;
}
this.request.id = response.data.id;
this.request.root = true;
this.request.projectId = response.data.projectId;
let req = JSON.parse(response.data.request);
if (req && this.request) {
this.request.hashTree = hashTree;
this.mergeHashTree(req.hashTree);
}
this.reload();
this.sort();
}
})
}
if(this.request.refType==='API'){
else if(this.request.refType==='API'){
this.$get("/api/definition/get/" + this.request.id, response => {
if (response.data) {
let hashTree = [];
if (this.request.hashTree) {
hashTree = JSON.parse(JSON.stringify(this.request.hashTree));
}
Object.assign(this.request, JSON.parse(response.data.request));
this.request.name = response.data.name;
this.request.referenced = "Copy";
this.request.enable = enable;
if (response.data.path && response.data.path != null) {
this.request.path = response.data.path;
this.request.url = response.data.url;
}
if (response.data.method && response.data.method != null) {
this.request.method = response.data.method;
}
if (requestResult && Object.prototype.toString.call(requestResult) !== '[object Array]') {
this.request.requestResult = [requestResult];
} else {
this.request.requestResult = requestResult;
}
if(response.data.num){
this.request.num = response.data.num;
this.isShowNum = true;
}
this.request.id = response.data.id;
this.request.root = true;
this.request.projectId = response.data.projectId;
let req = JSON.parse(response.data.request);
if (req && this.request) {
this.request.hashTree = hashTree;
this.mergeHashTree(req.hashTree);
}
this.reload();
this.sort();
}
})
}
@ -675,6 +617,9 @@ export default {
this.loading = false;
this.$emit('refReload', this.request, this.node);
},
setDomain() {
this.$emit("setDomain");
},
reload() {
this.loading = true
this.$nextTick(() => {

View File

@ -36,7 +36,6 @@ export default {
this.getExecResult();
} else {
this.response = this.result;
// this.isActive = true;
}
if(this.apiActive){
this.isActive = false
@ -62,10 +61,14 @@ export default {
let url = "/api/definition/report/getReport/" + this.apiItem.id;
this.$get(url, response => {
if (response.data) {
try {
let data = JSON.parse(response.data.content);
this.response = data;
this.$set(this.apiItem, 'responseData', data);
this.isActive = true;
}catch (error){
this.isActive = true;
}
}
});
}

View File

@ -41,7 +41,7 @@
</template>
<template v-slot:scenarioEnable>
<el-tooltip content="启用场景环境:当前步骤使用场景原始环境配置运行" placement="top">
<el-checkbox v-model="scenario.environmentEnable" @change="checkEnv">启用场景环境</el-checkbox>
<el-checkbox v-model="scenario.environmentEnable" @change="checkEnv" :disabled="scenario.disabled">启用场景环境</el-checkbox>
</el-tooltip>
</template>
<template v-slot:button>
@ -66,8 +66,7 @@ import MsTcpBasisParameters from "../../../definition/components/request/tcp/Tcp
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiRequestForm from "../../../definition/components/request/http/ApiHttpRequestForm";
import ApiBaseComponent from "../common/ApiBaseComponent";
import {getCurrentProjectID, getUUID} from "@/common/js/utils";
import {getUrl} from "@/business/components/api/automation/scenario/component/urlhelper";
import {getCurrentProjectID, getUUID, strMapToObj} from "@/common/js/utils";
export default {
name: "ApiScenarioComponent",
@ -88,7 +87,10 @@ export default {
default: false,
},
currentEnvironmentId: String,
projectList: Array
projectList: Array,
environmentType: String,
environmentGroupId: String,
envMap: Map
},
watch: {
message() {
@ -99,6 +101,9 @@ export default {
},
},
created() {
if(this.scenario.num){
this.isShowNum = true;
}
if (!this.scenario.projectId) {
this.scenario.projectId = getCurrentProjectID();
}
@ -128,8 +133,16 @@ export default {
this.scenario.variables = obj.variables;
this.scenario.environmentMap = obj.environmentMap;
this.$emit('refReload');
} else {
this.scenario.referenced = "Deleted";
}
})
}
else if(this.scenario.id && this.scenario.referenced === 'Copy' && !this.scenario.loaded){
this.result = this.$get("/api/automation/getApiScenario/" + this.scenario.id, response => {
if (response.data) {
if(response.data.num){
this.scenario.num = response.data.num;
this.isShowNum = true;
}
}
})
}
@ -163,21 +176,23 @@ export default {
this.$emit('stopScenario');
this.reload();
},
checkEnv() {
checkEnv(val) {
this.$post("/api/automation/checkScenarioEnv", {scenarioDefinition: JSON.stringify(this.scenario), projectId: this.projectId}, res => {
if (this.scenario.environmentEnable && !res.data) {
this.scenario.environmentEnable = false;
this.$warning("当前场景没有环境,需要先设置自身环境");
return;
}
this.setDomain();
this.setDomain(val);
});
},
setDomain() {
if (this.scenario.environmentEnable) {
setDomain(val) {
let param = {
environmentEnable: true,
environmentEnable: val,
id: this.scenario.id,
environmentType: this.environmentType,
environmentGroupId: this.environmentGroupId,
environmentMap: strMapToObj(this.envMap),
definition: JSON.stringify(this.scenario)
}
this.$post("/api/automation/setDomain", param, res => {
@ -186,7 +201,6 @@ export default {
this.scenario.hashTree = data.hashTree;
}
})
}
},
getCode() {
if (this.node && this.node.data.code && this.node.data.debug) {

View File

@ -20,7 +20,7 @@
:title="title"
:color="titleColor"
:response="response"
:environmet-type="environmentType"
:environment-type="environmentType"
:environment-group-id="envGroupId"
:background-color="backgroundColor"
:project-list="projectList"
@ -34,7 +34,7 @@
@copyRow="copyRow"
@refReload="refReload"
@openScenario="openScenario"
@setDomain="setDomain"
/>
</keep-alive>
</div>
@ -231,6 +231,9 @@ export default {
},
stopScenario() {
this.$emit('stopScenario');
},
setDomain() {
this.$emit("setDomain");
}
}
}

View File

@ -555,28 +555,28 @@ export default {
}
},
closeConfirm(targetName) {
let tabs = this.apiTabs;
if(!tabs[1].api) {
this.handleTabRemove(targetName);
}
if (tabs[1].api && this.$store.state.apiMap.size > 0) {
if (this.$store.state.apiMap.get(tabs[1].api.id).get("responseChange") === true || this.$store.state.apiMap.get(tabs[1].api.id).get("requestChange") === true ||
this.$store.state.apiMap.get(tabs[1].api.id).get("fromChange") === true) {
this.$alert("接口[ " + tabs[1].api.name + " ]未保存,是否确认关闭?", '', {
let tab = this.apiTabs;
tab.forEach(t => {
if (t.name === targetName) {
if (t.api && this.$store.state.apiMap.size > 0 && this.$store.state.apiMap.has(t.api.id)) {
if (this.$store.state.apiMap.get(t.api.id).get("responseChange") === true || this.$store.state.apiMap.get(t.api.id).get("requestChange") === true ||
this.$store.state.apiMap.get(t.api.id).get("fromChange") === true) {
this.$alert("接口[ " + t.api.name + " ]未保存,是否确认关闭?", '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
callback: (action) => {
if (action === 'confirm') {
this.$store.state.apiMap.delete(tabs[1].api.id);
this.$store.state.apiMap.delete(t.api.id);
this.handleTabRemove(targetName);
}
}
});
}
} else{
} else {
this.handleTabRemove(targetName);
}
}
})
},
handleTabRemove(targetName) {
let tabs = this.apiTabs;

View File

@ -267,6 +267,8 @@ export default {
this.$emit('saveApi', data);
});
this.$store.state.apiMap.delete(this.currentApi.id);
this.responseCount = 0;
this.count = 0
},
handleSave() {
if (this.$refs.httpApi) {

View File

@ -72,7 +72,7 @@
<el-row>
<el-col :span="8">
<el-form-item :label="$t('commons.tag')" prop="tag">
<ms-input-tag :currentScenario="httpForm" ref="tag"/>
<ms-input-tag :currentScenario="httpForm" ref="tag" v-model="httpForm.tags"/>
</el-form-item>
</el-col>
<el-col :span="8">
@ -179,6 +179,7 @@
label: 'name',
},
mockBaseUrl: "",
count: 0
}
},
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array, projectId: String},
@ -232,6 +233,14 @@
}
}
},
'httpForm.tags': {
handler(v, v1) {
this.count++;
if (v && v1 && JSON.stringify(v) !== JSON.stringify(v1) && this.count > 1) {
this.apiMapStatus();
}
}
},
syncTabs() {
if (this.basisData && this.syncTabs && this.syncTabs.includes(this.basisData.id)) {
//
@ -337,6 +346,8 @@
if (valid) {
this.setParameter();
this.$emit('saveApi', this.httpForm);
this.count = 0;
this.$store.state.apiMap.delete(this.httpForm.id);
} else {
return false;
}

View File

@ -502,9 +502,13 @@ export default {
let url = "/api/definition/report/get/" + apiCase.lastResultId;
this.$get(url, response => {
if (response.data) {
try {
let data = JSON.parse(response.data.content);
this.response = data;
this.resVisible = true;
} catch (error) {
this.resVisible = true;
}
}
});
}
@ -653,9 +657,9 @@ export default {
} else if (this.selectDataRange != null) {
let selectParamArr = this.selectDataRange.split(":");
if (selectParamArr.length === 2) {
if(selectParamArr[0] === "single") {
if (selectParamArr[0] === "single") {
this.condition.id = selectParamArr[1];
}else {
} else {
this.condition.apiDefinitionId = selectParamArr[1];
}
}

View File

@ -13,25 +13,78 @@
</el-tag>
</template>
</el-table-column>
<el-table-column prop="script">
<template v-slot:default="{row}">
<div class="assertion-item btn circle" v-if="row.script">
<i class="el-icon-view el-button el-button--primary el-button--mini is-circle" circle
@click="showPage(row.script)"/>
</div>
</template>
</el-table-column>
<el-dialog :title="$t('api_test.request.assertions.script')" :visible.sync="visible" width="900px" append-to-body>
<el-row type="flex" justify="space-between" align="middle" class="quick-script-block">
<el-col :span="codeSpan" class="script-content">
<ms-code-edit v-if="isCodeEditAlive"
:read-only="disabled"
:data.sync="scriptContent" theme="eclipse" :modes="['java','python']"
ref="codeEdit"/>
</el-col>
</el-row>
</el-dialog>
</el-table>
</template>
<script>
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
export default {
name: "MsAssertionResults",
components: {MsCodeEdit},
props: {
assertions: Array
},
data() {
return {
visible: false,
disabled: false,
codeSpan: 20,
isCodeEditAlive: true,
scriptContent: '',
}
},
methods: {
getRowStyle() {
return {backgroundColor: "#F5F5F5"};
}
}
},
showPage(script) {
this.disabled = true;
this.visible = true;
this.scriptContent = script;
this.reload();
},
reload() {
this.isCodeEditAlive = false;
this.$nextTick(() => (this.isCodeEditAlive = true));
},
},
}
</script>
<style scoped>
.assertion-item.btn.circle {
text-align: right;
min-width: 80px;
}
.script-content {
height: calc(100vh - 570px);
min-height: 440px;
}
.quick-script-block {
margin-bottom: 10px;
}
</style>

View File

@ -39,6 +39,10 @@ export const Test_Plan_List = [
{id: 'executionTimes', label: i18n.t('commons.execution_times')},
{id: 'passRate', label: i18n.t('commons.pass_rate')},
{id: 'createUser', label: i18n.t('commons.create_user')},
{id: 'testPlanTestCaseCount', label: i18n.t('test_track.plan.test_plan_test_case_count')},
{id: 'testPlanApiCaseCount', label: i18n.t('test_track.plan.test_plan_api_case_count')},
{id: 'testPlanApiScenarioCount', label: i18n.t('test_track.plan.test_plan_api_scenario_count')},
{id: 'testPlanLoadCaseCount', label: i18n.t('test_track.plan.test_plan_load_case_count')}
]
//接口定义-api列表
export const Api_List = [

View File

@ -50,6 +50,15 @@ export function getResource(d) {
switch (d.resourceType) {
case "JENKINS_TASK" :
resourceType = "Jenkins";
if (d.operation === 'EXECUTE_SUCCESSFUL') {
resourceType = "Jenkins 成功";
}
if (d.operation === 'EXECUTE_FAILED') {
resourceType = "Jenkins 失败";
}
if (d.operation === 'EXECUTE_COMPLETED') {
resourceType = "Jenkins 完成";
}
break;
case "TEST_PLAN_TASK" :
resourceType = "测试计划";
@ -115,7 +124,40 @@ export function getUrl(d) {
let url = "/#";
switch (d.resourceType) {
case "JENKINS_TASK" :
// jenkins 跳转需要特殊处理
try {
let obj = JSON.parse(d.content);
// 接口自动化,性能测试
if (obj.reportUrl) {
let s = obj.reportUrl.indexOf('#');
url += obj.reportUrl.substring(s + 1);
}
// 接口用例
else if (obj.caseStatus) {
url += "/api/definition?caseId=" + d.resourceId;
}
// 测试计划
else if (obj.url) {
let s = obj.url.indexOf('#');
url += obj.url.substring(s + 1);
} else {
url += "/track/plan/all";
}
} catch (e) {
// jenkins 跳转需要特殊处理
if (d.content.indexOf("接口用例") > -1) {
url += "/api/definition?caseId=" + d.resourceId;
} else if (d.content.indexOf("性能测试") > -1) {
url += "/performance/test/edit/" + d.resourceId;
} else if (d.content.indexOf("接口测试") > -1) {
url += "/api/automation/report/view/" + d.resourceId;
} else if (d.content.indexOf("测试计划运行") > -1) {
url += "/track/plan/view/" + d.resourceId;
} else {
url += "/track/plan/all";
}
}
break;
case "TEST_PLAN_TASK" :
url += "/track/plan/view/" + d.resourceId;
@ -133,7 +175,7 @@ export function getUrl(d) {
url += "/api/automation?resourceId=" + d.resourceId;
break;
case "API_DEFINITION_TASK" :
if (d.operation.startsWith('CASE_') || d.operation.startsWith('EXECUTE_') ) {
if (d.operation.startsWith('CASE_') || d.operation.startsWith('EXECUTE_')) {
url += "/api/definition?caseId=" + d.resourceId;
} else {
url += "/api/definition?resourceId=" + d.resourceId;

View File

@ -157,11 +157,11 @@ export default {
'</head>\n' +
'<body>\n' +
'<div>\n' +
'${operator}所执行的 ${name} ${type}测试运行成功' +
'${operator}执行 Jenkins 成功: ${name}' +
'</div>\n' +
'</body>\n' +
'</html>',
robotTitle: "${operator}所执行的 ${name} ${type}测试运行成功",
robotTitle: "${operator}执行 Jenkins 成功: ${name}",
jenkinsTask: [{
taskType: "jenkinsTask",
event: "",

View File

@ -360,9 +360,13 @@ export default {
let url = "/api/definition/report/get/" + reportId;
this.$get(url, response => {
if (response.data) {
try {
let data = JSON.parse(response.data.content);
this.response = data;
this.visible = true;
} catch (error) {
this.visible = true;
}
}
});
}

View File

@ -295,7 +295,7 @@ export default {
handleTabClose() {
let message = "";
this.tabs.forEach(t => {
if (t && this.$store.state.testCaseMap.has(t.testCaseInfo.id) && this.$store.state.testCaseMap.get(t.testCaseInfo.id) > 2) {
if (t && this.$store.state.testCaseMap.has(t.testCaseInfo.id) && this.$store.state.testCaseMap.get(t.testCaseInfo.id) > 1) {
message += t.testCaseInfo.name + "";
}
})
@ -320,7 +320,7 @@ export default {
},
closeConfirm(targetName) {
let t = this.tabs.filter(tab => tab.name === targetName);
if (t && this.$store.state.testCaseMap.has(t[0].testCaseInfo.id) && this.$store.state.testCaseMap.get(t[0].testCaseInfo.id) > 2) {
if (t && this.$store.state.testCaseMap.has(t[0].testCaseInfo.id) && this.$store.state.testCaseMap.get(t[0].testCaseInfo.id) > 1) {
this.$alert("用例[ " + t[0].testCaseInfo.name + " ]未保存,是否确认关闭?", '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),

View File

@ -457,6 +457,7 @@ export default {
if (!this.form.remark) {
this.form.remark = "";
}
this.$store.state.testCaseMap.set(this.form.id, 0);
},
handleCommand(e) {
if (e === "ADD_AND_CREATE") {
@ -498,7 +499,10 @@ export default {
},
reload() {
this.isStepTableAlive = false;
this.$nextTick(() => (this.isStepTableAlive = true));
this.$nextTick(() => {
this.isStepTableAlive = true;
this.$store.state.testCaseMap.set(this.form.id, 0);
});
},
reloadForm() {
this.isFormAlive = false;
@ -606,7 +610,6 @@ export default {
this.showInputTag = true;
});
});
this.$store.state.testCaseMap.set(this.form.id, 0);
},
async setFormData(testCase) {
try {
@ -635,7 +638,6 @@ export default {
this.setDefaultValue();
//
this.reloadForm();
this.$store.state.testCaseMap.set(this.form.id, 0);
},
setTestCaseExtInfo(testCase) {
this.testCase = {};
@ -692,7 +694,6 @@ export default {
callback(this);
}
//
this.$refs.otherInfo.getFileMetaData(this.form.id);
});
}
},

View File

@ -128,6 +128,38 @@
:min-width="100"
:key="index">
</el-table-column>
<el-table-column
v-if="item.id == 'testPlanTestCaseCount'"
prop="testPlanTestCaseCount"
:label="$t('test_track.plan.test_plan_test_case_count')"
show-overflow-tooltip
:min-width="100"
:key="index">
</el-table-column>
<el-table-column
v-if="item.id == 'testPlanApiCaseCount'"
prop="testPlanApiCaseCount"
:label="$t('test_track.plan.test_plan_api_case_count')"
show-overflow-tooltip
:min-width="100"
:key="index">
</el-table-column>
<el-table-column
v-if="item.id == 'testPlanApiScenarioCount'"
prop="testPlanApiScenarioCount"
:label="$t('test_track.plan.test_plan_api_scenario_count')"
show-overflow-tooltip
:min-width="100"
:key="index">
</el-table-column>
<el-table-column
v-if="item.id == 'testPlanLoadCaseCount'"
prop="testPlanLoadCaseCount"
:label="$t('test_track.plan.test_plan_load_case_count')"
show-overflow-tooltip
:min-width="100"
:key="index">
</el-table-column>
<el-table-column
v-if="item.id == 'passRate'"
prop="passRate"

View File

@ -37,6 +37,7 @@
import MsApiScenarioList from "../../../../../api/automation/scenario/ApiScenarioList";
import MsApiScenarioModule from "../../../../../api/automation/scenario/ApiScenarioModule";
import RelevanceScenarioList from "./RelevanceScenarioList";
import {ENV_TYPE} from "@/common/js/constants";
export default {
name: "TestCaseScenarioRelevance",
@ -109,6 +110,17 @@
let map = this.$refs.apiScenarioList.map;
let envType = this.$refs.apiScenarioList.environmentType;
let envGroupId = this.$refs.apiScenarioList.envGroupId;
if (!map || map.size < 1) {
this.$warning("请选择用例!");
return false;
}
if (envType === ENV_TYPE.JSON && (!envMap || envMap.size < 1)) {
this.$warning("请选择环境!");
return false;
} else if (envType === ENV_TYPE.GROUP && !envGroupId) {
this.$warning("请选择环境!");
return false;
}
param.planId = this.planId;
param.mapping = strMapToObj(map);
param.envMap = strMapToObj(envMap);

View File

@ -119,6 +119,10 @@ export let CUSTOM_TABLE_HEADER = {
{id: 'executionTimes', key: 'c', label: 'commons.execution_times'},
{id: 'passRate', key: 'd', label: 'commons.pass_rate'},
{id: 'createUser', key: 'e', label: 'commons.create_user'},
{id: 'testPlanTestCaseCount', key: 'f', label: 'test_track.plan.test_plan_test_case_count'},
{id: 'testPlanApiCaseCount', key: 'g', label: 'test_track.plan.test_plan_api_case_count'},
{id: 'testPlanApiScenarioCount', key: 'h', label: 'test_track.plan.test_plan_api_scenario_count'},
{id: 'testPlanLoadCaseCount', key: 'i', label: 'test_track.plan.test_plan_load_case_count'}
],
//测试计划-功能用例
TEST_PLAN_FUNCTION_TEST_CASE: [

View File

@ -1769,6 +1769,10 @@ export default {
api_case: "Api case",
scenario_case: "Scenario case",
execute_result: "Execute Result",
test_plan_test_case_count: "Track case count",
test_plan_api_case_count: "Api case count",
test_plan_api_scenario_count: "Scenario case count",
test_plan_load_case_count: "Load case count",
load_case: {
case: "Load Case",
execution_status: "Execution status",

View File

@ -1780,6 +1780,10 @@ export default {
api_case: "接口测试用例",
scenario_case: "场景测试用例",
execute_result: "执行结果",
test_plan_test_case_count: "功能用例数",
test_plan_api_case_count: "接口用例数",
test_plan_api_scenario_count: "场景用例数",
test_plan_load_case_count: "性能用例数",
load_case: {
case: "性能用例",
execution_status: "执行状态",

View File

@ -1778,6 +1778,10 @@ export default {
api_case: "接口測試用例",
scenario_case: "場景測試用例",
execute_result: "執行結果",
test_plan_test_case_count: "功能用例數",
test_plan_api_case_count: "接口用例數",
test_plan_api_scenario_count: "場景用例數",
test_plan_load_case_count: "性能用例數",
load_case: {
case: "性能用例",
execution_status: "執行狀態",