UI执行接口

This commit is contained in:
2025-04-27 14:19:12 +08:00
parent 83109f3170
commit d71d5c070e
6 changed files with 1126 additions and 71 deletions

View File

@@ -1,5 +1,6 @@
package com.test.common.utils; package com.test.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.*; import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.ExpectedConditions;
@@ -13,6 +14,7 @@ import java.util.Set;
/** /**
* Selenium 工具类 * Selenium 工具类
*/ */
@Slf4j
public class SeleniumUtils { public class SeleniumUtils {
private WebDriver driver; private WebDriver driver;
@@ -238,9 +240,9 @@ public class SeleniumUtils {
} }
// 获取alert文本 // 获取alert文本
public String getAlertText() { // public String getAlertText() {
return switchToAlert().getText(); // return switchToAlert().getText();
} // }
// 在alert中输入文本 // 在alert中输入文本
public void sendKeysToAlert(String text) { public void sendKeysToAlert(String text) {
@@ -377,4 +379,480 @@ public class SeleniumUtils {
driver.quit(); driver.quit();
} }
} }
//Add SeleniumUtils -----
/**
* 根据句柄ID切换到指定窗口
* @param handleId 窗口句柄ID
*/
public void switchToWindowByHandle(String handleId) {
driver.switchTo().window(handleId);
log.info("已切换到句柄ID为 {} 的窗口", handleId);
}
/**
* 根据网页索引号切换到指定窗口
* @param index 窗口索引从0开始
*/
public void switchToWindowByIndex(int index) {
Set<String> handles = driver.getWindowHandles();
if (index >= 0 && index < handles.size()) {
String handle = handles.toArray(new String[0])[index];
driver.switchTo().window(handle);
log.info("已切换到索引为 {} 的窗口", index);
} else {
throw new NoSuchWindowException("无效的窗口索引: " + index);
}
}
/**
* 切换到初始窗口(第一个打开的窗口)
*/
public void switchToDefaultWindow() {
Set<String> handles = driver.getWindowHandles();
if (!handles.isEmpty()) {
String firstHandle = handles.iterator().next();
driver.switchTo().window(firstHandle);
log.info("已切换回初始窗口");
}
}
/**
* 根据索引切换到指定frame
* @param index frame索引(从0开始)
*/
public void switchToFrameByIndex(int index) {
try {
driver.switchTo().frame(index);
log.info("已切换到索引为 {} 的frame", index);
} catch (NoSuchFrameException e) {
log.error("按索引切换frame失败: {}", e.getMessage());
throw new RuntimeException("找不到索引为 " + index + " 的frame", e);
}
}
/**
* 根据定位方式切换到frame
* @param locatorType 定位类型(id/name/xpath/css等)
* @param locatorValue 定位值
*/
public void switchToFrameByLocator(String locatorType, String locatorValue) {
By locator = getLocator(locatorType, locatorValue);
try {
WebElement frameElement = wait.until(ExpectedConditions.presenceOfElementLocated(locator));
driver.switchTo().frame(frameElement);
log.info("已切换到 {} = '{}' 的frame", locatorType, locatorValue);
} catch (TimeoutException e) {
log.error("等待frame元素超时: {} = '{}'", locatorType, locatorValue);
throw new RuntimeException("找不到 " + locatorType + " = '" + locatorValue + "' 的frame元素", e);
}
}
/**
* 根据定位类型和值获取Selenium定位器
* @param locatorType 定位类型(不区分大小写):
* id/name/className/tagName/linkText/partialLinkText/css/xpath/label/value/index
* @param locatorValue 定位值
* @return By 定位器对象
* @throws IllegalArgumentException 如果定位类型不支持
*/
public By getLocator(String locatorType, String locatorValue) {
if (locatorValue == null || locatorValue.trim().isEmpty()) {
throw new IllegalArgumentException("定位值不能为空");
}
switch (locatorType.toLowerCase()) {
case "id":
return By.id(locatorValue);
case "name":
return By.name(locatorValue);
case "classname":
case "class":
return By.className(locatorValue);
case "tagname":
case "tag":
return By.tagName(locatorValue);
case "linktext":
case "link":
return By.linkText(locatorValue);
case "partiallinktext":
case "partiallink":
return By.partialLinkText(locatorValue);
case "css":
case "cssselector":
return By.cssSelector(locatorValue);
case "xpath":
return By.xpath(locatorValue);
case "label":
// 通过label文本定位对应的元素
return By.xpath(String.format("//label[contains(text(), '%s')]", locatorValue));
case "value":
// 通过value属性定位
return By.xpath(String.format("//*[@value='%s']", locatorValue));
case "index":
// 索引定位需要特殊处理,通常结合其他定位方式使用
try {
int index = Integer.parseInt(locatorValue);
return By.xpath(String.format("(//*)[%d]", index + 1)); // XPath索引从1开始
} catch (NumberFormatException e) {
throw new IllegalArgumentException("索引必须是数字: " + locatorValue);
}
default:
throw new IllegalArgumentException("不支持的定位类型: " + locatorType +
"。支持的定位类型: id,name,className,tagName,linkText," +
"partialLinkText,css,xpath,label,value,index");
}
}
/**
* 处理弹窗
* @param operationType 操作类型 (1=确定, 2=取消)
* @param inputText 需要输入的文本 (可为null表示不输入)
*/
public void handleAlert(int operationType, String inputText) {
try {
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
// 如果有输入文本
if (inputText != null && !inputText.isEmpty()) {
alert.sendKeys(inputText);
log.info("已在弹窗中输入文本: {}", inputText);
}
// 执行确认或取消操作
if (operationType == 1) {
alert.accept();
log.info("已确认弹窗");
} else if (operationType == 2) {
alert.dismiss();
log.info("已取消弹窗");
} else {
throw new IllegalArgumentException("无效的弹窗操作类型: " + operationType);
}
} catch (NoAlertPresentException e) {
log.error("没有找到弹窗", e);
throw new RuntimeException("当前没有可操作的弹窗", e);
} catch (TimeoutException e) {
log.error("等待弹窗超时", e);
throw new RuntimeException("等待弹窗出现超时", e);
}
}
/**
* 获取弹窗文本
* @return 弹窗显示的文本内容
*/
public String getAlertText() {
try {
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
String text = alert.getText();
log.info("获取到弹窗文本: {}", text);
return text;
} catch (Exception e) {
log.error("获取弹窗文本失败", e);
throw new RuntimeException("无法获取弹窗文本", e);
}
}
/**
* 根据定位方式和定位值查找元素
* @param locType 定位方式 (如 "id", "xpath", "cssSelector" 等)
* @param locValue 定位值
* @return 找到的WebElement
*/
public WebElement findElement(String locType, String locValue) {
try {
By by = getLocator(locType, locValue);
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(by));
return element;
} catch (Exception e) {
throw new RuntimeException("无法定位元素,定位方式:" + locType + ",定位值:" + locValue, e);
}
}
/**
* 操作下拉框
* @param element 下拉框元素
* @param optionType 选项类型 (1=选项文本, 2=索引, 3=值)
* @param optionValue 选项值
*/
public void selectDropdownOption(WebElement element, String optionType, String optionValue) {
Select select = new Select(element);
try {
switch (optionType) {
case "1": // 选项文本
select.selectByVisibleText(optionValue);
log.info("通过选项文本选择下拉框选项: {}", optionValue);
break;
case "2": // 索引
int index = Integer.parseInt(optionValue);
select.selectByIndex(index);
log.info("通过索引选择下拉框选项: {}", index);
break;
case "3": // 值
select.selectByValue(optionValue);
log.info("通过值选择下拉框选项: {}", optionValue);
break;
default:
throw new IllegalArgumentException("不支持的选项类型: " + optionType);
}
} catch (Exception e) {
log.error("操作下拉框失败", e);
throw new RuntimeException("操作下拉框失败", e);
}
}
/**
* 等待元素满足指定条件
* @param locator 元素定位器
* @param operate 操作类型:
* 1=等待元素文本等于给定值
* 2=等待元素存在
* 3=等待元素显示
* 4=等待元素不显示
* 5=等待元素不存在
* 6=等待元素可编辑
* 7=等待元素不可编辑
* @param awaitValue 等待的值(用于文本比较或自定义超时时间)
* @param timeoutInMillis 默认超时时间(毫秒)
*/
public void waitForElement(By locator, int operate, String awaitValue, long timeoutInMillis) {
WebDriverWait customWait = new WebDriverWait(driver, Duration.ofMillis(timeoutInMillis));
try {
switch (operate) {
case 1: // 等待元素文本等于给定值
customWait.until(ExpectedConditions.textToBe(locator, awaitValue));
log.info("元素文本已等于: {}", awaitValue);
break;
case 2: // 等待元素存在
customWait.until(ExpectedConditions.presenceOfElementLocated(locator));
log.info("元素已存在");
break;
case 3: // 等待元素显示
customWait.until(ExpectedConditions.visibilityOfElementLocated(locator));
log.info("元素已显示");
break;
case 4: // 等待元素不显示
customWait.until(ExpectedConditions.invisibilityOfElementLocated(locator));
log.info("元素已不显示");
break;
case 5: // 等待元素不存在
boolean isAbsent = customWait.until(ExpectedConditions.not(
ExpectedConditions.presenceOfElementLocated(locator)
));
log.info("元素已不存在");
break;
case 6: // 等待元素可编辑
customWait.until(driver -> {
WebElement element = driver.findElement(locator);
return element.isEnabled() && !element.getAttribute("readonly").equals("true");
});
log.info("元素已可编辑");
break;
case 7: // 等待元素不可编辑
customWait.until(driver -> {
WebElement element = driver.findElement(locator);
return !element.isEnabled() || element.getAttribute("readonly").equals("true");
});
log.info("元素已不可编辑");
break;
default:
throw new IllegalArgumentException("不支持的等待操作类型: " + operate);
}
} catch (TimeoutException e) {
log.error("等待元素超时,操作类型: {}, 定位器: {}", operate, locator);
throw new RuntimeException("等待元素条件未满足: " + getOperationDescription(operate), e);
}
}
// 获取操作类型描述
private String getOperationDescription(int operate) {
switch (operate) {
case 1: return "文本等于给定值";
case 2: return "元素存在";
case 3: return "元素显示";
case 4: return "元素不显示";
case 5: return "元素不存在";
case 6: return "元素可编辑";
case 7: return "元素不可编辑";
default: return "未知操作";
}
}
/**
* 执行鼠标操作
* @param locator 元素定位器
* @param clickMethod 点击方式:
* 1=单击(左键)
* 2=单击(右键)
* 3=双击
* 4=按下
* 5=弹起
*/
public void performMouseAction(By locator, int clickMethod) {
try {
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(locator));
switch (clickMethod) {
case 1: // 左键单击
actions.click(element).perform();
log.info("已执行左键单击操作");
break;
case 2: // 右键单击
actions.contextClick(element).perform();
log.info("已执行右键单击操作");
break;
case 3: // 双击
actions.doubleClick(element).perform();
log.info("已执行双击操作");
break;
case 4: // 按下
actions.clickAndHold(element).perform();
log.info("已执行鼠标按下操作");
break;
case 5: // 弹起
actions.release(element).perform();
log.info("已执行鼠标弹起操作");
break;
default:
throw new IllegalArgumentException("不支持的鼠标操作类型: " + clickMethod);
}
} catch (TimeoutException e) {
log.error("等待元素可点击超时,定位器: {}", locator);
throw new RuntimeException("元素不可点击或未找到: " + locator, e);
} catch (Exception e) {
log.error("鼠标操作执行失败", e);
throw new RuntimeException("鼠标操作失败: " + e.getMessage(), e);
}
}
/**
* 执行鼠标移动操作
* @param locator 元素定位器
* @param moveType 移动类型:
* 1=鼠标移出元素
* 2=鼠标移入元素
*/
public void performMouseMove(By locator, int moveType) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
switch (moveType) {
case 1: // 鼠标移出元素
// 先移动到元素上,再移动到页面左上角
actions.moveToElement(element)
.moveByOffset(-element.getSize().getWidth(), -element.getSize().getHeight())
.perform();
log.info("已将鼠标从元素移出");
break;
case 2: // 鼠标移入元素(悬停)
actions.moveToElement(element).perform();
log.info("已将鼠标悬停在元素上");
break;
default:
throw new IllegalArgumentException("不支持的鼠标移动类型: " + moveType);
}
} catch (TimeoutException e) {
log.error("等待元素可见超时,定位器: {}", locator);
throw new RuntimeException("元素不可见或未找到: " + locator, e);
} catch (Exception e) {
log.error("鼠标移动操作执行失败", e);
throw new RuntimeException("鼠标移动操作失败: " + e.getMessage(), e);
}
}
/**
* 在指定元素中输入文本
* @param locator 元素定位器
* @param text 要输入的文本
* @param clearFirst 是否先清空原有内容
* @param inputMethod 输入方式:
* 1=普通输入sendKeys
* 2=通过JavaScript设置值
* 3=模拟人工输入(带延迟)
*/
public void inputText(By locator, String text, boolean clearFirst, int inputMethod) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
// 先清空内容(如果需要)
if (clearFirst) {
element.clear();
log.info("已清空输入框内容");
}
switch (inputMethod) {
case 1: // 普通输入
element.sendKeys(text);
log.info("已通过sendKeys输入文本: {}", text);
break;
case 2: // JavaScript输入
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].value = arguments[1]", element, text);
log.info("已通过JavaScript设置文本: {}", text);
break;
case 3: // 模拟人工输入
for (char c : text.toCharArray()) {
element.sendKeys(String.valueOf(c));
Thread.sleep(50); // 每个字符间隔50ms
}
log.info("已模拟人工输入文本: {}", text);
break;
default:
throw new IllegalArgumentException("不支持的输入方式: " + inputMethod);
}
} catch (TimeoutException e) {
log.error("等待输入元素可见超时,定位器: {}", locator);
throw new RuntimeException("输入元素不可见或未找到: " + locator, e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("模拟人工输入被中断");
throw new RuntimeException("输入操作被中断", e);
} catch (Exception e) {
log.error("输入操作执行失败", e);
throw new RuntimeException("输入操作失败: " + e.getMessage(), e);
}
}
/**
* 在可编辑段落中输入文本(如富文本编辑器)
* @param locator 元素定位器
* @param text 要输入的文本
*/
public void inputToEditableDiv(By locator, String text) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
element.click(); // 先点击激活
element.sendKeys(text);
log.info("已在可编辑段落中输入文本: {}", text);
} catch (Exception e) {
log.error("可编辑段落输入失败", e);
throw new RuntimeException("可编辑段落输入失败: " + e.getMessage(), e);
}
}
/**
* 清空输入框内容
* @param locator 元素定位器
*/
public void clearInput(By locator) {
try {
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
element.clear();
log.info("已清空输入框内容");
} catch (Exception e) {
log.error("清空输入框失败", e);
throw new RuntimeException("清空输入框失败: " + e.getMessage(), e);
}
}
} }

