执行高级设置 断言和数据提取

This commit is contained in:
2025-05-07 16:40:43 +08:00
parent d1b00e3ebf
commit fa30bb8bc5
14 changed files with 823 additions and 62 deletions

View File

@@ -2,13 +2,17 @@ package com.test.test.controller;
import java.util.List;
import com.test.common.utils.SeleniumUtils;
import com.test.test.domain.UiAutomation;
import com.test.test.domain.qo.UiAutomationDataQO;
import com.test.test.domain.qo.UiAutomationQO;
import com.test.test.service.IUiAutomationService;
import com.test.test.service.IUiSceneStepsService;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import com.test.common.annotation.Log;
import com.test.common.core.controller.BaseController;
@@ -32,6 +36,8 @@ public class UiAutomationController extends BaseController
private IUiAutomationService uiAutomationService;
@Autowired
private IUiSceneStepsService uiSceneStepsService;
@Value("${test.selenium.chrome-driver-path}")
private String chromeDriverPath;
/**
* 查询ui自动化列表
@@ -110,11 +116,17 @@ public class UiAutomationController extends BaseController
public AjaxResult executeStep(@RequestParam Long id)
{
try{
String triggerMode = "1"; //手动执行
log.info("执行完成!");
return success(uiSceneStepsService.executeStep(id));
return success(uiSceneStepsService.executeStep(id,triggerMode));
} catch (Exception e) {
log.error("执行完成!",e);
return error("执行完成!");
System.setProperty("webdriver.chrome.driver", chromeDriverPath);
WebDriver driver = new ChromeDriver();
SeleniumUtils seleniumUtils = new SeleniumUtils(driver);
//关闭浏览器
seleniumUtils.quit();
log.error("执行错误!",e);
return error("执行错误!"+e.getMessage());
}
}
}

View File

@@ -0,0 +1,21 @@
package com.test.test.domain.qo;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AssertionConfigQO {
/** 弹窗文本数组 */
private List<AssertionQO> popupTexts = new ArrayList<>();
/** 元素断言数组 */
private List<AssertionQO> elementAssertions = new ArrayList<>();
/** 下拉框数组 */
private List<AssertionQO> dropdownBoxes = new ArrayList<>();
/** 网页标题数组 */
private List<AssertionQO> webTitles = new ArrayList<>();
}

View File

