添加事件操作注入功能

This commit is contained in:
彭宇琦 2020-07-10 19:31:56 +08:00
parent bf549f3f32
commit eb427a1b61
11 changed files with 301 additions and 71 deletions

View File

@ -107,7 +107,7 @@ public class CommonBy extends AbstractBy {
switchFrame(getParentFrameName(elementInformation.name));
}
return new Element(driver, ElementType.COMMON_ELEMENT, recognitionElement(elementInformation));
return new Element(driver, ElementType.COMMON_ELEMENT, recognitionElement(elementInformation), elementInformation.name);
}
@Override

View File

@ -36,6 +36,11 @@ public class Element {
*/
private WebDriver driver;
/**
* 用于存储元素的名称
*/
private String name;
/**
* 标记元素的类型以用于重新获取时
*/
@ -46,12 +51,13 @@ public class Element {
* @param name 元素名称或定位内容
* @param byType 元素定位
*/
public Element(WebDriver driver, ElementType elementType, By by, int index) {
public Element(WebDriver driver, ElementType elementType, By by, String name, int index) {
super();
this.by = by;
this.index = index;
this.driver = driver;
this.elementType = elementType;
this.name = name;
}
/**
@ -59,8 +65,8 @@ public class Element {
* @param name 元素名称或定位内容
* @param byType 元素定位
*/
public Element(WebDriver driver, ElementType elementType, By by) {
this(driver, elementType, by, 0);
public Element(WebDriver driver, ElementType elementType, By by, String name) {
this(driver, elementType, by, name, 0);
}
/**
@ -94,4 +100,29 @@ public class Element {
throw new IllegalArgumentException("Unexpected value: " + elementType);
}
}
/**
* 用于返回元素 的名称
* @return 元素名称
*/
public String getName() {
return name;
}
/**
* 用于返回元素信息输出格式元素名称 + 元素 + 列表选项
* @return 元素信息
*/
public String getLog() {
switch (elementType) {
case COMMON_ELEMENT:
return name + "元素";
case DATA_LIST_ELEMENT:
case SELECT_DATAS_ELEMENT:
case SELECT_OPTION_ELEMENT:
return name + "元素第" + index + "个选项";
default:
throw new IllegalArgumentException("Unexpected value: " + elementType);
}
}
}

View File

@ -93,7 +93,7 @@ public abstract class ListBy extends MultiBy {
int size = driver.findElements(by).size();
//构造Element对象
for (int i = 0; i < size; i++) {
elementList.add(new Element(driver, ElementType.DATA_LIST_ELEMENT, by, i));
elementList.add(new Element(driver, ElementType.DATA_LIST_ELEMENT, by, elementInformation.name, i));
}
//elementList = driver.findElements(recognitionElement(elementInformation));
//添加元素

View File

@ -198,7 +198,7 @@ public class SelectBy extends MultiBy {
//构造Element对象
for (int i = 0; i < size; i++) {
//获取元素
option.add(new Element(driver, elementType, by, i));
option.add(new Element(driver, elementType, by, elementInformation.name, i));
//获取元素的文本内容
optionText.add(elementList.get(i).getText());
}

View File

@ -2,16 +2,14 @@ package pres.auxiliary.work.selenium.event;
import java.time.Duration;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
/**
* <p><b>文件名</b>AbstractEvent.java</p>
* <p><b>用途</b>所有事件类的基类包含了事件类所用到的基础方法以及弹窗处理方法和窗体窗口的切换方法</p>
* <p><b>编码时间</b>2019年9月24日下午4:24:15</p>
* <p><b>修改时间</b>2020年5月10日 下午3:42:15</p>
* <p><b>修改时间</b>2020年7月10日上午16:49:37</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
@ -31,16 +29,6 @@ public abstract class AbstractEvent {
*/
long waitTime = 5;
/**
* 用于在记录步骤时需要替换的元素名称文本
*/
public static final String ELEMENT_NAME = "&{元素名称}";
/**
* 存储事件的操作说明
*/
String step = "";
/**
* 构造对象并存储浏览器的WebDriver对象
*
@ -59,29 +47,4 @@ public abstract class AbstractEvent {
public void setWaitTime(long waitTime) {
wait.withTimeout(Duration.ofSeconds(waitTime));
}
/**
* 用于获取事件的文字说明其文字存在一个可以替换元素名称的预留字段可根据参数确定返回时是否需要保留该字段
* @param clearElementName 是否清除预留字段
* @return 操作的文本说明
*/
public String getStep(boolean clearElementName) {
return clearElementName ? step.replaceAll(ELEMENT_NAME, "") : step;
}
/**
* 用于将页面控件元素高亮显示
* @param element 当前指向的元素
*/
void elementHight(WebElement element) {
//获取当前指向的元素的style属性
String elementStyle = element.getAttribute("style");
// 控件高亮
((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('style',arguments[1])", element,
elementStyle + "background:yellow;solid:red;");
//解除高亮
((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('style',arguments[1])",
element, elementStyle);
}
}

View File

@ -14,7 +14,7 @@ import pres.auxiliary.work.selenium.element.Element;
* 定义了对控件进行点击操作相关的方法可通过该类对页面进行基本的点击操作
* </p>
* <p><b>编码时间</b>2019年8月29日下午3:24:34</p>
* <p><b>修改时间</b>2020年5月10日 下午3:42:36</p>
* <p><b>修改时间</b>2020年7月10日上午16:49:37</p>
*
* @author 彭宇琦
* @version Ver2.0
@ -55,8 +55,6 @@ public class ClickEvent extends AbstractEvent {
return false;
}
});
step = "鼠标左键点击“" + ELEMENT_NAME + "”元素";
}
/**
@ -82,8 +80,6 @@ public class ClickEvent extends AbstractEvent {
return false;
}
});
step = "鼠标左键双击“" + ELEMENT_NAME + "”元素";
}
/**
@ -108,8 +104,6 @@ public class ClickEvent extends AbstractEvent {
return false;
}
});
step = "鼠标右键点击“" + ELEMENT_NAME + "”元素";
}
/**
@ -128,7 +122,5 @@ public class ClickEvent extends AbstractEvent {
continue;
}
}
step = "鼠标左键连续" + clickCount + "次点击“" + ELEMENT_NAME + "”元素";
}
}

View File

@ -0,0 +1,23 @@
package pres.auxiliary.work.selenium.event;
import pres.auxiliary.work.selenium.element.Element;
/**
* <p><b>文件名</b>EventAction.java</p>
* <p><b>用途</b>
* 用于执行事件增强的方法方法中可通过{@link EventInformation}类对象回调事件的操作的步骤
* 以及传入到事件中的{@link Element}类对象
* </p>
* <p><b>编码时间</b>2020年7月10日下午3:40:13</p>
* <p><b>修改时间</b>2020年7月10日下午3:40:13</p>
* @author 彭宇琦
* @version Ver1.0
*
*/
public interface EventAction {
/**
* 事件增强的方法可通过形参回调事件的操作步骤以及传入到事件中的{@link Element}类对象
* @param name {@link EventInformation}类对象
*/
void action(EventInformation elemenetInformation);
}

View File

@ -0,0 +1,73 @@
package pres.auxiliary.work.selenium.event;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import pres.auxiliary.work.selenium.element.Element;
/**
* <p><b>文件名</b>EventInformation.java</p>
* <p><b>用途</b>
* 用于存储事件的信息
* </p>
* <p><b>编码时间</b>2020年7月10日下午3:47:58</p>
* <p><b>修改时间</b>2020年7月10日下午3:47:58</p>
* @author 彭宇琦
* @version Ver1.0
*
*/
public class EventInformation {
/**
* 存储事件操作的方法
*/
private Method method;
/**
* 传入到事件的参数
*/
private Object[] args;
/**
* 存储传入到方法中的元素类对象由args进行分离
*/
private ArrayList<Element> elementList = new ArrayList<>();
/**
* 构造对象
* @param method 事件方法的{@link Method}类对象
* @param args 传入事件方法的参数
*/
public EventInformation(Method method, Object[] args) {
super();
this.method = method;
this.args = args;
//提取Element类对象
getElement();
}
/**
* 返回事件操作方法类对象
* @return 事件的{@link Method}类对象
*/
public Method getMethod() {
return method;
}
/**
* 用于返回传入事件方法的参数
* @return 传入事件方法的参数
*/
public Object[] getParam() {
return args;
}
/**
* 用于将args中为Element类对象的参数进行转换并存储至elementList中
*/
private void getElement() {
Arrays.stream(args).forEach(arg -> {
if (arg instanceof Element) {
elementList.add((Element) arg);
}
});
}
}

View File

@ -0,0 +1,163 @@
package pres.auxiliary.work.selenium.event;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.regex.Pattern;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import pres.auxiliary.work.selenium.element.Element;
public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
/**
* 用于存储方法前置通知key表示方法名称匹配规则value表示调用的方法
*/
private LinkedHashMap<String, ArrayList<EventAction>> functionBeforeActionMap = new LinkedHashMap<>(16);
/**
* 用于存储元素前置通知key表示元素名称匹配规则value表示调用的方法
*/
private LinkedHashMap<String, ArrayList<EventAction>> elementBeforeActionMap = new LinkedHashMap<>(16);
/**
* 用于存储元素后置通知
*/
private LinkedHashMap<String, ArrayList<EventAction>> elementAfterActionMap = new LinkedHashMap<>(16);
/**
* 用于存储方法执行成功通知
*/
private LinkedHashMap<String, ArrayList<EventAction>> functionSuccessActionMap = new LinkedHashMap<>(16);
/**
* 用于存储方法执行失败通知
*/
private LinkedHashMap<String, ArrayList<EventAction>> functionFailActionMap = new LinkedHashMap<>(16);
/**
* 用于存储方法最终通知
*/
private LinkedHashMap<String, ArrayList<EventAction>> functionFinalActionMap = new LinkedHashMap<>(16);
/**
* 事件类对象
*/
private T target;
/**
* 构造代理类
* @param target {@link AbstractEvent}类或其子类
*/
public EventProxy(T target) {
this.target = target;
}
/**
* 创建{@link AbstractEvent}类或其子类的代理类对象通过该类可调用
* {@link AbstractEvent}类或子类的所有方法
* @return {@link AbstractEvent}类或子类的代理类对象
*/
@SuppressWarnings("unchecked")
public T getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return (T) en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//构造事件信息类对象
EventInformation eventInformation = new EventInformation(method, args);
//按照方法名或元素名匹配到相应的通知后运行通知若通知运行出现异常则直接跳过
//运行方法前置通知
functionBeforeActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
//运行元素前置通知
Arrays.stream(args).filter(arg -> arg instanceof Element).forEach(arg -> {
elementBeforeActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(((Element) arg).getName()).matches()) {
value.forEach(action -> {
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
});
//执行目标对象的方法
try {
Object returnValue = method.invoke(target, args);
//运行方法成功执行通知
functionSuccessActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
return returnValue;
} catch (Exception exception) {
//运行方法失败执行通知
functionFailActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
throw exception;
} finally {
//运行元素后置通知
Arrays.stream(args).filter(arg -> arg instanceof Element).forEach(arg -> {
elementAfterActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(((Element) arg).getName()).matches()) {
value.forEach(action -> {
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
});
//运行方法最终通知
functionFinalActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
}
}
}

View File

@ -145,7 +145,7 @@ public class JsEvent extends AbstractEvent {
// 获取新添加元素的xpath
String xpath = addElement(element, elementName);
// 查找新添加的元素由于是新添加的元素肯定能查找到故无需编写等待
Element newElement = new Element(driver, ElementType.COMMON_ELEMENT, By.xpath(xpath));
Element newElement = new Element(driver, ElementType.COMMON_ELEMENT, By.xpath(xpath), "TeamElement");
// 获取元素的所有属性
JSONArray attributes = elementJson.getJSONArray("attributes");

View File

@ -21,10 +21,10 @@ import pres.auxiliary.work.selenium.tool.Screenshot;
* <p><b>文件名</b>TextEvent.java</p>
* <p><b>用途</b>定义了对控件文本操作相关的方法可通过该类对页面进行对控件输入文本获取等操作</p>
* <p><b>编码时间</b>2019年9月6日上午9:28:59</p>
* <p><b>修改时间</b>2019年11月29日上午9:53:37</p>
* <p><b>修改时间</b>2020年7月10日上午16:49:37</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
* @since JDK 8
*
*/
public class TextEvent extends AbstractEvent {
@ -62,9 +62,6 @@ public class TextEvent extends AbstractEvent {
}
});
//记录操作
step = "清空“" + ELEMENT_NAME + "”元素内的文本";
return text;
}
@ -78,10 +75,6 @@ public class TextEvent extends AbstractEvent {
//等待元素中attributeName指向的属性内容出现
wait.until(ExpectedConditions.attributeToBeNotEmpty(element.getWebElement(), attributeName));
//记录操作
step = "获取“" + ELEMENT_NAME + "”元素的" + attributeName +"属性的内容";
//对元素进行操作若元素过期则重新获取
return wait.until(driver -> {
try {
@ -99,9 +92,6 @@ public class TextEvent extends AbstractEvent {
* @return 对应元素中的文本内容
*/
public String getText(Element element) {
//记录操作
step = "获取“" + ELEMENT_NAME + "”元素内的文本";
//对元素进行操作若元素过期则重新获取
return wait.until(driver -> {
try {
@ -131,9 +121,6 @@ public class TextEvent extends AbstractEvent {
}
});
//记录操作
step = "获取“" + ELEMENT_NAME + "”元素内的文本";
return text;
}
@ -249,8 +236,6 @@ public class TextEvent extends AbstractEvent {
* @return 上传的文件路径
*/
public String updataFile(Element element, File updataFile) {
//记录操作
step = "向“" + ELEMENT_NAME + "”元素中的上传文件";
return input(element, updataFile.getAbsolutePath());
}