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 93f7c16..02c1872 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java @@ -1,9 +1,11 @@ package pres.auxiliary.work.selenium.event; import java.time.Duration; +import java.util.Arrays; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.WebDriverWait; import pres.auxiliary.work.selenium.brower.AbstractBrower; @@ -82,18 +84,59 @@ public abstract class AbstractEvent { public String getResultText() { return resultText; } + + /** + * 用于返回当前指向的{@link AbstractBrower}类对象 + * @return {@link AbstractBrower}类对象 + */ + protected AbstractBrower getBrower() { + return brower; + } /** * 用于通过js脚本,将页面定位元素所在位置 * @param element {@link Element}对象 */ - protected void locationElement(Element element) { + protected void locationElement(WebElement element) { //若抛出NoSuchElementException异常,则将异常抛出,其他异常将不做处理 try { - ((JavascriptExecutor) brower.getDriver()).executeScript(LOCATION_ELEMENT_JS, element.getWebElement()); - } catch (NoSuchElementException e) { - throw e; + ((JavascriptExecutor) brower.getDriver()).executeScript(LOCATION_ELEMENT_JS, element); } catch (Exception e) { + throw e; } } + + /** + * 用于判断元素是否存在 + * @param element {@link Element}对象 + * @return 当前指定的元素是否存在 + */ + protected boolean isExistElement(Element element) { + //判断元素是否存在,若返回元素时抛出异常,则返回false + try { + element.getWebElement(); + return true; + } catch (NoSuchElementException e) { + return false; + } + } + + /** + * 用于将字符串数组内容转成字符串形式返回 + * @param keys 字符串数组 + * @return 数组文本 + */ + protected String arrayToString(String...keys) { + if (keys == null || keys.length == 0) { + return "[]"; + } + + StringBuilder text = new StringBuilder("["); + Arrays.asList(keys).forEach(key -> { + text.append(key); + text.append(", "); + }); + + return text.substring(0, text.lastIndexOf(", ")); + } } diff --git a/src/main/java/pres/auxiliary/work/selenium/event/AssertEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/AssertEvent.java new file mode 100644 index 0000000..462ab51 --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/event/AssertEvent.java @@ -0,0 +1,386 @@ +package pres.auxiliary.work.selenium.event; + +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.TimeoutException; + +import pres.auxiliary.work.selenium.brower.AbstractBrower; +import pres.auxiliary.work.selenium.element.AbstractBy.Element; + +/** + *
+ * 文件名:AssertEvent.java + *
+ *+ * 用途: 定义了对控件进行断言的方法,可通过该类,对页面元素进行断言操作。类中的所有断言均以 + * boolean类型进行返回,可通过类中提供的方法指定当断言失败时,是否抛出一个异常,默认 不抛出异常。 + *
+ *+ * 编码时间:2020年10月20日上午7:48:05 + *
+ *+ * 修改时间:2020年10月20日上午7:48:05 + *
+ * + * @author 彭宇琦 + * @version Ver1.0 + * + */ +public class AssertEvent extends AbstractEvent { + /** + * 控制当断言失败时,是否抛出一个异常 + */ + boolean isThrowException = false; + /** + * 定义文本事件,用于对元素的文本进行获取 + */ + TextEvent textEvent; + + /** + * 构造对象 + * + * @param brower 浏览器{@link AbstractBrower}类对象 + */ + public AssertEvent(AbstractBrower brower) { + super(brower); + // 初始化文本事件 + textEvent = new TextEvent(brower); + } + + /** + * 设置当前断言失败时,是否抛出一个异常,默认为false,即不抛出异常 + * + * @param isThrowException 是否抛出异常 + */ + public void setThrowException(boolean isThrowException) { + this.isThrowException = isThrowException; + } + + /** + *+ * 断言元素的文本内容中包含指定的关键词。可设置元素的文本内容是否需要判断传入的所有关键词,即 + *
+ * 例如,假设元素中存在文本“你好,世界!”,则 + *
+ * 注意:若不传入关键词,或关键词为null时,则返回true + *
+ * + * @param element {@link Element}对象 + * @param isJudgeAllKey 是否需要完全判断所有关键词 + * @param keys 关键词组 + * @return 断言结果 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 + */ + public boolean assertTextContainKey(Element element, boolean isJudgeAllKey, String... keys) { + //判断是否传入关键词 + boolean result = true; + if (keys != null && keys.length != 0) { + result = judgetText(textEvent.getText(element), isJudgeAllKey, false, keys); + } + + logText = "断言“" + element.getElementData().getName() + "”元素的文本内容包含" + + (isJudgeAllKey ? "所有" : "部分") + "关键词" + arrayToString(keys); + resultText = String.valueOf(result); + + return result; + } + + /** + *+ * 断言元素的文本内容中不包含指定的关键词。可设置元素的文本内容是否需要判断传入的所有关键词,即 + *
+ * 例如,假设元素中存在文本“你好,世界!”,则 + *
+ * 注意:若不传入关键词,或关键词为null时,则返回true + *
+ * + * @param element {@link Element}对象 + * @param isJudgeAllKey 是否需要完全判断所有关键词 + * @param keys 关键词组 + * @return 断言结果 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 + */ + public boolean assertTextNotContainKey(Element element, boolean isJudgeAllKey, String... keys) { + //判断是否传入关键词 + boolean result = true; + if (keys != null && keys.length != 0) { + result = judgetText(textEvent.getText(element), isJudgeAllKey, true, keys); + } + + logText = "断言“" + element.getElementData().getName() + "”元素的文本内容不包含" + + (isJudgeAllKey ? "所有" : "部分") + "关键词" + arrayToString(keys); + resultText = String.valueOf(result); + + return result; + } + + /** + * 断言元素的指定属性是否包含指定的关键词。可设置元素的文本内容是否需要判断传入的所有关键词, + * 具体参数介绍可参考{@link #assertTextContainKey(Element, boolean, String...)}方法 + * + * @param element {@link Element}对象 + * @param attributeName 属性名称 + * @param isJudgeAllKey 是否需要完全判断所有关键词 + * @param keys 关键词组 + * @return 断言结果 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 + */ + public boolean assertAttributeContainKey(Element element, String attributeName, boolean isJudgeAllKey, + String... keys) { + //判断是否传入关键词 + boolean result = true; + if (keys != null && keys.length != 0) { + result = judgetText(textEvent.getAttributeValue(element, attributeName), isJudgeAllKey, false, keys); + } + + logText = "断言“" + element.getElementData().getName() + "”元素的“" + attributeName + + "”属性值包含" + + (isJudgeAllKey ? "所有" : "部分") + "关键词" + arrayToString(keys); + resultText = String.valueOf(result); + + return result; + } + + /** + * 断言元素的文本内容中不包含指定的关键词。可设置元素的文本内容是否需要判断传入的所有关键词, + * 具体参数介绍可参考{@link #assertTextNotContainKey(Element, boolean, String...)}方法 + * + * @param element {@link Element}对象 + * @param attributeName 属性名称 + * @param isJudgeAllKey 是否需要完全判断所有关键词 + * @param keys 关键词组 + * @return 断言结果 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 + */ + public boolean assertAttributeNotContainKey(Element element, String attributeName, boolean isJudgeAllKey, + String... keys) { + //判断是否传入关键词 + boolean result = true; + if (keys != null && keys.length != 0) { + result = judgetText(textEvent.getAttributeValue(element, attributeName), isJudgeAllKey, true, keys); + } + + logText = "断言“" + element.getElementData().getName() + "”元素的“" + attributeName + + "”属性值不包含" + + (isJudgeAllKey ? "所有" : "部分") + "关键词" + arrayToString(keys); + resultText = String.valueOf(result); + + return result; + } + + /** + * 用于断言元素的内容与预期的文本一致 + * @param element {@link Element}对象 + * @param text 需要判断的文本内容 + * @return 断言结果 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 + */ + public boolean assertEqualsText(Element element, String text) { + //判断是否传入关键词 + text = text == null ? "" : text; + + boolean result = judgetText(textEvent.getText(element), true, false, text); + + logText = "断言“" + element.getElementData().getName() + "”元素的文本内容为“" + text + "”"; + resultText = String.valueOf(result); + + return result; + } + + /** + * 用于断言元素的内容与传入的文本不一致 + * @param element {@link Element}对象 + * @param text 需要判断的文本内容 + * @return 断言结果 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 + */ + public boolean assertNotEqualsText(Element element, String text) { + //判断是否传入关键词 + text = text == null ? "" : text; + + boolean result = judgetText(textEvent.getText(element), true, true, text); + + logText = "断言“" + element.getElementData().getName() + "”元素的文本内容不为“" + text + "”"; + resultText = String.valueOf(result); + + return result; + } + + /** + * 断言元素存在 + * @param element {@link Element}对象 + * @return 断言结果 + */ + public boolean assertExistElement(Element element) { + boolean result = isExistElement(element); + + logText = "断言“" + element.getElementData().getName() + "”元素存在"; + resultText = String.valueOf(result); + + return result; + } + + /** + * 断言元素不存在 + * @param element {@link Element}对象 + * @return 断言结果 + */ + public boolean assertNotExistElement(Element element) { + boolean result = !isExistElement(element); + + logText = "断言“" + element.getElementData().getName() + "”元素不存在"; + resultText = String.valueOf(result); + + return result; + } + + /** + * 断言元素中的数字内容与指定的数字按照{@link CompareNumberType}指定的比较类型进行比较。若断言的 + * 元素文本内容为非数字字符时,则直接断言失败 + * + * @param element {@link Element}对象 + * @param compareNumberType {@link CompareNumberType}枚举类 + * @param compareNumber 预期数字 + * @return 断言结果 + */ + public boolean assertNumber(Element element, CompareNumberType compareNumberType, double compareNumber) { + logText = "断言“" + element.getElementData().getName() + "”元素数字内容" + compareNumberType.getLogText() + compareNumber; + boolean result = false; + + try { + double elementNumber = Double.valueOf(textEvent.getText(element)); + //根据枚举内容,返回对比结果 + switch (compareNumberType) { + case EQUAL: + result = elementNumber == compareNumber; + break; + case GREATER: + result = elementNumber > compareNumber; + break; + case LESS: + result = elementNumber < compareNumber; + break; + case GREATER_OR_EQUAL: + result = elementNumber >= compareNumber; + break; + case LESS_OR_EQUAL: + result = elementNumber <= compareNumber; + break; + default: + break; + } + } catch (NumberFormatException e) { + } + + resultText = String.valueOf(result); + return result; + } + + /** + * 用于对文本信息与关键词进行对比 + * @param text 需要判断的文本 + * @param isJudgeAllKey 是否需要完全判断关键词 + * @param isNot 是否为不包含关键词 + * @param keys 关键词组 + * @return 断言结果 + */ + private boolean judgetText(String text, boolean isJudgeAllKey, boolean isNot, String... keys) { + boolean result = false; + // 循环,判断keys中所有的内容 + for (String key : keys) { + // 判断当前关键词是否包含于text中 + if (text.contains(key)) { + // 若包含文本且不需要关键词完全包含,且判断条件为需要包含文本,则记录当前结果为True,并结束循环 + if (!isJudgeAllKey && !isNot) { + result = true; + break; + } else if (isJudgeAllKey && isNot) { + // 若包含文本且需要关键词完全包含,且判断条件为不需要包含文本,则记录当前结果为False,并结束循环 + result = false; + break; + } else if (!isJudgeAllKey && isNot) { + result = false; + continue; + } else { + result = true; + continue; + } + } else { + // 若不包含且需要关键词完全包含,且判断条件为需要包含文本,则记录当前结果为False,并结束循环 + if (isJudgeAllKey && !isNot) { + result = false; + break; + } else if (!isJudgeAllKey && isNot) { + // 若包含文本且需要关键词完全包含,且判断条件为不需要包含文本,则记录当前结果为False,并结束循环 + result = true; + break; + } else if (isJudgeAllKey && isNot) { + result = true; + continue; + } else { + result = false; + continue; + } + } + } + + return result; + } +} diff --git a/src/main/java/pres/auxiliary/work/selenium/event/ClickEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/ClickEvent.java index 4ed5d6e..b86f44f 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/ClickEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/ClickEvent.java @@ -3,6 +3,7 @@ package pres.auxiliary.work.selenium.event; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import pres.auxiliary.work.selenium.brower.AbstractBrower; @@ -35,17 +36,20 @@ public class ClickEvent extends AbstractEvent { * 鼠标左键单击事件 * * @param element {@link Element}对象 - * @throws NoSuchElementException 元素不存在或下标有误时抛出的异常 - * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public void click(Element element) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); //在指定的时间内判断是否能进行点击,若抛出StaleElementReferenceException异常,则重新获取元素 wait.until((driver) -> { try { - element.getWebElement().click(); + WebElement we = element.getWebElement(); + //定位到元素上 + locationElement(we); + we.click(); return true; } catch (StaleElementReferenceException e) { element.againFindElement(); @@ -61,21 +65,24 @@ public class ClickEvent extends AbstractEvent { * 鼠标左键双击事件 * * @param element {@link Element}对象 - * @throws NoSuchElementException 元素不存在或下标有误时抛出的异常 * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public void doubleClick(Element element) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); - + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); + //在指定的时间内判断是否能进行点击,若抛出StaleElementReferenceException异常,则重新获取元素 wait.until((driver) -> { try { - new Actions(driver).doubleClick(element.getWebElement()).perform(); + WebElement we = element.getWebElement(); + //定位到元素上 + locationElement(we); + new Actions(driver).doubleClick(we).perform(); return true; } catch (StaleElementReferenceException e) { element.againFindElement(); - throw e; + throw e ; } }); @@ -86,17 +93,20 @@ public class ClickEvent extends AbstractEvent { /** * 鼠标右键点击事件 * @param element {@link Element}对象 - * @throws NoSuchElementException 元素不存在或下标有误时抛出的异常 * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public void rightClick(Element element) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); //在指定的时间内判断是否能进行点击,若抛出StaleElementReferenceException异常,则重新获取元素 wait.until((driver) -> { try { - new Actions(driver).contextClick(element.getWebElement()).perform(); + WebElement we = element.getWebElement(); + //定位到元素上 + locationElement(we); + new Actions(driver).contextClick(we).perform(); return true; } catch (StaleElementReferenceException e) { element.againFindElement(); @@ -113,8 +123,8 @@ public class ClickEvent extends AbstractEvent { * @param element {@link Element}对象 * @param clickCount 点击次数 * @param sleepInMillis 操作时间间隔,单位为毫秒 - * @throws NoSuchElementException 元素不存在或下标有误时抛出的异常 * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public void continuousClick(Element element, int clickCount, long sleepInMillis) { for(int i = 0; i < clickCount; i++) { diff --git a/src/main/java/pres/auxiliary/work/selenium/event/CompareNumberType.java b/src/main/java/pres/auxiliary/work/selenium/event/CompareNumberType.java new file mode 100644 index 0000000..32b2af0 --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/event/CompareNumberType.java @@ -0,0 +1,56 @@ +package pres.auxiliary.work.selenium.event; + +/** + *文件名:CompareNumberType.java
+ *用途: + * 用于枚举对数字比较的方式 + *
+ *编码时间:2020年10月20日下午7:00:14
+ *修改时间:2020年10月20日下午7:00:14
+ * @author 彭宇琦 + * @version Ver1.0 + * + */ +public enum CompareNumberType { + /** + * 等于 + */ + EQUAL("等于"), + /** + * 大于 + */ + GREATER("大于"), + /** + * 小于 + */ + LESS("小于"), + /** + * 大于等于 + */ + GREATER_OR_EQUAL("大于等于"), + /** + * 小于等于 + */ + LESS_OR_EQUAL("小于等于"); + + /** + * 日志文本 + */ + String logText; + + /** + * 初始化枚举值 + * @param logText 枚举值 + */ + private CompareNumberType(String logText) { + this.logText = logText; + } + + /** + * 返回枚举值 + * @return 枚举值 + */ + public String getLogText() { + return logText; + } +} 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 a453b59..bd2ae79 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,13 @@ 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.AbstractBrower; import pres.auxiliary.work.selenium.brower.ChromeBrower; +import pres.auxiliary.work.selenium.element.AbstractBy.Element; /** *文件名:EventProxy.java
@@ -28,11 +29,12 @@ import pres.auxiliary.work.selenium.brower.ChromeBrower; *
* 假设存在元素xpah:元素1“//*[text()='登录']”、元素2“//*[@name='account']”、元素3“//*[@name='password']”,
* 在点击元素1前,需要先在元素2和元素3中分别输入“admin”、“123456”,并且在此前定义了{@link ChromeBrower}浏览器对象,变量名为
* chrome,此时,可以将代码写作
- *
{@code + ** - * @param element 元素 - * @return 元素的信息 + * @param element {@link Element}对象 + * @return 被删除的元素信息 + * @throws TimeoutException 元素无法操作时抛出的异常 */ public JSONObject deleteElement(Element element) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); - + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); + //获取元素信息 JSONObject json = getElementInfromation(wait.until(driver -> { try { @@ -201,6 +210,7 @@ public class JsEvent extends AbstractEvent { * @param script js脚本 * @param args 传入的参数 * @return 执行结果 + * @throws TimeoutException 元素无法操作时抛出的异常 */ public Object runScript(String script, Object... args) { logText = "执行脚本:" + script; @@ -230,8 +240,9 @@ public class JsEvent extends AbstractEvent { * } * * - * @param element 元素 + * @param element {@link Element}对象 * @return 元素属性的信息,以json的形式返回 + * @throws TimeoutException 元素无法操作时抛出的异常 */ @SuppressWarnings("unchecked") private JSONObject getElementInfromation(WebElement element) { diff --git a/src/main/java/pres/auxiliary/work/selenium/event/TextEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/TextEvent.java index 33530ca..ca650fd 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/TextEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/TextEvent.java @@ -48,10 +48,13 @@ public class TextEvent extends AbstractEvent { * 文本 * @param element {@link Element}对象 * @return 被清空的文本内容 - * @throws NoSuchElementException 元素不存在或下标有误时抛出的异常 * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String clear(Element element) { + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); + //由于需要存储步骤,若直接调用getText方法进行返回时,其会更改存储的step,为保证step正确,故存储返回值进行返回 resultText = getText(element); //由于在获取元素时,已对元素进行相应操作等待,故此处将不再重新获取 @@ -66,17 +69,20 @@ public class TextEvent extends AbstractEvent { * @param element {@link Element}对象 * @param attributeName 属性名称 * @return 对应属性的值 - * @throws NoSuchElementException 元素不存在或下标有误时抛出的异常 * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String getAttributeValue(Element element, String attributeName) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); //在指定的时间内判断是否能进行操作,若抛出StaleElementReferenceException异常,则重新获取元素 resultText = wait.until((driver) -> { try { - return element.getWebElement().getAttribute(attributeName); + WebElement we = element.getWebElement(); + //定位到元素上 + locationElement(we); + return we.getAttribute(attributeName); } catch (StaleElementReferenceException e) { element.againFindElement(); throw e; @@ -91,18 +97,20 @@ public class TextEvent extends AbstractEvent { * 用于获取相应元素中的文本内容 * @param element {@link Element}对象 * @return 对应元素中的文本内容 - * @throws NoSuchElementException 元素不存在或下标有误时抛出的异常 * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String getText(Element element) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); //在指定的时间内判断是否能进行操作,若抛出StaleElementReferenceException异常,则重新获取元素 resultText = wait.until((driver) -> { try { - WebElement webElement = element.getWebElement(); - return "input".equalsIgnoreCase(webElement.getTagName()) ? webElement.getAttribute("value") : webElement.getText(); + WebElement we = element.getWebElement(); + //定位到元素上 + locationElement(we); + return "input".equalsIgnoreCase(we.getTagName()) ? we.getAttribute("value") : we.getText(); } catch (StaleElementReferenceException e) { element.againFindElement(); throw e; @@ -118,15 +126,20 @@ public class TextEvent extends AbstractEvent { * @param element {@link Element}对象 * @param text 需要输入到控件中的 * @return 在控件中输入的内容 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String input(Element element, String text) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); //在指定的时间内判断是否能进行操作,若抛出StaleElementReferenceException异常,则重新获取元素 wait.until((driver) -> { try { - element.getWebElement().sendKeys(text); + WebElement we = element.getWebElement(); + //定位到元素上 + locationElement(we); + we.sendKeys(text); return true; } catch (StaleElementReferenceException e) { element.againFindElement(); @@ -148,15 +161,20 @@ public class TextEvent extends AbstractEvent { * @param element {@link Element}对象 * @param keys 需要传入的按键,可传入{@link Keys}枚举类或字符串,若传入字符串,则只取字符串中第一个字母 * @return 发送按键组合,每个按键间用“ + ”字符串连接 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String keyToSend(Element element, CharSequence... keys) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); //在指定的时间内判断是否能进行操作,若抛出StaleElementReferenceException异常,则重新获取元素 wait.until((driver) -> { try { - element.getWebElement().sendKeys(keys); + WebElement we = element.getWebElement(); + //定位到元素上 + locationElement(we); + we.sendKeys(keys); return true; } catch (StaleElementReferenceException e) { element.againFindElement(); @@ -178,7 +196,7 @@ public class TextEvent extends AbstractEvent { }); //删除最后多余的符号 - resultText = textBul.substring(0, textBul.indexOf(" + ")); + resultText = textBul.substring(0, textBul.lastIndexOf(" + ")); logText = "在“" + element.getElementData().getName() + "”元素发送按键“" + resultText + "”"; return resultText; @@ -192,8 +210,14 @@ public class TextEvent extends AbstractEvent { * @param textElement 通过查找页面得到的文本框控件{@link Element}对象 * @param codeImageElement 通过查找页面得到的验证码图片控件{@link Element}对象 * @return 输入的内容 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String codeInput(Element textElement, Element codeImageElement) { + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + codeImageElement.getWebElement(); + textElement.getWebElement(); + // 判断验证码信息是否加载,加载后,获取其Rectang对象 Rectangle r = codeImageElement.getWebElement().getRect(); // 构造截图对象,并创建截图 @@ -231,6 +255,8 @@ public class TextEvent extends AbstractEvent { * @param textElements 通过查找页面得到的一组控件元素对象 * @return 由于涉及到多个文本框,故其返回值有多个,将以“值1,值2,值3...”的形式进行返回 * @deprecated 当前方法有些BUG,请勿调用,下个版本修复 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ @Deprecated public String avgIntergeInput(int num, Element... elements) { @@ -278,6 +304,8 @@ public class TextEvent extends AbstractEvent { * @param element {@link Element}对象 * @param updataFile 需要上传到控件中的文件 * @return 上传的文件路径 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String updataFile(Element element, File updataFile) { resultText = input(element, updataFile.getAbsolutePath()); diff --git a/src/main/java/pres/auxiliary/work/selenium/event/WaitEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/WaitEvent.java index 0ce8dc2..cccc1bc 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/WaitEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/WaitEvent.java @@ -2,16 +2,31 @@ package pres.auxiliary.work.selenium.event; import java.time.Duration; -import org.openqa.selenium.WebDriver; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.TimeoutException; import org.openqa.selenium.support.ui.WebDriverWait; import pres.auxiliary.work.selenium.brower.AbstractBrower; +import pres.auxiliary.work.selenium.element.AbstractBy.Element; +/** + ** EventProxy* - * *clickEventProxy = new EventProxy(new ClickEvent(chrome.getDriver())); * * clickProxy.addAcion(ActionType.ELEMENT_BEFORE, ".*登录.*", (info) -> { @@ -41,15 +43,16 @@ import pres.auxiliary.work.selenium.brower.ChromeBrower; * 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 彭宇琦 + *修改时间:2020年10月20日下午7:54:15
+ * * @version Ver1.0 - * @since JDK 12 + * @since JDK 8 + * @author 彭宇琦 + * + * @param继承自{@link AbstractEvent}的事件类 */ public class EventProxy implements MethodInterceptor { /** @@ -81,7 +84,7 @@ public class EventProxy implements MethodInterceptor { * 事件类对象 */ private T target; - private WebDriver driver; + private AbstractBrower brower; /** * 构造代理类 @@ -89,7 +92,7 @@ public class EventProxy implements MethodInterceptor { */ public EventProxy(T target) { this.target = target; - driver = ((AbstractEvent) target).getDriver(); + brower = ((AbstractEvent) target).getBrower(); } /** @@ -106,7 +109,7 @@ public class EventProxy implements MethodInterceptor { //设置回调函数 en.setCallback(this); //创建子类(代理对象) - return (T) en.create(new Class[] {WebDriver.class}, new Object[] {driver}); + return (T) en.create(new Class[] {AbstractBrower.class}, new Object[] {brower}); // return (T) en.create(); } @@ -204,9 +207,9 @@ public class EventProxy implements MethodInterceptor { * @param actionMap 需要执行的通知 */ private void runElementAction(EventInformation eventInformation, LinkedHashMap > actionMap) { - Arrays.stream(eventInformation.getParam()).filter(arg -> arg instanceof Element_Old).forEach(arg -> { + Arrays.stream(eventInformation.getParam()).filter(arg -> arg instanceof Element).forEach(arg -> { actionMap.forEach((key, value) -> { - if (Pattern.compile(key).matcher(((Element_Old) arg).getName()).matches()) { + if (Pattern.compile(key).matcher(((Element) arg).getElementData().getName()).matches()) { value.forEach(action -> { try { action.action(eventInformation); diff --git a/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java index 3fa5e7c..264bfdc 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java @@ -5,7 +5,9 @@ import java.util.Arrays; import java.util.UUID; import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebElement; import com.alibaba.fastjson.JSONArray; @@ -53,11 +55,13 @@ public class JsEvent extends AbstractEvent { * @param element {@link Element}对象 * @param attributeName 属性名 * @return 元素对应属性的内容 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String getAttribute(Element element, String attributeName) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); - + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); + // 获取对应元素的内容 String text = (String) (js.executeScript("return arguments[0].getAttribute('" + attributeName + "');", wait.until(driver -> { @@ -82,10 +86,12 @@ public class JsEvent extends AbstractEvent { * @param attributeName 需要设置的属性名 * @param value 需要设置的属性值 * @return 属性的原值 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String putAttribute(Element element, String attributeName, String value) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); // 获取原属性中的值 resultText = getAttribute(element, attributeName); @@ -111,11 +117,13 @@ public class JsEvent extends AbstractEvent { * @param element {@link Element}对象 * @param elementName 新元素(标签)的名称 * @return 新增元素的定位方式 + * @throws TimeoutException 元素无法操作时抛出的异常 + * @throws NoSuchElementException 元素不存在或下标不正确时抛出的异常 */ public String addElement(Element element, String elementName) { - //定位到元素上,若元素不存在或下标有误时,会抛出相应的异常 - locationElement(element); - + //由于在until()方法中无法直接抛出元素不存在的异常,故此处直接调用返回元素的方法,让元素不存在的异常抛出 + element.getWebElement(); + // 获取并将其作为 String script = "var oldElement = arguments[0];"; // 拼接添加元素的代码 @@ -162,13 +170,14 @@ public class JsEvent extends AbstractEvent { * } *
文件名:WaitEvent.java
+ *用途: + * 定义了对元素进行特殊事件等待的方法,包括等待控件消失、等待控件出现文字等, + * 可通过该类,等待元素进行一定的变化的操作 + *
+ *编码时间:2020年10月19日上午7:21:05
+ *修改时间:2020年10月19日上午7:21:05
+ * @author + * @version Ver1.0 + * + */ public class WaitEvent extends AbstractEvent{ /** * 控制等待 */ - private WebDriverWait wait; + private WebDriverWait eventWait; /** * 构造对象 @@ -29,8 +44,8 @@ public class WaitEvent extends AbstractEvent{ */ public WaitEvent(AbstractBrower brower, long waitTime) { super(brower); - wait = new WebDriverWait(brower.getDriver(), waitTime, 200); - wait.withMessage("等待超时,事件等待失败:" + waitTime + "秒"); + eventWait = new WebDriverWait(brower.getDriver(), waitTime, 200); + eventWait.withMessage("等待超时,事件等待失败,超时时间:" + waitTime + "秒"); } /** @@ -38,26 +53,122 @@ public class WaitEvent extends AbstractEvent{ * @param overtime 超时时间 */ public void setOvertime(long overtime) { - wait.pollingEvery(Duration.ofSeconds(overtime)); + eventWait.pollingEvery(Duration.ofSeconds(overtime < 0 ? 60L : overtime)); } /** - * 用于等待元素消失 - * @param waitElement 需要等待的元素 - */ - public void disappear(Element_Old waitElement) { - wait.until(driver -> { - return !waitElement.getWebElement().isDisplayed(); + * 用于等待元素消失,若元素无法获取到,则也判定为元素不存在 + * @param element {@link Element}对象 + * @return 元素是否已消失 + * @throws TimeoutException 等待超时时抛出的异常 + */ + public boolean disappear(Element element) { + eventWait.withMessage("等待超时,元素“" + element.getElementData().getName() +"”仍然存在,超时时间:" + waitTime + "秒"); + boolean result = eventWait.until(driver -> { + //调用isDisplayed()方法,判断元素是否存在 + try { + return !element.getWebElement().isDisplayed(); + } catch (NoSuchElementException e) { + //若在调用获取页面元素时抛出NoSuchElementException异常,则说明元素本身不存在,则直接返回true + return true; + } catch (StaleElementReferenceException e) { + //若抛出StaleElementReferenceException异常,则说明页面过期,重新获取元素后再进行判断 + element.againFindElement(); + return false; + } }); + + logText = "等待“" + element.getElementData().getName() + "”元素从页面消失"; + resultText = String.valueOf(result); + + return result; } /** - * 用于等待元素元素内出现文本 - * @param waitElement 需要等待的元素 - */ - public void showText(Element_Old waitElement) { - wait.until(driver -> { - return !new TextEvent(driver).getText(waitElement).isEmpty(); + * 该方法用于根据元素信息,在元素被加载后,等待元素在页面中出现,并返回元素出现的结果, + * 注意,等待元素出现的超时时间与元素中设置的超时时间一致,与类中超时时间无关 + * @param element {@link Element}对象 + * @return 元素是否出现 + * @throws TimeoutException 等待超时时抛出的异常 + */ + public boolean appear(Element element) { + eventWait.withMessage("等待超时,元素“" + element.getElementData().getName() +"”仍然不存在,超时时间:" + waitTime + "秒"); + boolean result = eventWait.until(driver -> { + //调用isDisplayed()方法,判断元素是否存在 + try { + return element.getWebElement().isDisplayed(); + } catch (StaleElementReferenceException | NoSuchElementException e) { + //若抛出StaleElementReferenceException异常,则说明页面过期,重新获取元素后再进行判断 + //若抛出NoSuchElementException异常,则说明当前元素不存在,则再重新进行一次获取 + element.againFindElement(); + return false; + } }); + + logText = "等待“" + element.getElementData().getName() + "”元素从页面消失"; + resultText = String.valueOf(result); + + return result; + } + + /** + * 该方法用于等待指定元素中显示相应的文本,可指定显示文本的关键词,直到显示相应的关键词为止, + * 若不传入关键词,则只判断元素加载出文本。若元素未出现,则返回false + * @param element {@link Element}对象 + * @return 元素是否存在文本或包含指定文本 + * @throws TimeoutException 等待超时时抛出的异常 + */ + public boolean showText(Element element, String...keys) { + //判断是否传入关键词数组,根据是否传入数组,调用不同的判断方式 + if (keys == null || keys.length == 0) { + logText = "等待“" + element.getElementData().getName() + "”元素加载出文本内容"; + + //判断元素是否存在,若不存在,则直接返回false + if (isExistElement(element)) { + resultText = Boolean.toString(false); + return false; + } else { + eventWait.withMessage("等待超时,元素“" + element.getElementData().getName() +"”仍未出现文本,超时时间:" + waitTime + "秒"); + TextEvent textEvent = new TextEvent(brower); + boolean result = eventWait.until(driver -> { + //调用isDisplayed()方法,判断元素是否存在 + try { + return !textEvent.getText(element).isEmpty(); + } catch (StaleElementReferenceException e) { + //若抛出StaleElementReferenceException异常,则说明页面过期,重新获取元素后再进行判断 + element.againFindElement(); + return false; + } + }); + + resultText = String.valueOf(result); + return result; + } + } else { + String keyText = arrayToString(keys); + logText = "等待“" + element.getElementData().getName() + "”元素出现文本关键词:" + keyText; + + //判断元素是否存在,若不存在,则直接返回false + if (isExistElement(element)) { + resultText = Boolean.toString(false); + return false; + } else { + eventWait.withMessage("等待超时,元素“" + element.getElementData().getName() +"”仍未出现关键词“" + keyText + "”,超时时间:" + waitTime + "秒"); + AssertEvent assertEvent = new AssertEvent(brower); + boolean result = eventWait.until(driver -> { + //断言方法,直到方法返回true为止 + try { + return assertEvent.assertTextContainKey(element, true, keys); + } catch (StaleElementReferenceException e) { + //若抛出StaleElementReferenceException异常,则说明页面过期,重新获取元素后再进行判断 + element.againFindElement(); + return false; + } + }); + + resultText = String.valueOf(result); + return result; + } + } } }