UI执行接口
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.test.common.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.openqa.selenium.*;
|
||||
import org.openqa.selenium.interactions.Actions;
|
||||
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||
@@ -13,6 +14,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Selenium 工具类
|
||||
*/
|
||||
@Slf4j
|
||||
public class SeleniumUtils {
|
||||
|
||||
private WebDriver driver;
|
||||
@@ -238,9 +240,9 @@ public class SeleniumUtils {
|
||||
}
|
||||
|
||||
// 获取alert文本
|
||||
public String getAlertText() {
|
||||
return switchToAlert().getText();
|
||||
}
|
||||
// public String getAlertText() {
|
||||
// return switchToAlert().getText();
|
||||
// }
|
||||
|
||||
// 在alert中输入文本
|
||||
public void sendKeysToAlert(String text) {
|
||||
@@ -377,4 +379,480 @@ public class SeleniumUtils {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,11 +52,11 @@ public class UiSceneSteps extends BaseEntity
|
||||
|
||||
/** 元素库名称 */
|
||||
@Excel(name = "元素库名称")
|
||||
private Integer operateGroupId;
|
||||
private Long operateGroupId;
|
||||
|
||||
/** 元素id */
|
||||
@Excel(name = "元素id")
|
||||
private Integer operateElementId;
|
||||
private Long operateElementId;
|
||||
|
||||
/** 元素定位类型 */
|
||||
@Excel(name = "元素定位类型")
|
||||
@@ -76,7 +76,7 @@ public class UiSceneSteps extends BaseEntity
|
||||
|
||||
/** 窗口尺寸 */
|
||||
@Excel(name = "窗口尺寸")
|
||||
private Integer windowSize;
|
||||
private String windowSize;
|
||||
|
||||
/** 子选项 */
|
||||
@Excel(name = "子选项")
|
||||
@@ -201,21 +201,21 @@ public class UiSceneSteps extends BaseEntity
|
||||
{
|
||||
return operateObject;
|
||||
}
|
||||
public void setOperateGroupId(Integer operateGroupId)
|
||||
public void setOperateGroupId(Long operateGroupId)
|
||||
{
|
||||
this.operateGroupId = operateGroupId;
|
||||
}
|
||||
|
||||
public Integer getOperateGroupId()
|
||||
public Long getOperateGroupId()
|
||||
{
|
||||
return operateGroupId;
|
||||
}
|
||||
public void setOperateElementId(Integer operateElementId)
|
||||
public void setOperateElementId(Long operateElementId)
|
||||
{
|
||||
this.operateElementId = operateElementId;
|
||||
}
|
||||
|
||||
public Integer getOperateElementId()
|
||||
public Long getOperateElementId()
|
||||
{
|
||||
return operateElementId;
|
||||
}
|
||||
@@ -255,12 +255,12 @@ public class UiSceneSteps extends BaseEntity
|
||||
{
|
||||
return inputValue;
|
||||
}
|
||||
public void setWindowSize(Integer windowSize)
|
||||
public void setWindowSize(String windowSize)
|
||||
{
|
||||
this.windowSize = windowSize;
|
||||
}
|
||||
|
||||
public Integer getWindowSize()
|
||||
public String getWindowSize()
|
||||
{
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class UiSceneStepsQO extends BaseEntity
|
||||
private String inputValue;
|
||||
|
||||
/** 窗口尺寸 */
|
||||
private Integer windowSize;
|
||||
private String windowSize;
|
||||
|
||||
/** 子选项 */
|
||||
private String subOptions;
|
||||
|
||||
@@ -190,6 +190,7 @@ public class UiAutomationServiceImpl implements IUiAutomationService {
|
||||
uiAutomation.setStatus("1"); //未开始
|
||||
uiAutomation.setDutyBy(SecurityUtils.getUsername());
|
||||
uiAutomation.setDelFlag(0);
|
||||
uiAutomation.setCrontabStatus(0); //未开启
|
||||
uiAutomationMapper.insertUiAutomation(uiAutomation);
|
||||
Long automationId = uiAutomation.getId();
|
||||
//新增场景步骤
|
||||
|
||||
@@ -1,32 +1,26 @@
|
||||
package com.test.test.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.UiAutomation;
|
||||
import com.test.test.domain.UiReport;
|
||||
import com.test.test.domain.UiSceneSteps;
|
||||
import com.test.test.domain.UiSceneStepsReport;
|
||||
import com.test.test.domain.*;
|
||||
import com.test.test.domain.qo.OtherSettingsQO;
|
||||
import com.test.test.domain.vo.UiHighSettingVO;
|
||||
import com.test.test.mapper.UiAutomationMapper;
|
||||
import com.test.test.mapper.UiSceneStepsMapper;
|
||||
import com.test.test.mapper.UiSceneStepsReportMapper;
|
||||
import com.test.test.service.IUiAutomationService;
|
||||
import com.test.test.service.IUiReportService;
|
||||
import com.test.test.service.IUiSceneStepsService;
|
||||
import com.test.test.service.StepExecution;
|
||||
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.chrome.ChromeDriver;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -46,18 +40,12 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
private UiSceneStepsReportMapper uiSceneStepsReportMapper;
|
||||
@Resource
|
||||
private IUiAutomationService uiAutomationService;
|
||||
//场景成功数
|
||||
private Integer scenesSucceedNumber = 0;
|
||||
//场景失败数
|
||||
private Integer scenesErrorNumber = 0;
|
||||
//场景未执行数
|
||||
private Integer scenesNotNumber = 0;
|
||||
//步骤成功数
|
||||
private Integer stepsSucceedNumber = 0;
|
||||
//步骤失败数
|
||||
private Integer stepsErrorNumber = 0;
|
||||
//步骤未执行数
|
||||
private Integer stepsNotNumber = 0;
|
||||
@Resource
|
||||
private IUiElementService uiElementService;
|
||||
@Resource
|
||||
private UiAutomationMapper uiAutomationMapper;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@@ -72,7 +60,14 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
result.put("id", 0L);
|
||||
// 1. 验证并获取步骤
|
||||
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();
|
||||
// 2. 创建执行报告
|
||||
@@ -91,22 +86,48 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
// 3. 执行所有步骤
|
||||
executeAllSteps(steps, reportId);
|
||||
log.info("场景执行成功: {}", automationId);
|
||||
scenesSucceedNumber++;
|
||||
uiReport.setConsoleStr("OK");
|
||||
uiReport.setStatus(3);
|
||||
} catch (IllegalArgumentException e) {
|
||||
result.put("msg", e.getMessage());
|
||||
log.error("场景执行失败: {}", e.getMessage());
|
||||
scenesErrorNumber++;
|
||||
uiReport.setConsoleStr(e.toString());
|
||||
uiReport.setStatus(2);
|
||||
uiAutomation.setExecutionResult("2");
|
||||
} finally {
|
||||
endTime = DateUtils.getNowDate();
|
||||
uiReport.setTake(DateUtils.calculateTimeDifference(startTime, 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.setScenesErrorNumber(scenesErrorNumber);
|
||||
uiReport.setScenesNotNumber(scenesNotNumber);
|
||||
uiReport.setScenesNotNumber(0);
|
||||
uiReport.setStepsSucceedNumber(stepsSucceedNumber);
|
||||
uiReport.setStepsErrorNumber(stepsErrorNumber);
|
||||
uiReport.setStepsNotNumber(stepsNotNumber);
|
||||
@@ -116,6 +137,16 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
);
|
||||
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;
|
||||
}
|
||||
@@ -128,6 +159,7 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
*/
|
||||
private List<UiSceneSteps> validateAndGetSteps(Long automationId) {
|
||||
List<UiSceneSteps> steps = uiSceneStepsMapper.selectUiSceneStepsById(automationId);
|
||||
steps = steps.stream().filter(e->e.getIsDisabled() == 0).collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
throw new IllegalArgumentException("步骤不能为空");
|
||||
}
|
||||
@@ -186,30 +218,29 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
// 定义所有操作类型的执行方法映射
|
||||
Map<String, Map<String, StepExecution>> operationStrategies = Map.of(
|
||||
"1", Map.of( // 浏览器操作
|
||||
"1", this::openWebPage
|
||||
// "2", this::closeBrowser,
|
||||
// "3", this::switchWindow,
|
||||
// "4", this::resizeWindow,
|
||||
// "5", this::selectEmbeddedPage
|
||||
"1", this::openWebPage,
|
||||
"2", this::closeBrowser,
|
||||
"3", this::switchWindow,
|
||||
"4", this::resizeWindow,
|
||||
"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);
|
||||
OtherSettingsQO otherSettingsQO = otherSetting.getOtherSettingsQO();
|
||||
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. 准备报告对象
|
||||
UiSceneStepsReport report = new UiSceneStepsReport();
|
||||
report.setId(sceneStepsReportId);
|
||||
@@ -261,28 +301,42 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
Date endTime = null;
|
||||
boolean continueExecution = true; // 默认继续执行
|
||||
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. 执行具体步骤
|
||||
stepExecution.execute(step, seleniumUtils);
|
||||
|
||||
// 执行后置等待
|
||||
if (afterAwaitTime > 0) {
|
||||
log.info("执行后置等待: {}ms", afterAwaitTime);
|
||||
Thread.sleep(afterAwaitTime);
|
||||
}
|
||||
|
||||
report.setLogInfo("OK");
|
||||
report.setExecutionFlag("1");
|
||||
} catch (Exception e) {
|
||||
// 4. 错误处理
|
||||
stepsErrorNumber++;
|
||||
stepsSucceedNumber--;
|
||||
report.setLogInfo(e.toString());
|
||||
report.setExecutionFlag("2");
|
||||
// 根据错误处理设置决定是否继续
|
||||
if ("1".equals(errorSetting.getErrorHandling())) {
|
||||
continueExecution = false; // 不继续执行后续步骤
|
||||
}
|
||||
if (screenshotConfiguration == 2) {
|
||||
report.setScreenshot(seleniumUtils.takeScreenshotAsFile(TestConfig.getProfile()));
|
||||
log.info("截图成功,路径:{}",seleniumUtils.takeScreenshotAsFile(TestConfig.getProfile()));
|
||||
}
|
||||
log.error("步骤执行失败: {}", e.getMessage());
|
||||
} finally {
|
||||
endTime = DateUtils.getNowDate();
|
||||
stepsNotNumber--;
|
||||
// 更新报告
|
||||
report.setCreateTime(startTime);
|
||||
report.setUpdateTime(endTime);
|
||||
@@ -293,6 +347,52 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
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
|
||||
@@ -305,6 +405,9 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
.orElse(new UiHighSettingVO()); // 返回默认设置
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 提取错误处理设置
|
||||
* @param settings
|
||||
@@ -317,6 +420,14 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
.orElse(new UiHighSettingVO()); // 返回默认设置
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------浏览器操作---------------------------
|
||||
|
||||
/**
|
||||
* 打开网页
|
||||
*
|
||||
@@ -324,8 +435,465 @@ public class UiSceneStepsServiceImpl implements IUiSceneStepsService {
|
||||
* @param seleniumUtils Selenium工具类
|
||||
*/
|
||||
private void openWebPage(UiSceneSteps step, SeleniumUtils seleniumUtils) {
|
||||
log.info("打开网页:{}",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){
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,10 +22,12 @@
|
||||
<result property="crontabStatus" column="crontab_status" />
|
||||
<result property="delFlag" column="del_flag" />
|
||||
<result property="description" column="description" />
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
</resultMap>
|
||||
|
||||
<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>
|
||||
|
||||
<select id="selectUiAutomationList" parameterType="UiAutomation" resultMap="UiAutomationResult">
|
||||
@@ -126,6 +128,8 @@
|
||||
<if test="crontabStatus != null">crontab_status,</if>
|
||||
<if test="delFlag != null">del_flag,</if>
|
||||
<if test="description != null">description,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateBy != null">update_by,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="groupId != null">#{groupId},</if>
|
||||
@@ -144,6 +148,8 @@
|
||||
<if test="crontabStatus != null">#{crontabStatus},</if>
|
||||
<if test="delFlag != null">#{delFlag},</if>
|
||||
<if test="description != null">#{description},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateBy != null">#{updateBy},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
@@ -166,6 +172,8 @@
|
||||
<if test="crontabStatus != null">crontab_status = #{crontabStatus},</if>
|
||||
<if test="delFlag != null">del_flag = #{delFlag},</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>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
Reference in New Issue
Block a user