View File

@@ -52,11 +52,11 @@ public class UiSceneSteps extends BaseEntity
/** 元素库名称 */ /** 元素库名称 */
@Excel(name = "元素库名称") @Excel(name = "元素库名称")
private Integer operateGroupId; private Long operateGroupId;
/** 元素id */ /** 元素id */
@Excel(name = "元素id") @Excel(name = "元素id")
private Integer operateElementId; private Long operateElementId;
/** 元素定位类型 */ /** 元素定位类型 */
@Excel(name = "元素定位类型") @Excel(name = "元素定位类型")
@@ -76,7 +76,7 @@ public class UiSceneSteps extends BaseEntity
/** 窗口尺寸 */ /** 窗口尺寸 */
@Excel(name = "窗口尺寸") @Excel(name = "窗口尺寸")
private Integer windowSize; private String windowSize;
/** 子选项 */ /** 子选项 */
@Excel(name = "子选项") @Excel(name = "子选项")
@@ -201,21 +201,21 @@ public class UiSceneSteps extends BaseEntity
{ {
return operateObject; return operateObject;
} }
public void setOperateGroupId(Integer operateGroupId) public void setOperateGroupId(Long operateGroupId)
{ {
this.operateGroupId = operateGroupId; this.operateGroupId = operateGroupId;
} }
public Integer getOperateGroupId() public Long getOperateGroupId()
{ {
return operateGroupId; return operateGroupId;
} }
public void setOperateElementId(Integer operateElementId) public void setOperateElementId(Long operateElementId)
{ {
this.operateElementId = operateElementId; this.operateElementId = operateElementId;
} }
public Integer getOperateElementId() public Long getOperateElementId()
{ {
return operateElementId; return operateElementId;
} }
@@ -255,12 +255,12 @@ public class UiSceneSteps extends BaseEntity
{ {
return inputValue; return inputValue;
} }
public void setWindowSize(Integer windowSize) public void setWindowSize(String windowSize)
{ {
this.windowSize = windowSize; this.windowSize = windowSize;
} }
public Integer getWindowSize() public String getWindowSize()
{ {
return windowSize; return windowSize;
} }

