diff --git a/Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe b/Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe
new file mode 100644
index 0000000..4850c8d
Binary files /dev/null and b/Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe differ
diff --git a/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java
index c436379..54e081b 100644
--- a/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java
+++ b/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java
@@ -47,4 +47,12 @@ public abstract class AbstractEvent {
public void setWaitTime(long waitTime) {
wait.withTimeout(Duration.ofSeconds(waitTime));
}
+
+ /**
+ * 用于返回存储的{@link WebDriver}类对象
+ * @return{@link WebDriver}类对象
+ */
+ public WebDriver getDriver() {
+ return driver;
+ }
}
diff --git a/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java b/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java
index df15359..56f2c48 100644
--- a/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java
+++ b/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java
@@ -41,7 +41,7 @@ public class EventInformation {
this.method = method;
this.args = args;
//提取Element类对象
- getElement();
+ toElement();
}
/**
@@ -60,10 +60,18 @@ public class EventInformation {
return args;
}
+ /**
+ * 用于返回传入到方法中{@link Element}类对象集合
+ * @return {@link Element}类对象集合
+ */
+ public ArrayList getElement() {
+ return elementList;
+ }
+
/**
* 用于将args中为Element类对象的参数进行转换并存储至elementList中
*/
- private void getElement() {
+ private void toElement() {
Arrays.stream(args).forEach(arg -> {
if (arg instanceof Element) {
elementList.add((Element) arg);
diff --git a/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java b/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java
index 2a65625..d097dca 100644
--- a/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java
+++ b/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java
@@ -6,12 +6,52 @@ import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.regex.Pattern;
+import org.openqa.selenium.WebDriver;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
+import pres.auxiliary.work.selenium.brower.ChromeBrower;
import pres.auxiliary.work.selenium.element.Element;
+/**
+ * 文件名:EventProxy.java
+ * 用途:
+ * 用于对事件类进行代理,使其能在对应的事件方法执行前后能执行指定方法,以增强事件的执行。
+ * 类中提供6种增强方法的方式,其名称与执行顺序为:方法前置通知、元素前置通知、方法成功/失败通知(两种)、
+ * 元素后置通知、方法最终通知,解释如下:
+ *
+ * - 方法前置通知:根据方法名,匹配到相应的方法后,在执行事件前执行的方法
+ * - 元素前置通知:根据元素名称,匹配到传入方法的元素后,在执行事件前执行的方法
+ * - 方法成功通知:根据方法名,匹配到相应的方法后,在事件成功执行(未抛出异常)后执行的方法
+ * - 方法失败通知:根据方法名,匹配到相应的方法后,在事件失败执行(抛出异常)后执行的方法
+ * - 元素后置通知:根据元素名称,匹配到传入方法的元素后,在执行事件后(无论是否抛出异常)执行的方法
+ * - 方法最终通知:根据方法名,匹配到相应的方法后,在执行事件后(无论是否抛出异常)执行的方法
+ *
+ * 可参考以下示例:
+ *
+ * 假设存在元素xpah:元素1“//*[text()='登录']”、元素2“//*[@name='account']”、元素3“//*[@name='password']”,
+ * 在点击元素1前,需要先在元素2和元素3中分别输入“admin”、“123456”,并且在此前定义了{@link ChromeBrower}浏览器对象,变量名为
+ * chrome,此时,可以将代码写作
+ *
{@code
+ * EventProxy clickEventProxy = new EventProxy(new ClickEvent(chrome.getDriver()));
+ *
+ * clickProxy.addAcion(ActionType.ELEMENT_BEFORE, ".*登录.*", (info) -> {
+ * TextEvent text = inputProxy.getProxyInstance();
+ * text.input(by.getElement("//*[@name='account']"), "admin");
+ * text.input(by.getElement("//*[@name='password']"), "1111111");
+ * });
+ * clickEventProxy.getProxyInstance().click(new CommnBy(chrome).getElement("//*[text()='登录']"));
+ *
+ *
+ *
+ *
+ * 编码时间:2020年7月12日 下午1:35:22
+ * 修改时间:2020年7月12日 下午1:35:22
+ * @author 彭宇琦
+ * @version Ver1.0
+ * @since JDK 12
+ */
public class EventProxy implements MethodInterceptor {
/**
* 用于存储方法前置通知,key表示方法名称匹配规则,value表示调用的方法
@@ -42,6 +82,7 @@ public class EventProxy implements MethodInterceptor {
* 事件类对象
*/
private T target;
+ private WebDriver driver;
/**
* 构造代理类
@@ -49,6 +90,7 @@ public class EventProxy implements MethodInterceptor {
*/
public EventProxy(T target) {
this.target = target;
+ driver = ((AbstractEvent) target).getDriver();
}
/**
@@ -58,14 +100,53 @@ public class EventProxy implements MethodInterceptor {
*/
@SuppressWarnings("unchecked")
public T getProxyInstance(){
- //1.工具类
+ //工具类
Enhancer en = new Enhancer();
- //2.设置父类
+ //设置父类
en.setSuperclass(target.getClass());
- //3.设置回调函数
+ //设置回调函数
en.setCallback(this);
- //4.创建子类(代理对象)
- return (T) en.create();
+ //创建子类(代理对象)
+ return (T) en.create(new Class[] {WebDriver.class}, new Object[] {driver});
+// return (T) en.create();
+ }
+
+ /**
+ * 根据相应的执行的方法类型,添加指定的名称匹配规则及执行方法
+ * @param actionType 通知类型枚举类{@link ActionType}
+ * @param regex 名称匹配规则,元素名称或者方法名称,规则为正则表达式
+ * @param action 需要执行的方法
+ */
+ public void addAcion(ActionType actionType, String regex, EventAction action) {
+ //指向需要添加通知的map
+ LinkedHashMap> actionMap = null;
+ //根据不同类型的通知,将actionMap指向相应的map
+ switch (actionType) {
+ case FUNCTION_BEFORE:
+ actionMap = functionBeforeActionMap;
+ break;
+ case ELEMENT_BEFORE:
+ actionMap = elementBeforeActionMap;
+ break;
+ case FUNCTION_SUCCESS_AFTER:
+ actionMap = functionSuccessActionMap;
+ break;
+ case FUNCTION_FAIL_AFTER:
+ actionMap = functionFailActionMap;
+ break;
+ case ELEMENT_AFTER:
+ actionMap = elementAfterActionMap;
+ break;
+ case FUNCTION_FINAL:
+ actionMap = functionFinalActionMap;
+ break;
+ default:
+ break;
+ }
+
+ //执行添加通知的方法
+ mapAddAction(regex, action, actionMap);
+
}
@Override
@@ -75,8 +156,38 @@ public class EventProxy implements MethodInterceptor {
//按照方法名或元素名,匹配到相应的通知后,运行通知,若通知运行出现异常,则直接跳过
//运行方法前置通知
- functionBeforeActionMap.forEach((key, value) -> {
- if (Pattern.compile(key).matcher(method.getName()).matches()) {
+ runFuntionAction(eventInformation, functionBeforeActionMap);
+
+ //运行元素前置通知
+ runElementAction(eventInformation, elementBeforeActionMap);
+
+ //执行目标对象的方法
+ try {
+ Object returnValue = method.invoke(target, args);
+ //运行方法成功执行通知
+ runFuntionAction(eventInformation, functionSuccessActionMap);
+ return returnValue;
+ } catch (Exception exception) {
+ //运行方法失败执行通知
+ runFuntionAction(eventInformation, functionFailActionMap);
+ throw exception;
+ } finally {
+ //运行元素后置通知
+ runElementAction(eventInformation, elementAfterActionMap);
+
+ //运行方法最终通知
+ runFuntionAction(eventInformation, functionFinalActionMap);
+ }
+ }
+
+ /**
+ * 运行方法通知
+ * @param eventInformation 事件信息类对象
+ * @param actionMap 需要执行的通知
+ */
+ private void runFuntionAction(EventInformation eventInformation, LinkedHashMap> actionMap) {
+ actionMap.forEach((key, value) -> {
+ if (Pattern.compile(key).matcher(eventInformation.getMethod().getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
@@ -86,10 +197,16 @@ public class EventProxy implements MethodInterceptor {
});
}
});
-
- //运行元素前置通知
- Arrays.stream(args).filter(arg -> arg instanceof Element).forEach(arg -> {
- elementBeforeActionMap.forEach((key, value) -> {
+ }
+
+ /**
+ * 执行元素通知
+ * @param eventInformation 事件类对象
+ * @param actionMap 需要执行的通知
+ */
+ private void runElementAction(EventInformation eventInformation, LinkedHashMap> actionMap) {
+ Arrays.stream(eventInformation.getParam()).filter(arg -> arg instanceof Element).forEach(arg -> {
+ actionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(((Element) arg).getName()).matches()) {
value.forEach(action -> {
try {
@@ -100,64 +217,57 @@ public class EventProxy implements MethodInterceptor {
}
});
});
-
- //执行目标对象的方法
- 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) {
- }
- });
- }
- });
+ }
+
+ /**
+ * 用于向相应的通知map中添加通知
+ * @param regex 匹配规则
+ * @param action 通知
+ * @param actionMap 存储通知的map
+ */
+ private void mapAddAction(String regex, EventAction action, LinkedHashMap> actionMap) {
+ //判断actionMap中是否存在regex,若不存在,则将regex加入到actionMap,并构造ArrayList类
+ if (!actionMap.containsKey(regex)) {
+ actionMap.put(regex, new ArrayList());
}
+
+ //在相应的regex中添加action
+ actionMap.get(regex).add(action);
+ }
+
+ /**
+ * 文件名:EventProxy.java
+ * 用途:用于标记通知的类型
+ * 编码时间:2020年7月12日 上午11:24:57
+ * 修改时间:2020年7月12日 上午11:24:57
+ * @author 彭宇琦
+ * @version Ver1.0
+ * @since JDK 8
+ */
+ public enum ActionType {
+ /**
+ * 表示方法前置通知
+ */
+ FUNCTION_BEFORE,
+ /**
+ * 表示元素前置通知
+ */
+ ELEMENT_BEFORE,
+ /**
+ * 表示方法执行成功通知
+ */
+ FUNCTION_SUCCESS_AFTER,
+ /**
+ * 表示方法执行失败通知
+ */
+ FUNCTION_FAIL_AFTER,
+ /**
+ * 表示元素后置通知
+ */
+ ELEMENT_AFTER,
+ /**
+ * 表示方法最终通知
+ */
+ FUNCTION_FINAL;
}
}
diff --git a/src/test/java/pres/auxiliary/work/selenium/event/EventProxyTest.java b/src/test/java/pres/auxiliary/work/selenium/event/EventProxyTest.java
new file mode 100644
index 0000000..f4215dd
--- /dev/null
+++ b/src/test/java/pres/auxiliary/work/selenium/event/EventProxyTest.java
@@ -0,0 +1,59 @@
+package pres.auxiliary.work.selenium.event;
+
+import java.io.File;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import pres.auxiliary.work.selenium.brower.ChromeBrower;
+import pres.auxiliary.work.selenium.brower.ChromeBrower.ChromeOptionType;
+import pres.auxiliary.work.selenium.element.CommonBy;
+import pres.auxiliary.work.selenium.event.EventProxy.ActionType;
+
+public class EventProxyTest {
+ EventProxy clickProxy;
+ EventProxy inputProxy;
+ ChromeBrower chrome;
+ CommonBy by;
+
+ @BeforeClass
+ public void init() {
+ chrome = new ChromeBrower(new File("Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe"));
+ chrome.addConfig(ChromeOptionType.CONTRAL_OPEN_BROWER, "127.0.0.1:9222");
+ clickProxy = new EventProxy<>(new ClickEvent(chrome.getDriver()));
+ inputProxy = new EventProxy<>(new TextEvent(chrome.getDriver()));
+ by = new CommonBy(chrome);
+ }
+
+ @AfterClass
+ public void showResult() {
+ ClickEvent click = clickProxy.getProxyInstance();
+ click.doubleClick(by.getElement("//*[text()='登录']"));
+ }
+
+ @Test
+ public void addAcionTest() {
+ TextEvent textEvent = new TextEvent(chrome.getDriver());
+ textEvent.input(by.getElement("//*[@name='account']"), "admin");
+ textEvent.input(by.getElement("//*[@name='password']"), "1111111");
+
+ inputProxy.addAcion(ActionType.FUNCTION_BEFORE, ".*input.*", (info) -> {
+ inputProxy.getProxyInstance().clear(info.getElement().get(0));
+ });
+
+ clickProxy.addAcion(ActionType.ELEMENT_BEFORE, ".*登录.*", (info) -> {
+ TextEvent text = inputProxy.getProxyInstance();
+ text.input(by.getElement("//*[@name='account']"), "admin");
+ text.input(by.getElement("//*[@name='password']"), "1111111");
+ });
+
+ clickProxy.addAcion(ActionType.ELEMENT_AFTER, ".*登录.*", (info) -> {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ }
+ by.alertAccept();
+ });
+ }
+}