@@ -18,10 +18,10 @@ public class AssertionQO {
private String operateObject;
/** 元素库名称 */
private Integer operateGroupId;
private Long operateGroupId;
/** 元素id */
private Integer operateElementId;
private Long operateElementId;
/** 元素定位类型 id css ……*/
private String operateLocType;

View File

@@ -0,0 +1,16 @@
package com.test.test.domain.qo;
import lombok.Data;
import java.util.List;
/**
* 数据提取配置(新版嵌套结构)
*/
@Data
public class DataExtractionConfigQO {
/** 窗口信息提取配置 */
private List<DataExtractionQO> windowExtractions;
/** 元素信息提取配置 */
private List<DataExtractionQO> elementExtractions;
}

View File

@@ -8,14 +8,14 @@ import lombok.Data;
@Data
public class DataExtractionQO {
/** 1提取元素信息 2提取窗口信息 */
/** 1提取窗口信息 2提取元素信息 */
private String informationType;
/** 1普通对象(store) 2元素文本(storeText) 3元素值(storeValue) 4元素属性(storeAttribute)
/** informationType为2时 1普通对象(store) 2元素文本(storeText) 3元素值(storeValue) 4元素属性(storeAttribute)
* 5CSS属性(storeCssAttribute) 6匹配 xpath 的元素数量(storeXpathCount) */
private String elementType;
/** 1窗口 Handle(storeWindowHandle) 2网页标题(storeTitle) */
/** informationType为1时 1窗口 Handle(storeWindowHandle) 2网页标题(storeTitle) */
private String windowType;
/**值 */
@@ -26,10 +26,10 @@ public class DataExtractionQO {
private String operateObject;
/** 元素库名称 */
private Integer operateGroupId;
private Long operateGroupId;
/** 元素id */
private Integer operateElementId;
private Long operateElementId;
/** 元素定位类型 id css ……*/
private String operateLocType;
@@ -37,7 +37,7 @@ public class DataExtractionQO {
/** 元素定位值 */
private String operateLocValue;
/**元素属性*/
/** 普通对象 元素属性 元素css属性*/
private String elementAttribute;
/**是否禁用 0否 1是 */

View File

@@ -56,16 +56,13 @@ public class UiHighSettingQO extends BaseEntity
/** 是否删除 */
private Integer delFlag;
/** 等待元素超时时间 */
private Integer waitElementTime;
/** 截图配置 */
private Integer screenshotConfiguration;
/**其他设置*/
OtherSettingsQO otherSettingsQO = new OtherSettingsQO();
/**数据提取*/
private List<DataExtractionQO> dataExtractionQOList = new ArrayList<>();
private DataExtractionConfigQO dataExtractionQOList = new DataExtractionConfigQO();
/**断言*/
private List<AssertionQO> assertionQOList = new ArrayList<>();
private AssertionConfigQO assertionQOList = new AssertionConfigQO();
}

View File

@@ -0,0 +1,25 @@
package com.test.test.domain.vo;
import lombok.Data;
/**
* 断言报告结果
*/
@Data
public class AssertionReportVO {
/**
* 断言名称
*/
private String name;
/**
* 错误信息
*/
private String errorInfo;
/**
* 是否成功 0否 1是
*/
private String isSuccess;
}

View File

@@ -1,13 +1,10 @@
package com.test.test.domain.vo;
import com.test.common.annotation.Excel;
import com.test.common.core.domain.BaseEntity;
import com.test.test.domain.qo.AssertionConfigQO;
import com.test.test.domain.qo.AssertionQO;
import com.test.test.domain.qo.DataExtractionQO;
import com.test.test.domain.qo.DataExtractionConfigQO;
import com.test.test.domain.qo.OtherSettingsQO;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.ArrayList;
import java.util.List;
@@ -48,10 +45,10 @@ public class UiHighSettingVO
private Integer isDisabled;
/**断言*/
private List<AssertionQO> assertionQOList = new ArrayList<>();
private AssertionConfigQO assertionQOList = new AssertionConfigQO();
/**数据提取*/
private List<DataExtractionQO> dataExtractionQOList = new ArrayList<>();
private DataExtractionConfigQO dataExtractionQOList =new DataExtractionConfigQO();
/**其他设置*/
private OtherSettingsQO otherSettingsQO;

View File

@@ -19,6 +19,6 @@ public interface IUiSceneStepsService
* @param automationId 场景id
* @return
*/
Map<String,Object> executeStep(Long automationId);
Map<String,Object> executeStep(Long automationId,String triggerMode);
}

View File

@@ -76,16 +76,44 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
new TypeReference<List<AssertionQO>>() {
}
);
uiHighSettingVO.setAssertionQOList(assertionList);
List<AssertionQO> popupTexts = new ArrayList<>();
List<AssertionQO> elementAssertions = new ArrayList<>();
List<AssertionQO> dropdownBoxes = new ArrayList<>();
List<AssertionQO> webTitles = new ArrayList<>();
for (AssertionQO extractionQO : assertionList) {
if ("1".equals(extractionQO.getAssertionType())) {
popupTexts.add(extractionQO);
} else if ("2".equals(extractionQO.getAssertionType())) {
elementAssertions.add(extractionQO);
}else if ("3".equals(extractionQO.getAssertionType())) {
dropdownBoxes.add(extractionQO);
}else if ("4".equals(extractionQO.getAssertionType())) {
webTitles.add(extractionQO);
}
}
uiHighSettingVO.getAssertionQOList().setPopupTexts(popupTexts);
uiHighSettingVO.getAssertionQOList().setElementAssertions(elementAssertions);
uiHighSettingVO.getAssertionQOList().setDropdownBoxes(dropdownBoxes);
uiHighSettingVO.getAssertionQOList().setWebTitles(webTitles);
// 转换extractionDataJson 数据提取
if (StringUtils.isNotBlank(uiHighSetting.getExtractionDataJson())) {
List<DataExtractionQO> extractionData = null;
extractionData = objectMapper.readValue(
uiHighSetting.getExtractionDataJson(),
new TypeReference<List<DataExtractionQO>>(){
new TypeReference<List<DataExtractionQO>>() {
}
);
uiHighSettingVO.setDataExtractionQOList(extractionData);
List<DataExtractionQO> windowExtractions = new ArrayList<>();
List<DataExtractionQO> elementExtractions = new ArrayList<>();
for (DataExtractionQO extractionQO : extractionData) {
if ("1".equals(extractionQO.getInformationType())) {
windowExtractions.add(extractionQO);
} else if ("2".equals(extractionQO.getInformationType())) {
elementExtractions.add(extractionQO);
}
}
uiHighSettingVO.getDataExtractionQOList().setWindowExtractions(windowExtractions);
uiHighSettingVO.getDataExtractionQOList().setElementExtractions(elementExtractions);
}
// 转换otherSetting 其他设置
if (StringUtils.isNotBlank(uiHighSetting.getOtherSetting())) {
@@ -122,7 +150,25 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
new TypeReference<List<AssertionQO>>() {
}
);
uiHighSettingVO.setAssertionQOList(assertionList);
List<AssertionQO> popupTexts = new ArrayList<>();
List<AssertionQO> elementAssertions = new ArrayList<>();
List<AssertionQO> dropdownBoxes = new ArrayList<>();
List<AssertionQO> webTitles = new ArrayList<>();
for (AssertionQO extractionQO : assertionList) {
if ("1".equals(extractionQO.getAssertionType())) {
popupTexts.add(extractionQO);
} else if ("2".equals(extractionQO.getAssertionType())) {
elementAssertions.add(extractionQO);
}else if ("3".equals(extractionQO.getAssertionType())) {
dropdownBoxes.add(extractionQO);
}else if ("4".equals(extractionQO.getAssertionType())) {
webTitles.add(extractionQO);
}
}
uiHighSettingVO.getAssertionQOList().setPopupTexts(popupTexts);
uiHighSettingVO.getAssertionQOList().setElementAssertions(elementAssertions);
uiHighSettingVO.getAssertionQOList().setDropdownBoxes(dropdownBoxes);
uiHighSettingVO.getAssertionQOList().setWebTitles(webTitles);
// 转换extractionDataJson 数据提取
if (StringUtils.isNotBlank(uiHighSetting.getExtractionDataJson())) {
List<DataExtractionQO> extractionData = null;
@@ -131,7 +177,17 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
new TypeReference<List<DataExtractionQO>>() {
}
);
uiHighSettingVO.setDataExtractionQOList(extractionData);
List<DataExtractionQO> windowExtractions = new ArrayList<>();
List<DataExtractionQO> elementExtractions = new ArrayList<>();
for (DataExtractionQO extractionQO : extractionData) {
if ("1".equals(extractionQO.getInformationType())) {
windowExtractions.add(extractionQO);
} else if ("2".equals(extractionQO.getInformationType())) {
elementExtractions.add(extractionQO);
}
}
uiHighSettingVO.getDataExtractionQOList().setWindowExtractions(windowExtractions);
uiHighSettingVO.getDataExtractionQOList().setElementExtractions(elementExtractions);
}
// 转换otherSetting 其他设置
if (StringUtils.isNotBlank(uiHighSetting.getOtherSetting())) {
@@ -187,7 +243,6 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
uiAutomation.setUpdateTime(DateUtils.getNowDate());
uiAutomation.setCreateBy(SecurityUtils.getUsername());
uiAutomation.setUpdateBy(SecurityUtils.getUsername());
// uiAutomation.setStatus("1"); //未开始
uiAutomation.setDutyBy(SecurityUtils.getUsername());
uiAutomation.setDelFlag(0);
uiAutomation.setCrontabStatus(0); //未开启
@@ -218,22 +273,27 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
uiHighSetting.setCreateBy(SecurityUtils.getUsername());
uiHighSetting.setCreateTime(DateUtils.getNowDate());
try {
List<DataExtractionQO> combinedList1 = new ArrayList<>();
combinedList1.addAll(uiHighSettingQO.getDataExtractionQOList().getWindowExtractions());
combinedList1.addAll(uiHighSettingQO.getDataExtractionQOList().getElementExtractions());
//数据提取
String jsonStr = objectMapper.writeValueAsString(uiHighSettingQO.getDataExtractionQOList());
String jsonStr = objectMapper.writeValueAsString(combinedList1);
if (jsonStr != null) {
uiHighSetting.setExtractionDataJson(jsonStr);
}
//断言
jsonStr = objectMapper.writeValueAsString(uiHighSettingQO.getAssertionQOList());
List<AssertionQO> combinedList2 = new ArrayList<>();
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getPopupTexts());
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getElementAssertions());
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getDropdownBoxes());
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getWebTitles());
jsonStr = objectMapper.writeValueAsString(combinedList2);
if (jsonStr != null) {
uiHighSetting.setAssertionJson(jsonStr);
}
//其他设置
if (uiHighSettingQO.getWaitElementTime() != null || uiHighSettingQO.getScreenshotConfiguration() != null) {
OtherSettingsQO settings = new OtherSettingsQO();
settings.setWaitElementTime(uiHighSettingQO.getWaitElementTime());
settings.setScreenshotConfiguration(uiHighSettingQO.getScreenshotConfiguration());
jsonStr = objectMapper.writeValueAsString(settings);
if (uiHighSettingQO.getOtherSettingsQO()!=null) {
jsonStr = objectMapper.writeValueAsString(uiHighSettingQO.getOtherSettingsQO());
uiHighSetting.setOtherSetting(jsonStr);
}
} catch (JsonProcessingException e) {
@@ -297,22 +357,27 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
uiHighSetting.setCreateBy(SecurityUtils.getUsername());
uiHighSetting.setCreateTime(DateUtils.getNowDate());
try {
List<DataExtractionQO> combinedList1 = new ArrayList<>();
combinedList1.addAll(uiHighSettingQO.getDataExtractionQOList().getWindowExtractions());
combinedList1.addAll(uiHighSettingQO.getDataExtractionQOList().getElementExtractions());
//数据提取
String jsonStr = objectMapper.writeValueAsString(uiHighSettingQO.getDataExtractionQOList());
String jsonStr = objectMapper.writeValueAsString(combinedList1);
if (jsonStr != null) {
uiHighSetting.setExtractionDataJson(jsonStr);
}
//断言
jsonStr = objectMapper.writeValueAsString(uiHighSettingQO.getAssertionQOList());
List<AssertionQO> combinedList2 = new ArrayList<>();
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getPopupTexts());
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getElementAssertions());
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getDropdownBoxes());
combinedList2.addAll(uiHighSettingQO.getAssertionQOList().getWebTitles());
jsonStr = objectMapper.writeValueAsString(combinedList2);
if (jsonStr != null) {
uiHighSetting.setAssertionJson(jsonStr);
}
//其他设置
if (uiHighSettingQO.getWaitElementTime() != null || uiHighSettingQO.getScreenshotConfiguration() != null) {
OtherSettingsQO settings = new OtherSettingsQO();
settings.setWaitElementTime(uiHighSettingQO.getWaitElementTime());
settings.setScreenshotConfiguration(uiHighSettingQO.getScreenshotConfiguration());
jsonStr = objectMapper.writeValueAsString(settings);
if (uiHighSettingQO.getOtherSettingsQO()!=null) {
jsonStr = objectMapper.writeValueAsString(uiHighSettingQO.getOtherSettingsQO());
uiHighSetting.setOtherSetting(jsonStr);
}
} catch (JsonProcessingException e) {

View File

@@ -95,7 +95,7 @@ public class UiReportServiceImpl implements IUiReportService
UiAutomation automation = uiAutomationMapper.selectUiAutomationById(automationId);
String name = automation.getName();
UiReport uiReport = new UiReport();
uiReport.setName(name + "-" + DateUtils.getTime());
uiReport.setName(name + "-" + DateUtils.formatDateTime(startTime));
uiReport.setReportType("场景");
uiReport.setCreateTime(startTime);
uiReport.setCreateBy(SecurityUtils.getUsername());

View File

@@ -1,15 +1,22 @@
package com.test.test.service.impl;
import java.util.*;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.test.common.config.TestConfig;
import com.test.common.utils.DateUtils;
import com.test.common.utils.SecurityUtils;
import com.test.common.utils.SeleniumUtils;
import com.test.common.utils.StringUtils;
import com.test.test.domain.*;
import com.test.test.domain.qo.OtherSettingsQO;
import com.test.test.domain.qo.*;
import com.test.test.domain.vo.AssertionReportVO;
import com.test.test.domain.vo.UiHighSettingVO;
import com.test.test.mapper.UiAutomationMapper;
import com.test.test.mapper.UiSceneStepsMapper;
@@ -18,10 +25,10 @@ import com.test.test.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.C;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.UnexpectedTagNameException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -56,10 +63,13 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
* @param automationId
* @return
*/
public Map<String, Object> executeStep(Long automationId) {
public Map<String, Object> executeStep(Long automationId,String triggerMode) {
Map<String, Object> result = new HashMap<>();
result.put("msg", "");
result.put("id", 0L);
AtomicInteger totalAssertions = new AtomicInteger(0);
AtomicInteger successAssertions = new AtomicInteger(0);
Gson gson = new Gson();
// 1. 验证并获取步骤
List<UiSceneSteps> steps = validateAndGetSteps(automationId);
@@ -73,7 +83,7 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
Date startTime = DateUtils.getNowDate();
// 2. 创建执行报告
Long reportId = uiReportService.insertUiReport(startTime, automationId, "1", steps.size());
Long reportId = uiReportService.insertUiReport(startTime, automationId, triggerMode, steps.size());
UiReport uiReport = new UiReport();
result.put("id", reportId);
uiReport.setId(reportId);
@@ -120,6 +130,24 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
} else if (report.getExecutionFlag().equals("0")) {
stepsNotNumber++;
}
//成功断言数
String assertionJson = report.getAssertionJson();
if (assertionJson != null && !assertionJson.trim().isEmpty()) {
try {
List<AssertionReportVO> assertions = gson.fromJson(
assertionJson,
new TypeToken<List<AssertionReportVO>>(){}.getType()
);
int stepAssertionCount = assertions.size();
int stepSuccessCount = (int) assertions.stream()
.filter(a -> "1".equals(a.getIsSuccess()))
.count();
totalAssertions.addAndGet(stepAssertionCount);
successAssertions.addAndGet(stepSuccessCount);
} catch (Exception e) {
log.error("步骤[{}]断言数据解析失败: {}", report.getId(), assertionJson, e);
}
}
}
if (allSuccess) {
scenesSucceedNumber = 1;
@@ -127,6 +155,10 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
scenesErrorNumber = 1;
}
}
uiReport.setSuccessAssertion("0/0");
String globalAssertionResult = successAssertions.get() + "/" + totalAssertions.get();
uiReport.setSuccessAssertion(globalAssertionResult);
uiReport.setScenesSucceedNumber(scenesSucceedNumber);
uiReport.setScenesErrorNumber(scenesErrorNumber);
uiReport.setScenesNotNumber(0);
@@ -136,6 +168,8 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
uiReport.setFaiiRate(
stepsErrorNumber == 0 ? "0%" :
String.format("%.2f%%", (double) stepsErrorNumber / steps.size() * 100)
);
uiReportService.updateUiReport(uiReport);
@@ -214,6 +248,8 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
List<UiHighSettingVO> uiHighSettingVOList = uiAutomationService.getUiHighSettingVOList(step.getId());
executeSingleStep(step, seleniumUtils, uiSceneStepsReports.get(0).getId(), uiHighSettingVOList);
}
//关闭浏览器
seleniumUtils.quit();
}
private void executeSingleStep(UiSceneSteps step, SeleniumUtils seleniumUtils,
@@ -263,6 +299,8 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
boolean shouldContinue = executeStepWithLog(step, seleniumUtils, sceneStepsReportId,
execution, uiHighSettingVOList);
if (!shouldContinue) {
//关闭浏览器
seleniumUtils.quit();
throw new IllegalArgumentException("步骤执行失败,根据设置终止场景执行");
}
}
@@ -285,20 +323,29 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
UiHighSettingVO errorSetting = extractErrorSetting(uiHighSettingVOList);
UiHighSettingVO otherSetting = extractOtherSetting(uiHighSettingVOList);
OtherSettingsQO otherSettingsQO = otherSetting.getOtherSettingsQO();
Integer screenshotConfiguration = otherSettingsQO.getScreenshotConfiguration(); //是否截图 1当前步骤截图 2异常截图 3 不截图
//等待元素超时时间
Integer waitElementTime = otherSettingsQO.getWaitElementTime() == null ? 0 : otherSettingsQO.getWaitElementTime();
if (waitElementTime > 0) {
// 转换为秒至少1秒
long timeoutInSeconds = Math.max(1, waitElementTime / 1000);
log.info("元素等待时间{}秒", timeoutInSeconds);
seleniumUtils.setWaitTimeout(timeoutInSeconds);
Integer screenshotConfiguration = 0;
if (otherSettingsQO != null) {
screenshotConfiguration = otherSettingsQO.getScreenshotConfiguration() == null ? 0 : otherSettingsQO.getScreenshotConfiguration();
//等待元素超时时间
Integer waitElementTime = otherSettingsQO.getWaitElementTime() == null ? -1 : otherSettingsQO.getWaitElementTime();
if (waitElementTime > 0) {
// 转换为秒至少1秒
long timeoutInSeconds = Math.max(1, waitElementTime / 1000);
log.info("元素等待时间{}秒", timeoutInSeconds);
seleniumUtils.setWaitTimeout(timeoutInSeconds);
}
}
//前置操作设置
List<UiHighSettingVO> beforeSettingList = extractbeforeSetting(uiHighSettingVOList);
// 获取前置操作数据集合(判空)
Map<String, Object> beforeData = CollectionUtils.isEmpty(beforeSettingList)
? new HashMap<>()
: filterBydataExtractionQOList(beforeSettingList, seleniumUtils);
//后置操作设置
List<UiHighSettingVO> afterSettingList = extractafterSetting(uiHighSettingVOList);
//前置等待时间
int beforeAwaitTime = getAwaitTime(beforeSettingList);
//后置等待时间
@@ -328,7 +375,6 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
log.info("执行后置等待: {}ms", afterAwaitTime);
Thread.sleep(afterAwaitTime);
}
report.setLogInfo("OK");
report.setExecutionFlag("1");
} catch (Exception e) {
@@ -345,18 +391,50 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
}
log.error("步骤执行失败: {}", e.getMessage());
} finally {
//获取后置操作数据集合
Map<String, Object> afterData = CollectionUtils.isEmpty(afterSettingList)
? new HashMap<>()
: filterBydataExtractionQOList(afterSettingList, seleniumUtils);
Map<String, Object> mergedData = new HashMap<>();
if (!beforeData.isEmpty()) {
mergedData.put("前置数据提取", beforeData);
}
if (!afterData.isEmpty()) {
mergedData.put("后置数据提取", afterData);
}
// 设置到报告
try {
String json = mergedData.isEmpty() ? null : new ObjectMapper().writeValueAsString(mergedData);
report.setExtractionDataJson(json);
} catch (JsonProcessingException e) {
report.setExtractionDataJson("JsonProcessingException error");
}
Map<String, Object> stringObjectMap = filterByAssertionQOList(afterSettingList, seleniumUtils);
//断言失败是否终止
String continueExecution1 = (String) stringObjectMap.get("continueExecution");
if (continueExecution1.equals("1")){
continueExecution = false;
report.setLogInfo("");
report.setExecutionFlag("2");
}
List<AssertionReportVO> assertionReportVOS = (List<AssertionReportVO>) stringObjectMap.get("assertionReportVOS");
Gson gson = new Gson();
report.setAssertionJson(assertionReportVOS.isEmpty() ? null : gson.toJson(assertionReportVOS));
endTime = DateUtils.getNowDate();
// 更新报告
report.setCreateTime(startTime);
report.setUpdateTime(endTime);
report.setTake(DateUtils.differenceInMilliseconds(startTime, endTime) + "ms");
uiSceneStepsReportMapper.updateUiSceneStepsReport(report);
}
return continueExecution;
}
/**
* 提取前置操作
*
@@ -369,6 +447,505 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
.collect(Collectors.toList()); // 返回默认设置
}
/**
* 断言
* @param settingList
* @param seleniumUtils
* @return
*/
public Map<String, Object> filterByAssertionQOList(List<UiHighSettingVO> settingList, SeleniumUtils seleniumUtils) {
Map<String, Object> result = new HashMap<>();
String continueExecution = "2";
List<AssertionReportVO> assertionReports = new ArrayList<>();
result.put("continueExecution", continueExecution);
result.put("assertionReportVOS", assertionReports);
List<UiHighSettingVO> uiHighSettingVOS = settingList.stream()
.filter(setting -> setting.getOperateType().equals("2") && 0 == setting.getIsDisabled())
.toList();
if (CollectionUtils.isEmpty(uiHighSettingVOS)) {
return result;
}
for (UiHighSettingVO uiHighSettingVO : uiHighSettingVOS) {
AssertionConfigQO assertion = uiHighSettingVO.getAssertionQOList();
List<AssertionQO> assertionQOList = new ArrayList<>();
assertionQOList.addAll(assertion.getPopupTexts());
assertionQOList.addAll(assertion.getElementAssertions());
assertionQOList.addAll(assertion.getDropdownBoxes());
assertionQOList.addAll(assertion.getWebTitles());
if (!CollectionUtils.isEmpty(assertionQOList)) {
for (AssertionQO assertionQO : assertionQOList) {
if ("1".equals(assertionQO.getIsDisabled())) {
continue;
}
AssertionReportVO report = new AssertionReportVO();
report.setName("1".equals(assertionQO.getIsFailedAbort())?"assert":"verify");
report.setIsSuccess("1"); // 默认成功
try {
boolean assertionResult = false;
String errorDetail = "";
switch (assertionQO.getAssertionType()) {
case "1": // 弹窗文本断言
assertionResult = handleAlertAssertion(assertionQO, seleniumUtils, report);
break;
case "2": // 元素断言
assertionResult = handleElementAssertion(assertionQO, seleniumUtils, report);
break;
case "3": // 下拉框断言
assertionResult = handleDropdownAssertion(assertionQO, seleniumUtils, report);
break;
case "4": // 网页标题断言
assertionResult = handleTitleAssertion(assertionQO, seleniumUtils, report);
break;
default:
errorDetail = "不支持的断言类型: " + assertionQO.getAssertionType();
report.setErrorInfo(errorDetail);
report.setIsSuccess("0");
}
if (!assertionResult && "1".equals(assertionQO.getIsFailedAbort())) {
continueExecution = "1";
result.put("continueExecution", continueExecution);
}
} catch (Exception e) {
report.setErrorInfo("断言执行异常: " + e.getMessage());
report.setIsSuccess("0");
log.error("断言执行异常", e);
}
assertionReports.add(report);
}
}
}
result.put("assertionReportVOS", assertionReports);
return result;
}
private boolean handleAlertAssertion(AssertionQO assertionQO,
SeleniumUtils seleniumUtils,
AssertionReportVO report) {
try {
// 1. 获取弹窗文本带10秒等待
String actualText = seleniumUtils.getAlertText();
String expectedText = assertionQO.getExpectations();
report.setErrorInfo("");
// 3. 文本比较
if (!actualText.equals(expectedText)) {
report.setErrorInfo(String.format(
"弹窗文本不匹配,实际值:'%s',期望值:'%s'",
actualText, expectedText
));
report.setIsSuccess("0");
return false;
}
// 4. 根据配置处理弹窗
if ("1".equals(assertionQO.getIsPopText())) {
seleniumUtils.acceptAlert(); // 点击确认
log.info("弹窗断言成功,已点击确认");
} else {
log.info("弹窗断言成功,未执行点击操作");
}
report.setIsSuccess("1");
return true;
} catch (NoAlertPresentException e) {
report.setErrorInfo("弹窗未出现:" + e.getMessage());
report.setIsSuccess("0");
return false;
} catch (Exception e) {
report.setErrorInfo("弹窗处理异常:" + e.getMessage());
report.setIsSuccess("0");
return false;
}
}
/**
* 处理元素断言
* @param assertionQO 断言配置
* @param seleniumUtils Selenium工具类
* @param report 断言报告
* @return 断言是否成功
*/
private boolean handleElementAssertion(AssertionQO assertionQO,
SeleniumUtils seleniumUtils,
AssertionReportVO report) {
WebElement element = null;
String locatorDescription = "";
report.setErrorInfo("");
try {
// 1. 获取元素定位信息
if ("1".equals(assertionQO.getOperateObject())) {
// 从数据库查询元素信息
//元素定位
UiElement uiElement = uiElementService.selectUiElementById(assertionQO.getOperateElementId());
if (uiElement == null) {
report.setErrorInfo("元素ID " + assertionQO.getOperateElementId() + " 不存在");
report.setIsSuccess("0");
return false;
}
element = seleniumUtils.findElement(uiElement.getLocType(), uiElement.getElementLoc());
locatorDescription = String.format("元素ID:%d (%s=%s)",
assertionQO.getOperateElementId(),
uiElement.getLocType(),
uiElement.getElementLoc());
} else if ("2".equals(assertionQO.getOperateObject())) {
// 直接使用配置的定位信息
element = seleniumUtils.findElement(
assertionQO.getOperateLocType(),
assertionQO.getOperateLocValue()
);
locatorDescription = String.format("直接定位 (%s=%s)",
assertionQO.getOperateLocType(),
assertionQO.getOperateLocValue());
}
// 3. 执行断言
boolean result = false;
String actualValue = "";
String expectedValue = assertionQO.getExpectations();
switch (assertionQO.getAssertionMode()) {
case "1": // 元素被选中(Checked)
actualValue = String.valueOf(element.isSelected());
result = element.isSelected();
if (!result) {
report.setErrorInfo(locatorDescription + " 未被选中");
}
break;
case "2": // 元素可编辑(Editable)
actualValue = String.valueOf(element.isEnabled());
result = element.isEnabled();
if (!result) {
report.setErrorInfo(locatorDescription + " 不可编辑");
}
break;
case "3": // 元素存在(ElementPresent)
result = true; // 如果能找到元素,说明存在
break;
case "4": // 元素不存在(ElementNotPresent)
report.setErrorInfo("元素存在性断言应使用其他方式实现");
return false;
case "5": // 元素未被选中(NotChecked)
actualValue = String.valueOf(element.isSelected());
result = !element.isSelected();
if (!result) {
report.setErrorInfo(locatorDescription + " 已被选中");
}
break;
case "6": // 元素不可编辑(NotEditable)
actualValue = String.valueOf(element.isEnabled());
result = !element.isEnabled();
if (!result) {
report.setErrorInfo(locatorDescription + " 可编辑");
}
break;
case "7": // 元素文本不等于期望(NotText)
actualValue = element.getText();
result = !actualValue.equals(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"%s 文本等于期望值(实际:'%s',期望不等于:'%s'",
locatorDescription, actualValue, expectedValue
));
}
break;
case "8": // 元素文本等于期望(Text)
actualValue = element.getText();
result = actualValue.equals(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"%s 文本不等于期望值(实际:'%s',期望:'%s'",
locatorDescription, actualValue, expectedValue
));
}
break;
case "9": // 元素值等于期望(Value)
actualValue = element.getAttribute("value");
result = actualValue.equals(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"%s 值不等于期望值(实际:'%s',期望:'%s'",
locatorDescription, actualValue, expectedValue
));
}
break;
case "10": // 元素文本包含期望(InText)
actualValue = element.getText();
result = actualValue.contains(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"%s 文本不包含期望内容(实际:'%s',期望包含:'%s'",
locatorDescription, actualValue, expectedValue
));
}
break;
case "11": // 元素文本不包含期望(NotlnText)
actualValue = element.getText();
result = !actualValue.contains(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"%s 文本包含不应出现的内容(实际:'%s',期望不包含:'%s'",
locatorDescription, actualValue, expectedValue
));
}
break;
default:
report.setErrorInfo("不支持的断言方式: " + assertionQO.getAssertionMode());
return false;
}
report.setIsSuccess(result ? "1" : "0");
return result;
} catch (NoSuchElementException e) {
if ("3".equals(assertionQO.getAssertionMode())) {
// 元素存在断言时找不到元素应该返回false
report.setErrorInfo(locatorDescription + " 不存在");
report.setIsSuccess("0");
return false;
}
report.setErrorInfo("元素定位失败: " + e.getMessage());
report.setIsSuccess("0");
return false;
} catch (Exception e) {
report.setErrorInfo("元素断言异常: " + e.getMessage());
report.setIsSuccess("0");
return false;
}
}
/**
* 处理下拉框断言
* @param assertionQO 断言配置
* @param seleniumUtils Selenium工具类
* @param report 断言报告
* @return 断言是否成功
*/
private boolean handleDropdownAssertion(AssertionQO assertionQO,
SeleniumUtils seleniumUtils,
AssertionReportVO report) {
WebElement dropdown = null;
String locatorDescription = "";
report.setErrorInfo("");
try {
// 1. 获取下拉框元素
if ("1".equals(assertionQO.getOperateObject())) {
UiElement uiElement = uiElementService.selectUiElementById(assertionQO.getOperateElementId());
if (uiElement == null) {
report.setErrorInfo("元素ID " + assertionQO.getOperateElementId() + " 不存在");
report.setIsSuccess("0");
return false;
}
dropdown = seleniumUtils.findElement(uiElement.getLocType(), uiElement.getElementLoc());
locatorDescription = String.format("下拉框ID:%d (%s=%s)",
assertionQO.getOperateElementId(),
uiElement.getLocType(),
uiElement.getElementLoc());
} else {
dropdown = seleniumUtils.findElement(
assertionQO.getOperateLocType(),
assertionQO.getOperateLocValue()
);
locatorDescription = String.format("下拉框 (%s=%s)",
assertionQO.getOperateLocType(),
assertionQO.getOperateLocValue());
}
// 2. 转换为Select对象
Select select = new Select(dropdown);
WebElement selectedOption = select.getFirstSelectedOption();
String actualValue = selectedOption.getAttribute("value");
String actualText = selectedOption.getText();
String expectedValue = assertionQO.getExpectations();
// 4. 执行断言
boolean result = false;
switch (assertionQO.getAssertionMode()) {
case "1": // 所选元素的值等于期望(SelectedValue)
result = actualValue.equals(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"下拉框选中值不匹配(实际:'%s',期望:'%s'",
actualValue, expectedValue
));
}
break;
case "2": // 下拉框选项显示的文本等于期望(SelectedLabel)
result = actualText.equals(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"下拉框选中文本不匹配(实际:'%s',期望:'%s'",
actualText, expectedValue
));
}
break;
case "3": // 所选元素的值不等于期望(NotSelectedValue)
result = !actualValue.equals(expectedValue);
if (!result) {
report.setErrorInfo(String.format(
"下拉框选中值不应匹配(实际:'%s',期望不等于:'%s'",
actualValue, expectedValue
));
}
break;
default:
report.setErrorInfo("不支持的断言方式: " + assertionQO.getAssertionMode());
return false;
}
report.setIsSuccess(result ? "1" : "0");
return result;
} catch (NoSuchElementException e) {
report.setErrorInfo("下拉框元素不存在: " + e.getMessage());
report.setIsSuccess("0");
return false;
} catch (UnexpectedTagNameException e) {
report.setErrorInfo("元素不是下拉框: " + e.getMessage());
report.setIsSuccess("0");
return false;
} catch (Exception e) {
report.setErrorInfo("下拉框断言异常: " + e.getMessage());
report.setIsSuccess("0");
return false;
}
}
/**
* 处理网页标题断言
* @param assertionQO 断言配置
* @param seleniumUtils Selenium工具类
* @param report 断言报告
* @return 断言是否成功
*/
private boolean handleTitleAssertion(AssertionQO assertionQO,
SeleniumUtils seleniumUtils,
AssertionReportVO report) {
try {
// 1. 获取实际标题和期望标题
String actualTitle = seleniumUtils.getTitle();
String expectedTitle = assertionQO.getExpectations();
report.setErrorInfo("");
// 3. 执行完全匹配比较
boolean result = actualTitle.equals(expectedTitle);
if (!result) {
report.setErrorInfo(String.format(
"网页标题不匹配(实际:'%s',期望:'%s'",
actualTitle, expectedTitle
));
}
report.setIsSuccess(result ? "1" : "0");
return result;
} catch (Exception e) {
report.setErrorInfo("获取网页标题失败: " + e.getMessage());
report.setIsSuccess("0");
return false;
}
}
/**
* 获取数据提取集合
* @param settingList
* @return
*/
public Map<String,Object> filterBydataExtractionQOList(List<UiHighSettingVO> settingList, SeleniumUtils seleniumUtils) {
List<UiHighSettingVO> uiHighSettingVOS = settingList.stream()
.filter(setting -> setting.getOperateType().equals("3") && setting.getIsDisabled() == 0)
.toList();
Map<String,Object> variableStorage = new HashMap<>();
if (CollectionUtils.isEmpty(uiHighSettingVOS)) {
return variableStorage;
}
for (UiHighSettingVO uiHighSettingVO : uiHighSettingVOS) {
DataExtractionConfigQO dataExtractionQO = uiHighSettingVO.getDataExtractionQOList();
List<DataExtractionQO> dataExtractionQOList = new ArrayList<>();
dataExtractionQOList.addAll(dataExtractionQO.getElementExtractions());
dataExtractionQOList.addAll(dataExtractionQO.getWindowExtractions());
if (!CollectionUtils.isEmpty(dataExtractionQOList)) {
for (DataExtractionQO extraction : dataExtractionQOList) {
if ("1".equals(extraction.getIsDisabled())) {
continue;
}
try {
String variableName = extraction.getValue();
String extractedValue = extractData(extraction,seleniumUtils);
variableStorage.put(variableName, extractedValue);
log.info("Extracted '{}' = {}", variableName, extractedValue);
} catch (NoSuchElementException e) {
log.info("Extracted '" + extraction.getValue() + "' = NoSuchElementException");
variableStorage.put(extraction.getValue(), "NoSuchElementException");
} catch (Exception e) {
log.error("Error extracting '" + extraction.getValue() + "': " + e.getMessage());
}
}
}
}
return variableStorage;
}
/**
* 获取数据提取集合具体实现
* @param extraction
* @param seleniumUtils
* @return
*/
private String extractData(DataExtractionQO extraction,SeleniumUtils seleniumUtils) {
if ("1".equals(extraction.getInformationType())) {
return seleniumUtils.extractWindowInformation(extraction.getWindowType());
} else if ("2".equals(extraction.getInformationType())) {
WebElement element = null;
String locType = "";
String elementLoc = "";
if ("1".equals(extraction.getOperateObject())) {
//元素定位
UiElement uiElement = uiElementService.selectUiElementById(extraction.getOperateElementId());
if (uiElement == null) {
return "";
}
locType = uiElement.getLocType(); //属性
elementLoc = uiElement.getElementLoc();//值
} else if ("2".equals(extraction.getOperateObject())) {
locType = extraction.getOperateLocType(); //属性
elementLoc = extraction.getOperateLocValue();//值
}
element = seleniumUtils.findElement(locType, elementLoc);
switch (extraction.getElementType()) {
case "1": // 普通对象
return extraction.getElementAttribute(); // 直接返回属性值
case "2": // 元素文本
return element.getText();
case "3": // 元素值
return element.getAttribute("value");
case "4": // 元素属性
return element.getAttribute(extraction.getElementAttribute());
case "5": // CSS属性
return element.getCssValue(extraction.getElementAttribute());
case "6": // 匹配 xpath 的元素数量(storeXpathCount)
return String.valueOf(seleniumUtils.findElements(locType,elementLoc).size());
default:
return "";
}
}
return "";
}
/**
* 获取(前置//后置)等待时间
*
@@ -916,4 +1493,7 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
}
}