View File

@@ -68,7 +68,7 @@ public class UiSceneStepsQO extends BaseEntity
private String inputValue; private String inputValue;
/** 窗口尺寸 */ /** 窗口尺寸 */
private Integer windowSize; private String windowSize;
/** 子选项 */ /** 子选项 */
private String subOptions; private String subOptions;

View File

@@ -190,6 +190,7 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
uiAutomation.setStatus("1"); //未开始 uiAutomation.setStatus("1"); //未开始
uiAutomation.setDutyBy(SecurityUtils.getUsername()); uiAutomation.setDutyBy(SecurityUtils.getUsername());
uiAutomation.setDelFlag(0); uiAutomation.setDelFlag(0);
uiAutomation.setCrontabStatus(0); //未开启
uiAutomationMapper.insertUiAutomation(uiAutomation); uiAutomationMapper.insertUiAutomation(uiAutomation);
Long automationId = uiAutomation.getId(); Long automationId = uiAutomation.getId();
//新增场景步骤 //新增场景步骤

View File

@@ -1,32 +1,26 @@
package com.test.test.service.impl; package com.test.test.service.impl;
import java.util.Date; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.test.common.config.TestConfig;
import com.test.common.utils.DateUtils; import com.test.common.utils.DateUtils;
import com.test.common.utils.SecurityUtils; import com.test.common.utils.SecurityUtils;
import com.test.common.utils.SeleniumUtils; import com.test.common.utils.SeleniumUtils;
import com.test.common.utils.StringUtils; import com.test.common.utils.StringUtils;
import com.test.test.domain.UiAutomation; import com.test.test.domain.*;
import com.test.test.domain.UiReport;
import com.test.test.domain.UiSceneSteps;
import com.test.test.domain.UiSceneStepsReport;
import com.test.test.domain.qo.OtherSettingsQO; import com.test.test.domain.qo.OtherSettingsQO;
import com.test.test.domain.vo.UiHighSettingVO; import com.test.test.domain.vo.UiHighSettingVO;
import com.test.test.mapper.UiAutomationMapper; import com.test.test.mapper.UiAutomationMapper;
import com.test.test.mapper.UiSceneStepsMapper; import com.test.test.mapper.UiSceneStepsMapper;
import com.test.test.mapper.UiSceneStepsReportMapper; import com.test.test.mapper.UiSceneStepsReportMapper;
import com.test.test.service.IUiAutomationService; import com.test.test.service.*;
import com.test.test.service.IUiReportService;
import com.test.test.service.IUiSceneStepsService;
import com.test.test.service.StepExecution;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.C; import org.checkerframework.checker.units.qual.C;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -46,18 +40,12 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
private UiSceneStepsReportMapper uiSceneStepsReportMapper; private UiSceneStepsReportMapper uiSceneStepsReportMapper;
@Resource @Resource
private IUiAutomationService uiAutomationService; private IUiAutomationService uiAutomationService;
//场景成功数 @Resource
private Integer scenesSucceedNumber = 0; private IUiElementService uiElementService;
//场景失败数 @Resource
private Integer scenesErrorNumber = 0; private UiAutomationMapper uiAutomationMapper;
//场景未执行数
private Integer scenesNotNumber = 0;
//步骤成功数
private Integer stepsSucceedNumber = 0;
//步骤失败数
private Integer stepsErrorNumber = 0;
//步骤未执行数
private Integer stepsNotNumber = 0;
/** /**
@@ -72,7 +60,14 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
result.put("id", 0L); result.put("id", 0L);
// 1. 验证并获取步骤 // 1. 验证并获取步骤
List<UiSceneSteps> steps = validateAndGetSteps(automationId); List<UiSceneSteps> steps = validateAndGetSteps(automationId);
stepsNotNumber = steps.size();
//修改ui_automation 状态为进行中 执行结果为running
UiAutomation uiAutomation = new UiAutomation();
uiAutomation.setStatus("2");
uiAutomation.setExecutionResult("1");
uiAutomation.setUpdateBy(DateUtils.getTime());
uiAutomationMapper.updateUiAutomation(uiAutomation);
Date startTime = DateUtils.getNowDate(); Date startTime = DateUtils.getNowDate();
// 2. 创建执行报告 // 2. 创建执行报告
@@ -91,22 +86,48 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
// 3. 执行所有步骤 // 3. 执行所有步骤
executeAllSteps(steps, reportId); executeAllSteps(steps, reportId);
log.info("场景执行成功: {}", automationId); log.info("场景执行成功: {}", automationId);
scenesSucceedNumber++;
uiReport.setConsoleStr("OK"); uiReport.setConsoleStr("OK");
uiReport.setStatus(3); uiReport.setStatus(3);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
result.put("msg", e.getMessage()); result.put("msg", e.getMessage());
log.error("场景执行失败: {}", e.getMessage()); log.error("场景执行失败: {}", e.getMessage());
scenesErrorNumber++;
uiReport.setConsoleStr(e.toString()); uiReport.setConsoleStr(e.toString());
uiReport.setStatus(2); uiReport.setStatus(2);
uiAutomation.setExecutionResult("2");
} finally { } finally {
endTime = DateUtils.getNowDate(); endTime = DateUtils.getNowDate();
uiReport.setTake(DateUtils.calculateTimeDifference(startTime, endTime)); uiReport.setTake(DateUtils.calculateTimeDifference(startTime, endTime));
uiReport.setUpdateTime(endTime); uiReport.setUpdateTime(endTime);
//查询report
UiSceneStepsReport uiStepsReport = new UiSceneStepsReport();
uiStepsReport.setReportId(reportId);
List<UiSceneStepsReport> uiSceneStepsReports = uiSceneStepsReportMapper.selectUiSceneStepsReportList(uiStepsReport);
int scenesSucceedNumber = 0;
int scenesErrorNumber = 0;
int stepsSucceedNumber = 0;
int stepsErrorNumber = 0;
int stepsNotNumber = 0;
if (uiSceneStepsReports != null && !uiSceneStepsReports.isEmpty()) {
boolean allSuccess = true;
for (UiSceneStepsReport report : uiSceneStepsReports) {
if (report.getExecutionFlag().equals("1")) {
stepsSucceedNumber++;
} else if (report.getExecutionFlag().equals("2")) {
stepsErrorNumber++;
allSuccess = false;
} else if (report.getExecutionFlag().equals("0")) {
stepsNotNumber++;
}
}
if (allSuccess) {
scenesSucceedNumber = 1;
} else {
scenesErrorNumber = 1;
}
}
uiReport.setScenesSucceedNumber(scenesSucceedNumber); uiReport.setScenesSucceedNumber(scenesSucceedNumber);
uiReport.setScenesErrorNumber(scenesErrorNumber); uiReport.setScenesErrorNumber(scenesErrorNumber);
uiReport.setScenesNotNumber(scenesNotNumber); uiReport.setScenesNotNumber(0);
uiReport.setStepsSucceedNumber(stepsSucceedNumber); uiReport.setStepsSucceedNumber(stepsSucceedNumber);
uiReport.setStepsErrorNumber(stepsErrorNumber); uiReport.setStepsErrorNumber(stepsErrorNumber);
uiReport.setStepsNotNumber(stepsNotNumber); uiReport.setStepsNotNumber(stepsNotNumber);
@@ -116,6 +137,16 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
); );
uiReportService.updateUiReport(uiReport); uiReportService.updateUiReport(uiReport);
//修改ui_automation
uiAutomation = new UiAutomation();
if (!uiAutomation.getExecutionResult().equals("2")){
uiAutomation.setExecutionResult("3");
uiAutomation.setStatus("3");
}
uiAutomation.setUpdateBy(DateUtils.getTime());
uiAutomation.setPassRate(stepsSucceedNumber == 0 ? "0%" :
String.format("%.2f%%", (double)stepsSucceedNumber / steps.size() * 100));
uiAutomationMapper.updateUiAutomation(uiAutomation);
} }
return result; return result;
} }
@@ -128,6 +159,7 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
*/ */
private List<UiSceneSteps> validateAndGetSteps(Long automationId) { private List<UiSceneSteps> validateAndGetSteps(Long automationId) {
List<UiSceneSteps> steps = uiSceneStepsMapper.selectUiSceneStepsById(automationId); List<UiSceneSteps> steps = uiSceneStepsMapper.selectUiSceneStepsById(automationId);
steps = steps.stream().filter(e->e.getIsDisabled() == 0).collect(Collectors.toList());
if (CollectionUtils.isEmpty(steps)) { if (CollectionUtils.isEmpty(steps)) {
throw new IllegalArgumentException("步骤不能为空"); throw new IllegalArgumentException("步骤不能为空");
} }
@@ -186,30 +218,29 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
// 定义所有操作类型的执行方法映射 // 定义所有操作类型的执行方法映射
Map<String, Map<String, StepExecution>> operationStrategies = Map.of( Map<String, Map<String, StepExecution>> operationStrategies = Map.of(
"1", Map.of( // 浏览器操作 "1", Map.of( // 浏览器操作
"1", this::openWebPage "1", this::openWebPage,
// "2", this::closeBrowser, "2", this::closeBrowser,
// "3", this::switchWindow, "3", this::switchWindow,
// "4", this::resizeWindow, "4", this::resizeWindow,
// "5", this::selectEmbeddedPage "5", this::selectEmbeddedPage
),
"2", Map.of( // 弹窗操作
"1", this::handlePopup
),
"3", Map.of( // 元素操作
"1", this::submitForm,
"2", this::handleDropdown,
"3", this::setOption,
"4", this::waitForElement
),
"4", Map.of( // 鼠标操作
"1", this::mouseClick,
"2", this::mouseMove
),
"5", Map.of( // 输入操作
"1", this::inputText,
"2", this::uploadFile
) )
// "2", Map.of( // 弹窗操作
// "1", this::handlePopup
// ),
// "3", Map.of( // 元素操作
// "1", this::submitForm,
// "2", this::handleDropdown,
// "3", this::setOption,
// "4", this::waitForElement
// ),
// "4", Map.of( // 鼠标操作
// "1", this::mouseClick,
// "2", this::mouseMove,
// "3", this::mouseDrag
// ),
// "5", Map.of( // 输入操作
// "1", this::inputText,
// "2", this::uploadFile
// )
); );
// 获取对应的操作类型映射 // 获取对应的操作类型映射
@@ -253,7 +284,16 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
UiHighSettingVO otherSetting = extractOtherSetting(uiHighSettingVOList); UiHighSettingVO otherSetting = extractOtherSetting(uiHighSettingVOList);
OtherSettingsQO otherSettingsQO = otherSetting.getOtherSettingsQO(); OtherSettingsQO otherSettingsQO = otherSetting.getOtherSettingsQO();
Integer screenshotConfiguration = otherSettingsQO.getScreenshotConfiguration(); //是否截图 1当前步骤截图 2异常截图 3 不截图 Integer screenshotConfiguration = otherSettingsQO.getScreenshotConfiguration(); //是否截图 1当前步骤截图 2异常截图 3 不截图
//等待元素超时时间
Integer waitElementTime = otherSettingsQO.getWaitElementTime()==null?0:otherSettingsQO.getWaitElementTime();
//前置操作设置
List<UiHighSettingVO> beforeSettingList = extractbeforeSetting(uiHighSettingVOList);
//后置操作设置
List<UiHighSettingVO> afterSettingList = extractafterSetting(uiHighSettingVOList);
//前置等待时间
int beforeAwaitTime = getAwaitTime(beforeSettingList);
//后置等待时间
int afterAwaitTime = getAwaitTime(afterSettingList);
// 2. 准备报告对象 // 2. 准备报告对象
UiSceneStepsReport report = new UiSceneStepsReport(); UiSceneStepsReport report = new UiSceneStepsReport();
report.setId(sceneStepsReportId); report.setId(sceneStepsReportId);
@@ -261,28 +301,42 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
Date endTime = null; Date endTime = null;
boolean continueExecution = true; // 默认继续执行 boolean continueExecution = true; // 默认继续执行
try { try {
stepsSucceedNumber++; // 执行前置等待
if (screenshotConfiguration == 1) { if (beforeAwaitTime > 0) {
log.info("执行前置等待: {}ms", beforeAwaitTime);
Thread.sleep(beforeAwaitTime);
}
if (screenshotConfiguration == 1) {
report.setScreenshot(seleniumUtils.takeScreenshotAsFile(TestConfig.getProfile()));
log.info("截图成功,路径:{}",seleniumUtils.takeScreenshotAsFile(TestConfig.getProfile()));
} }
// 3. 执行具体步骤 // 3. 执行具体步骤
stepExecution.execute(step, seleniumUtils); stepExecution.execute(step, seleniumUtils);
// 执行后置等待
if (afterAwaitTime > 0) {
log.info("执行后置等待: {}ms", afterAwaitTime);
Thread.sleep(afterAwaitTime);
}
report.setLogInfo("OK"); report.setLogInfo("OK");
report.setExecutionFlag("1"); report.setExecutionFlag("1");
} catch (Exception e) { } catch (Exception e) {
// 4. 错误处理 // 4. 错误处理
stepsErrorNumber++;
stepsSucceedNumber--;
report.setLogInfo(e.toString()); report.setLogInfo(e.toString());
report.setExecutionFlag("2"); report.setExecutionFlag("2");
// 根据错误处理设置决定是否继续 // 根据错误处理设置决定是否继续
if ("1".equals(errorSetting.getErrorHandling())) { if ("1".equals(errorSetting.getErrorHandling())) {
continueExecution = false; // 不继续执行后续步骤 continueExecution = false; // 不继续执行后续步骤
} }
if (screenshotConfiguration == 2) {
report.setScreenshot(seleniumUtils.takeScreenshotAsFile(TestConfig.getProfile()));
log.info("截图成功,路径:{}",seleniumUtils.takeScreenshotAsFile(TestConfig.getProfile()));
}
log.error("步骤执行失败: {}", e.getMessage()); log.error("步骤执行失败: {}", e.getMessage());
} finally { } finally {
endTime = DateUtils.getNowDate(); endTime = DateUtils.getNowDate();
stepsNotNumber--;
// 更新报告 // 更新报告
report.setCreateTime(startTime); report.setCreateTime(startTime);
report.setUpdateTime(endTime); report.setUpdateTime(endTime);
@@ -293,6 +347,52 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
return continueExecution; return continueExecution;
} }
/**
* 提取前置操作
* @param settings
* @return
*/
private List<UiHighSettingVO> extractbeforeSetting(List<UiHighSettingVO> settings) {
return settings.stream()
.filter(e -> "1".equals(e.getSettingType()) && e.getIsDisabled() == 0)
.collect(Collectors.toList()); // 返回默认设置
}
/**
* 获取(前置//后置)等待时间
* @param settingList
* @return
*/
private int getAwaitTime(List<UiHighSettingVO> settingList){
//获取前置等待时间
int totalWaitTime = settingList.stream()
.map(UiHighSettingVO::getAwateTime)
.filter(Objects::nonNull)
.filter(s -> !s.isEmpty())
.mapToInt(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return 0;
}
})
.sum();
return totalWaitTime;
}
/**
* 提取后置操作
* @param settings
* @return
*/
private List<UiHighSettingVO> extractafterSetting(List<UiHighSettingVO> settings) {
return settings.stream()
.filter(e -> "2".equals(e.getSettingType()) && e.getIsDisabled() == 0)
.collect(Collectors.toList()); // 返回默认设置
}
/** /**
* 提取错误处理设置 * 提取错误处理设置
* @param settings * @param settings
@@ -305,6 +405,9 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
.orElse(new UiHighSettingVO()); // 返回默认设置 .orElse(new UiHighSettingVO()); // 返回默认设置
} }
/** /**
* 提取错误处理设置 * 提取错误处理设置
* @param settings * @param settings
@@ -317,6 +420,14 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
.orElse(new UiHighSettingVO()); // 返回默认设置 .orElse(new UiHighSettingVO()); // 返回默认设置
} }
//---------------------浏览器操作---------------------------
/** /**
* 打开网页 * 打开网页
* *
@@ -324,8 +435,465 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
* @param seleniumUtils Selenium工具类 * @param seleniumUtils Selenium工具类
*/ */
private void openWebPage(UiSceneSteps step, SeleniumUtils seleniumUtils) { private void openWebPage(UiSceneSteps step, SeleniumUtils seleniumUtils) {
log.info("打开网页:{}",step.getUrl());
seleniumUtils.openUrl(step.getUrl()); seleniumUtils.openUrl(step.getUrl());
} }
/**
* 关闭网页
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void closeBrowser(UiSceneSteps step, SeleniumUtils seleniumUtils) {
log.info("关闭网页");
seleniumUtils.quit();
}
/**
* 切换窗口
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void switchWindow(UiSceneSteps step, SeleniumUtils seleniumUtils) {
if (step.getOperate()==1){
log.info("根据句柄 ID 切换到指定窗口");
//句柄id
String handleId = step.getHandleId();
seleniumUtils.switchToWindowByHandle(handleId);
}else if (step.getOperate()==2){
log.info("根据网页索引号切换到指定窗口");
//网页索引号
Integer frameIndex = step.getFrameIndex();
seleniumUtils.switchToWindowByIndex(frameIndex);
}else if (step.getOperate()==3){
log.info("切换到初始窗口");
seleniumUtils.switchToDefaultWindow();
}else{
log.info("无效的窗口切换操作类型");
throw new IllegalArgumentException("无效的窗口切换操作类型");
}
}
/**
* 设置窗口大小
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void resizeWindow(UiSceneSteps step, SeleniumUtils seleniumUtils) {
if (step.getOperate()==1){
log.info("窗口最大化");
//窗口最大化
seleniumUtils.maximizeWindow();
}else if (step.getOperate()==2){
log.info("设置窗口大小");
String windowSize = step.getWindowSize();
String[] dimensions = windowSize.split("\\*");
int width = Integer.parseInt(dimensions[0]);
int height = Integer.parseInt(dimensions[1]);
seleniumUtils.setWindowSize(width, height);
}else{
log.info("无效的设置窗口大小");
throw new IllegalArgumentException("无效的设置窗口大小");
}
}
/**
* 选择内嵌网页
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void selectEmbeddedPage(UiSceneSteps step, SeleniumUtils seleniumUtils) {
if (step.getOperate()==1){
log.info("退出当前 frame(回到主页面)");
seleniumUtils.switchToDefaultContent();
}else if (step.getOperate()==2){
log.info("根据 frame 索引号切换到指定 frame");
//网页索引号
seleniumUtils.switchToFrameByIndex(step.getFrameIndex());
}else if (step.getOperate()==3){
log.info("根据定位方式切换 frame");
if ("2".equals(step.getOperateObject())) {
//元素对象
String operateLocType = step.getOperateLocType(); //属性
String operateLocValue = step.getOperateLocValue(); //值
seleniumUtils.switchToFrameByLocator(
operateLocType,
operateLocValue
);
}else{
//元素定位
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
if (uiElement == null) {
throw new IllegalArgumentException("未找到ID为 " + step.getOperateElementId() + " 的元素");
}
String locType = uiElement.getLocType(); //属性
String elementLoc = uiElement.getElementLoc();//值
seleniumUtils.switchToFrameByLocator(
locType,
elementLoc
);
}
} else{
log.info("无效的选择内嵌网页");
throw new IllegalArgumentException("无效的选择内嵌网页");
}
}
//--------------------弹窗操作--------------------
/**
* 弹窗操作
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void handlePopup(UiSceneSteps step, SeleniumUtils seleniumUtils) {
if (step.getOperate()==1){
log.info("弹窗操作");
// 获取输入内容(如果需要)
String inputValue = "1".equals(step.getIsEnter()) ? step.getInputValue() : null;
String operateWay = step.getOperateWay(); //操作方式 1确定 2取消
// 执行弹窗操作
seleniumUtils.handleAlert(
Integer.parseInt(operateWay), // 操作方式 (1=确定, 2=取消)
inputValue // 输入内容
);
}else{
log.info("无效的弹窗操作");
throw new IllegalArgumentException("无效的弹窗操作");
}
}
//---------------------------元素操作----------------------------------
/**
* 提交表单
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void submitForm(UiSceneSteps step, SeleniumUtils seleniumUtils) {
if ("2".equals(step.getOperateObject())) {
//元素对象
String operateLocType = step.getOperateLocType(); //属性
String operateLocValue = step.getOperateLocValue(); //值
// 根据属性和值定位元素并提交表单
seleniumUtils.findElement(operateLocType, operateLocValue).submit();
log.info("通过元素对象提交表单,定位方式:{},定位值:{}", operateLocType, operateLocValue);
}else{
//元素定位
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
if (uiElement == null) {
throw new IllegalArgumentException("未找到ID为 " + step.getOperateElementId() + " 的元素");
}
String locType = uiElement.getLocType(); //属性
String elementLoc = uiElement.getElementLoc();//值
seleniumUtils.findElement(locType, elementLoc).submit();
log.info("通过元素定位提交表单,定位方式:{},定位值:{}", locType, elementLoc);
}
}
/**
* 下拉框操作
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void handleDropdown(UiSceneSteps step, SeleniumUtils seleniumUtils) {
log.info("下拉框操作");
Integer operate = step.getOperate(); //操作 1选择 2取消
WebElement dropdownElement;
if ("2".equals(step.getOperateObject())) {
//元素对象
String operateLocType = step.getOperateLocType(); //属性
String operateLocValue = step.getOperateLocValue(); //值
dropdownElement = seleniumUtils.findElement(operateLocType, operateLocValue);
log.info("通过元素对象定位下拉框,定位方式:{},定位值:{}", operateLocType, operateLocValue);
}else{
//元素定位
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
if (uiElement == null) {
throw new IllegalArgumentException("未找到ID为 " + step.getOperateElementId() + " 的元素");
}
String locType = uiElement.getLocType(); //属性
String elementLoc = uiElement.getElementLoc();//值
dropdownElement = seleniumUtils.findElement(locType, elementLoc);
log.info("通过元素定位定位下拉框,定位方式:{},定位值:{}", locType, elementLoc);
}
//子选项
String subOptions = step.getSubOptions(); //1 选项 2索引 3值
String subOptionsValue = step.getSubOptionsValue(); //值
if (operate == 1) {
// 选择操作
seleniumUtils.selectDropdownOption(dropdownElement, subOptions, subOptionsValue);
} else if (operate == 2) {
// 取消操作
// 如果需要取消下拉框的选择,可以使用默认选项或其他逻辑
log.info("取消下拉框选择");
// 示例:取消选择(假设下拉框的第一个选项是默认选项)
seleniumUtils.selectDropdownOption(dropdownElement, "2", "0");
} else {
throw new IllegalArgumentException("无效的操作类型: " + operate);
}
}
/**
* 设置选项
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void setOption(UiSceneSteps step, SeleniumUtils seleniumUtils) {
log.info("设置选项");
Integer operate = step.getOperate(); // 操作 1选择 2取消
WebElement element;
if ("2".equals(step.getOperateObject())) {
// 元素对象
String operateLocType = step.getOperateLocType(); // 属性
String operateLocValue = step.getOperateLocValue(); // 值
element = seleniumUtils.findElement(operateLocType, operateLocValue);
log.info("通过元素对象定位选项,定位方式:{},定位值:{}", operateLocType, operateLocValue);
} else {
// 元素定位
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
if (uiElement == null) {
log.error("未找到指定的元素元素ID{}", step.getOperateElementId());
throw new IllegalArgumentException("未找到指定的元素");
}
String locType = uiElement.getLocType(); // 属性
String elementLoc = uiElement.getElementLoc(); // 值
element = seleniumUtils.findElement(locType, elementLoc);
log.info("通过元素定位定位选项,定位方式:{},定位值:{}", locType, elementLoc);
}
if (operate == 1) {
// 选择操作
if (!element.isSelected()) {
element.click();
log.info("设置选项为选中状态");
}
} else if (operate == 2) {
// 取消操作
if (element.isSelected()) {
element.click();
log.info("设置选项为未选中状态");
}
} else {
throw new IllegalArgumentException("无效的操作类型: " + operate);
}
}
/**
* 等待元素
*
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void waitForElement(UiSceneSteps step, SeleniumUtils seleniumUtils) {
log.info("等待元素");
//操作 1等待元素等于给定的定值(Text) 2 等待元素存在 3等待元素显示 4等待元素不显示 5等待元素不存在 6等待元素可编辑 7等待元素不可编辑
By locator;
if ("2".equals(step.getOperateObject())) {
//元素对象
String operateLocType = step.getOperateLocType(); //属性
String operateLocValue = step.getOperateLocValue(); //值
// 使用直接指定的定位方式
locator = seleniumUtils.getLocator(
operateLocType,
operateLocValue
);
}else{
//元素定位
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
String locType = uiElement.getLocType(); //属性
String elementLoc = uiElement.getElementLoc();//值
locator = seleniumUtils.getLocator(
locType,
elementLoc
);
}
// 解析等待时间默认15000ms
long timeout = 15000;
if (step.getOperate() != 1 && step.getAwaitValue() != null) {
try {
timeout = Long.parseLong(step.getAwaitValue());
} catch (NumberFormatException e) {
log.warn("等待时间格式错误使用默认值15000ms");
}
}
// 执行等待操作
seleniumUtils.waitForElement(
locator,
step.getOperate(),
step.getOperate() == 1 ? step.getAwaitValue() : null,
timeout
);
}
//--------------------------鼠标操作------------------------------
/**
* 鼠标点击操作
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void mouseClick(UiSceneSteps step, SeleniumUtils seleniumUtils) {
try {
log.info("执行鼠标操作,方式: {}", step.getClickMethod());
// 获取定位器
By locator;
if ("2".equals(step.getOperateObject())) {
// 使用直接指定的定位方式
locator = seleniumUtils.getLocator(
step.getOperateLocType(),
step.getOperateLocValue()
);
} else {
// 使用元素ID从数据库获取定位信息
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
if (uiElement == null) {
throw new IllegalArgumentException("未找到ID为 " + step.getOperateElementId() + " 的元素");
}
locator = seleniumUtils.getLocator(
uiElement.getLocType(),
uiElement.getElementLoc()
);
}
// 执行鼠标操作
seleniumUtils.performMouseAction(
locator,
Integer.parseInt(step.getClickMethod())
);
} catch (NumberFormatException e) {
log.error("鼠标操作类型格式错误: {}", step.getClickMethod());
throw new RuntimeException("鼠标操作类型必须是数字(1-5)", e);
} catch (Exception e) {
log.error("鼠标操作执行失败", e);
throw new RuntimeException("鼠标操作失败: " + e.getMessage(), e);
}
}
/**
* 鼠标移动操作
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
private void mouseMove(UiSceneSteps step, SeleniumUtils seleniumUtils) {
try {
log.info("执行鼠标移动操作,方式: {}", step.getClickMethod());
// 获取定位器
By locator;
if ("2".equals(step.getOperateObject())) {
// 使用直接指定的定位方式
locator = seleniumUtils.getLocator(
step.getOperateLocType(),
step.getOperateLocValue()
);
} else {
// 使用元素ID从数据库获取定位信息
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
if (uiElement == null) {
throw new IllegalArgumentException("未找到ID为 " + step.getOperateElementId() + " 的元素");
}
locator = seleniumUtils.getLocator(
uiElement.getLocType(),
uiElement.getElementLoc()
);
}
// 执行鼠标移动操作
seleniumUtils.performMouseMove(
locator,
Integer.parseInt(step.getClickMethod()) // 1=移出2=移入
);
} catch (NumberFormatException e) {
log.error("鼠标移动类型格式错误: {}", step.getClickMethod());
throw new RuntimeException("鼠标移动类型必须是数字(1-2)", e);
} catch (Exception e) {
log.error("鼠标移动操作执行失败", e);
throw new RuntimeException("鼠标移动操作失败: " + e.getMessage(), e);
}
}
/**
* 输入操作
* @param step 步骤对象
* @param seleniumUtils Selenium工具类
*/
public void inputText(UiSceneSteps step, SeleniumUtils seleniumUtils) {
try {
log.info("执行输入操作,类型: {}", step.getOperate());
// 获取定位器
By locator;
if ("2".equals(step.getOperateObject())) {
// 使用直接指定的定位方式
locator = seleniumUtils.getLocator(
step.getOperateLocType(),
step.getOperateLocValue()
);
} else {
// 使用元素ID从数据库获取定位信息
UiElement uiElement = uiElementService.selectUiElementById(step.getOperateElementId());
if (uiElement == null) {
throw new IllegalArgumentException("未找到ID为 " + step.getOperateElementId() + " 的元素");
}
locator = seleniumUtils.getLocator(
uiElement.getLocType(),
uiElement.getElementLoc()
);
}
// 获取输入内容
String inputValue = step.getInputValue();
if (inputValue == null || inputValue.trim().isEmpty()) {
log.warn("输入内容为空,将执行清空操作");
seleniumUtils.clearInput(locator);
return;
}
// 执行输入操作
if (step.getOperate() == 1) { // 普通输入框
seleniumUtils.inputText(
locator,
inputValue,
true, // 默认先清空
1 // 默认使用普通输入方式
);
} else if (step.getOperate() == 2) { // 可编辑段落
seleniumUtils.inputToEditableDiv(
locator,
inputValue
);
} else {
throw new IllegalArgumentException("不支持的输入操作类型: " + step.getOperate());
}
} catch (Exception e) {
log.error("输入操作执行失败", e);
throw new RuntimeException("输入操作失败: " + e.getMessage(), e);
}
}
/**
* 文件上传
* @param step
* @param seleniumUtils
*/
public void uploadFile(UiSceneSteps step, SeleniumUtils seleniumUtils){
}
} }

View File

@@ -22,10 +22,12 @@
<result property="crontabStatus" column="crontab_status" /> <result property="crontabStatus" column="crontab_status" />
<result property="delFlag" column="del_flag" /> <result property="delFlag" column="del_flag" />
<result property="description" column="description" /> <result property="description" column="description" />
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
</resultMap> </resultMap>
<sql id="selectUiAutomationVo"> <sql id="selectUiAutomationVo">
select id, group_id, name, case_level, status, label, create_by, duty_by, run_environment, update_time, steps_number, execution_result, pass_rate, crontab, crontab_status, del_flag,description from ui_automation select id, group_id, name, case_level, status, label, create_by, duty_by, run_environment, update_time, steps_number, execution_result, pass_rate, crontab, crontab_status, del_flag,create_time,update_by from ui_automation
</sql> </sql>
<select id="selectUiAutomationList" parameterType="UiAutomation" resultMap="UiAutomationResult"> <select id="selectUiAutomationList" parameterType="UiAutomation" resultMap="UiAutomationResult">
@@ -126,6 +128,8 @@
<if test="crontabStatus != null">crontab_status,</if> <if test="crontabStatus != null">crontab_status,</if>
<if test="delFlag != null">del_flag,</if> <if test="delFlag != null">del_flag,</if>
<if test="description != null">description,</if> <if test="description != null">description,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="groupId != null">#{groupId},</if> <if test="groupId != null">#{groupId},</if>
@@ -144,6 +148,8 @@
<if test="crontabStatus != null">#{crontabStatus},</if> <if test="crontabStatus != null">#{crontabStatus},</if>
<if test="delFlag != null">#{delFlag},</if> <if test="delFlag != null">#{delFlag},</if>
<if test="description != null">#{description},</if> <if test="description != null">#{description},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
</trim> </trim>
</insert> </insert>
@@ -166,6 +172,8 @@
<if test="crontabStatus != null">crontab_status = #{crontabStatus},</if> <if test="crontabStatus != null">crontab_status = #{crontabStatus},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if> <if test="delFlag != null">del_flag = #{delFlag},</if>
<if test="description != null">description = #{description},</if> <if test="description != null">description = #{description},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>