From e62c68b7772dc1458d7f22018ec77fe16f467676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com> Date: Fri, 22 May 2020 19:15:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=8B=E6=8B=89=E9=80=89?= =?UTF-8?q?=E9=A1=B9=E5=85=83=E7=B4=A0=E8=8E=B7=E5=8F=96=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pres/auxiliary/selenium/xml/ReadXml.java | 12 +- .../selenium/element/AbstractElement.java | 66 +++-- .../work/selenium/element/CommonElement.java | 8 +- .../selenium/element/DataListElement.java | 256 ++---------------- .../work/selenium/element/Element.java | 41 +-- .../work/selenium/element/ElementType.java | 32 +++ .../work/selenium/element/ListElement.java | 192 +++++++++++++ .../work/selenium/element/MultiElement.java | 111 ++++++++ .../work/selenium/element/SelectElement.java | 131 +++++++++ .../work/selenium/event/AbstractEvent.java | 2 +- .../work/selenium/event/JsEvent.java | 4 +- .../work/selenium/event/SelectEvent.java | 2 +- 12 files changed, 569 insertions(+), 288 deletions(-) create mode 100644 src/main/java/pres/auxiliary/work/selenium/element/ElementType.java create mode 100644 src/main/java/pres/auxiliary/work/selenium/element/ListElement.java create mode 100644 src/main/java/pres/auxiliary/work/selenium/element/MultiElement.java create mode 100644 src/main/java/pres/auxiliary/work/selenium/element/SelectElement.java diff --git a/src/main/java/pres/auxiliary/selenium/xml/ReadXml.java b/src/main/java/pres/auxiliary/selenium/xml/ReadXml.java index 454cc6a..5875a43 100644 --- a/src/main/java/pres/auxiliary/selenium/xml/ReadXml.java +++ b/src/main/java/pres/auxiliary/selenium/xml/ReadXml.java @@ -10,6 +10,7 @@ import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; +import org.dom4j.InvalidXPathException; import org.dom4j.io.SAXReader; import org.openqa.selenium.By; @@ -222,10 +223,15 @@ public class ReadXml { //获取元素的xpath,查找所有带name属性的与传入的name相同元素 String xpath = "//*[@name='" + name + "']"; //若不存在该节点,则返回false,反之,则返回true - if (dom.getRootElement().selectSingleNode(xpath) == null) { + try { + if (dom.getRootElement().selectSingleNode(xpath) == null) { + return false; + } else { + return true; + } + } catch (InvalidXPathException e) { + //当写入name为一个xpath时会抛出该异常,若存在该异常,则直接返回false return false; - } else { - return true; } } diff --git a/src/main/java/pres/auxiliary/work/selenium/element/AbstractElement.java b/src/main/java/pres/auxiliary/work/selenium/element/AbstractElement.java index 23a625b..f3b2aee 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/AbstractElement.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/AbstractElement.java @@ -87,6 +87,15 @@ public abstract class AbstractElement { this.driver = brower.getDriver(); } + /** + * 用于设置事件等待时间,默认时间为5秒 + * + * @param waitTime 事件等待时间 + */ + public void setWaitTime(long waitTime) { + this.waitTime = waitTime; + } + /** * 用于对单个控件设置等待时间 * @@ -97,14 +106,6 @@ public abstract class AbstractElement { controlWaitTime.put(name, waitTime); } - /** - * 用于设置控件的通用等待时间 - * @param waitTime 控件通用的等待时间 - */ - public void setWaitTime(long waitTime) { - this.waitTime = waitTime; - } - /** * 设置是否自动切换窗体 * @param switchIframe 是否自动切换窗体 @@ -203,7 +204,7 @@ public abstract class AbstractElement { * @param name 窗体的名称或xpath与css定位方式 */ public void switchFrame(String name) { - switchFrame(new ElementInformation(name, null)); + switchFrame(new ElementInformation(name, null, ElementType.COMMON_ELEMENT)); } /** @@ -216,7 +217,7 @@ public abstract class AbstractElement { * @see #switchFrame(String) */ public void switchFrame(String name, ByType byType) { - switchFrame(new ElementInformation(name, byType)); + switchFrame(new ElementInformation(name, byType, ElementType.COMMON_ELEMENT)); } /** @@ -270,7 +271,7 @@ public abstract class AbstractElement { } } else { //切换窗体 - driver.switchTo().frame(driver.findElement(recognitionElement(new ElementInformation(frameName, null)))); + driver.switchTo().frame(driver.findElement(recognitionElement(new ElementInformation(frameName, null, ElementType.COMMON_ELEMENT)))); iframeNameList.add(frameName); } }); @@ -315,7 +316,7 @@ public abstract class AbstractElement { driver.switchTo().window(newWinHandle); try { //构造信息,因为在构造过程中会判断元素是否存在, - recognitionElement(new ElementInformation(controlName, null)); + recognitionElement(new ElementInformation(controlName, null, ElementType.COMMON_ELEMENT)); return; }catch (Exception e) { continue; @@ -328,7 +329,7 @@ public abstract class AbstractElement { //切换窗口,并查找元素是否在窗口上,若存在,则结束切换 brower.switchWindow(page); try { - recognitionElement(new ElementInformation(controlName, null)); + recognitionElement(new ElementInformation(controlName, null, ElementType.COMMON_ELEMENT)); return; }catch (Exception e) { continue; @@ -606,9 +607,9 @@ public abstract class AbstractElement { * 存储获取元素时的信息 *

*

编码时间:2020年5月9日上午7:57:24

- *

修改时间:2020年5月9日上午7:57:24

+ *

修改时间:2020年5月22日上午8:18:39

* @author 彭宇琦 - * @version Ver1.0 + * @version Ver1.1 * @since JDK 12 * */ @@ -621,15 +622,48 @@ public abstract class AbstractElement { * 存储元素的定位方式 */ public ByType byType; + /** + * 用于标记元素的类型 + */ + public ElementType elementType; + /** + * 初始化信息 + * @param name 元素名称或定位内容 + * @param byType 元素定位 + * @param elementType 元素类型 + */ + public ElementInformation(String name, ByType byType, ElementType elementType) { + this(name, byType); + this.elementType = elementType; + } + /** * 初始化信息 * @param name 元素名称或定位内容 * @param byType 元素定位 */ public ElementInformation(String name, ByType byType) { - super(); this.name = name; this.byType = byType; } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ElementInformation other = (ElementInformation) obj; + if (byType != other.byType) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } } } diff --git a/src/main/java/pres/auxiliary/work/selenium/element/CommonElement.java b/src/main/java/pres/auxiliary/work/selenium/element/CommonElement.java index 62529cc..37cc228 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/CommonElement.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/CommonElement.java @@ -7,7 +7,6 @@ import org.openqa.selenium.support.ui.WebDriverWait; import pres.auxiliary.selenium.xml.ByType; import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.element.Element.ElementType; /** *

文件名:CommonElement.java

@@ -60,7 +59,7 @@ public class CommonElement extends AbstractElement { * @return {@link Element}对象 */ public Element getElement(String name, ByType byType) { - return getElement(new ElementInformation(name, byType)); + return getElement(new ElementInformation(name, byType, ElementType.COMMON_ELEMENT)); } /** @@ -101,5 +100,10 @@ public class CommonElement extends AbstractElement { WebElement element = driver.findElement(by); return element != null; }); + /* + return new WebDriverWait(driver, waitTime, 200). + until(ExpectedConditions.and(ExpectedConditions.visibilityOfAllElementsLocatedBy(by), + ExpectedConditions.invisibilityOfElementLocated(by))); + */ } } diff --git a/src/main/java/pres/auxiliary/work/selenium/element/DataListElement.java b/src/main/java/pres/auxiliary/work/selenium/element/DataListElement.java index f1bca34..4962484 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/DataListElement.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/DataListElement.java @@ -1,21 +1,17 @@ package pres.auxiliary.work.selenium.element; import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Random; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.WebDriverWait; import pres.auxiliary.selenium.xml.ByType; import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.element.Element.ElementType; /** *

文件名:DataListElement.java

@@ -30,27 +26,7 @@ import pres.auxiliary.work.selenium.element.Element.ElementType; * @version Ver1.0 * @since JDK 12 */ -public class DataListElement extends AbstractElement { - /** - * 用于存储获取到的列表一列元素,key为列表名称,value为列表元素 - */ - private LinkedHashMap> elementMap = new LinkedHashMap<>(16); - - /** - * 用于存储元素列累计的个数 - */ - private HashMap elementSizeMap = new HashMap(16); - - /** - * 用于存储是否开始累加列表元素的个数 - */ -// private boolean isStartAddSize = false; - - /** - * 用于判断列表的第一行元素是否为标题元素 - */ - private boolean isFristRowTitle = false; - +public class DataListElement extends ListElement { /** * 存储获取到的元素列表中最多元素列的元素个数 */ @@ -68,6 +44,21 @@ public class DataListElement extends AbstractElement { */ private ArrayList minColumnNameList = new ArrayList<>(); + /** + * 用于判断列表的第一行元素是否为标题元素 + */ + boolean isFristRowTitle = false; + + /** + * 用于存储元素列累计的个数 + */ +// private HashMap elementSizeMap = new HashMap(16); + + /** + * 用于存储是否开始累加列表元素的个数 + */ +// private boolean isStartAddSize = false; + /** * 通过浏览器对象{@link AbstractBrower}进行构造 * @param brower {@link AbstractBrower}对象 @@ -135,75 +126,16 @@ public class DataListElement extends AbstractElement { return minColumnNameList; } - /** - * 返回列表名称对应的元素个数,若该列未被获取,则返回-1 - * @param name 被获取的列名称 - * @return 列名对应列的元素个数 - */ - public int getColumnSize(String name) { - ElementInformation element = nameToElementInformation(name); - if (element != null) { - return elementMap.get(element).size(); - } else { - return -1; - } - } - - /** - * 该方法用于返回所有列的名称 - * @return 所有列的名称 - */ - public ArrayList getColumnName() { - ArrayList nameList = new ArrayList<>(); - elementMap.forEach((key, value) -> { - nameList.add(key.name); - }); - - return nameList; - } - - /** - * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,添加元素列。由于该方法不指定元素的定位 - * 方式,若传入的参数不是xml元素且非xpath路径或绝对css路径时,其识别效率较慢,建议在该情况下 - * 调用{@link #add(String, ByType)}方法,指定元素定位方法 - * @param name 元素在xml文件或者元素的定位内容 -// * @param isAddSize 是否对元素个数进行统计 - * @see #add(String, ByType) - * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 - */ - public void add(String name) { - add(name, null); - } - - /** - * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,以及元素的定位方式,添加元素列。 - * @param name 元素在xml文件或者元素的定位内容 - * @param byType 元素定位方式枚举对象({@link ByType}枚举) -// * @param isAddSize 是否对元素个数进行统计 - * @see #add(String) - * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 - */ + @Override public void add(String name, ByType byType) { - add(new ElementInformation(name, byType)); + add(new ElementInformation(name, byType, ElementType.DATA_LIST_ELEMENT)); + } - /** - * 添加元素的底层方法 - * @param elementInformation 元素信息类对象 - * @param isAddSize 是否需要统计 - */ - private void add(ElementInformation elementInformation) { - List elementList = new ArrayList(); - //获取元素 - By by = recognitionElement(elementInformation); - 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 = driver.findElements(recognitionElement(elementInformation)); - //添加元素 - elementMap.put(elementInformation, elementList); + @Override + void add(ElementInformation elementInformation) { + //重写父类的add方法,使元素能进行极值的统计 + super.add(elementInformation); //判断当前获取到的元素是否大于当前存储的元素的最大值或小于当前存储的最小值,若是,则将最大值或最小值进行替换 findLimitColumn(elementInformation); @@ -226,95 +158,6 @@ public class DataListElement extends AbstractElement { */ } - /** - * 用于清除或移除指定的列及列中的元素,当参数传入false时,则只清理列表中存储的元素,不移除 - * 整个列,若传入true时,则直接移除整个列。若列名称对应的列未被获取,则返回null - * @param name 已被获取的元素列名称 - * @param isRemove 是否需要将该列移除 - * @return 被移除列中存储的所有元素 - */ - public List clearColumn(String name, boolean isRemove) { - ElementInformation element = nameToElementInformation(name); - //若元素不存在,则直接返回null - if (element == null) { - return null; - } - - //用于存储被移除的元素 - List elementList = elementMap.get(element); - //判断元素是否需要被完全移除 - if (isRemove) { - //若元素需要被完全移除,则直接移除元素 - elementMap.remove(element); - //由于元素被移除,若该列存在元素个数统计,则同样将该元素移除 - if (elementSizeMap.containsKey(name)) { - elementSizeMap.remove(name); - } - } else { - //若元素无需移除,则将元素存储的列表内容清空 - elementMap.get(element).clear(); - } - - return elementList; - } - - /** - * 该方法用于根据存入的元素名称或定位方式,对元素进行重新获取的操作。主要用于当列表数据翻页后, - * 其原存入的数据将会失效,必须重新获取。注意,调用该方法后会清空原存储的数据。 - */ - public void againGetElement() { - // 读取elements中的元素 - elementMap.forEach((key, value) -> { - // 清空元素中的内容 - clearColumn(key.name, false); - // 对页面内容重新进行获取 - add(key); - }); - } - - /** - * 该方法用于根据列名称,查找到相应的列,并返回与传入下标对应的元素。下标支持从后向前获取,传入的下标 - * 与元素实际所在位置一致,当传入0时,则表示随机获取一个元素,如:
- * {@code getWebElement("姓名", 1)}表示获取名称为“姓名”的列中的第1个元素
- * {@code getWebElement("姓名", 0)}表示获取名称为“姓名”的列中在长度范围内随机一个元素
- * {@code getWebElement("//*[@id='name']", -1)}表示获取“//*[@id='name']”对应列中的倒数第1个元素
- * - * @param name 列名称 - * @param index 元素下标(即列表中对应的某一个元素) - * @return 对应列指定的元素 - * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 - */ - public Element getWebElement(String name, int index) { - //获取元素信息,并判断元素是否存在,不存在则抛出异常 - ElementInformation element = nameToElementInformation(name); - if (element == null) { - throw new NoSuchElementException("不存在的定位方式:" + name); - } - - // 转义下标 - index = getIndex(element, index); - - // 转义下标后,返回对应的元素 - return elementMap.get(element).get(index); - } - - /** - * 该方法用于根据列名称,获取该列下所有的元素 - * - * @param name 列名称 - * @return 对应列元素 - * @throws NoSuchElementException 当未对name列进行获取数据时抛出的异常 - */ - public List getAllWebElement(String name) { - //获取元素信息,并判断元素是否存在,不存在则抛出异常 - ElementInformation element = nameToElementInformation(name); - if (element == null) { - throw new NoSuchElementException("不存在的定位方式:" + name); - } - - return elementMap.get(element); - } - /** * 用于返回列表多个指定的元素,传入的下标可参见{@link #getWebElement(String, int)} * @@ -324,13 +167,13 @@ public class DataListElement extends AbstractElement { * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 * @see #getWebElement(String, int) */ - public List getWebElements(String name, int... indexs) { + public List getElements(String name, int... indexs) { // 存储所有获取到的事件 ArrayList events = new ArrayList<>(); // 循环,解析所有的下标,并调用getEvent()方法,存储至events for (int index : indexs) { - events.add(getWebElement(name, index)); + events.add(getElement(name, index)); } return events; @@ -343,7 +186,7 @@ public class DataListElement extends AbstractElement { * @param length 需要返回列表事件的个数 * @return 列表事件组 */ - public List getRandomWebElements(String name, int length) { + public List getRandomElements(String name, int length) { //获取元素信息,并判断元素是否存在,不存在则抛出异常 ElementInformation element = nameToElementInformation(name); if (element == null) { @@ -352,7 +195,7 @@ public class DataListElement extends AbstractElement { // 判断传入的长度是否大于等于当前 if (length >= elementMap.get(element).size()) { - return getAllWebElement(name); + return getAllElement(name); } // 存储通过随机得到的数字 @@ -373,7 +216,7 @@ public class DataListElement extends AbstractElement { indexs[i] = indexsList.get(i); } - return getWebElements(name, indexs); + return getElements(name, indexs); } /* @@ -409,49 +252,6 @@ public class DataListElement extends AbstractElement { } } - /** - * 由于方法允许传入负数和特殊数字0为下标,并且下标的序号由1开始, - * 故可通过该方法对下标的含义进行转义,得到java能识别的下标 - * @param element 元素信息类对象 - * @param index 传入的下标 - * @return 可识别的下标 - * @throws NoSuchElementException 当元素无法查找到时抛出的异常 - */ - int getIndex(ElementInformation element, int index) { - int length = elementMap.get(element).size(); - //判断元素下标是否超出范围,由于可以传入负数,故需要使用绝对值 - if (Math.abs(index) >= length) { - throw new NoSuchElementException("指定的选项值大于选项的最大值。选项总个数:" + length + ",指定项:" + index); - } - - //判断index的值,若大于0,则从前向后遍历,若小于0,则从后往前遍历,若等于0,则随机输入 - if (index > 0) { - //选择元素,正数的选项值从1开始,故需要减小1 - return index - 1; - } else if (index < 0) { - //选择元素,由于index为负数,则长度加上选项值即可得到需要选择的选项 - return length + index; - } else { - //为0,则随机进行选择 - return new Random().nextInt(length); - } - } - - /** - * 根据元素名称反推元素信息类对象,用于根据列名称查找数据以及判断列是否存在,若列名不存在,则返回null - * @return ElementInformation对象 - */ - ElementInformation nameToElementInformation(String name) { - //遍历elementMap,若查找与name一致的名称,则结束循环并返回相应的ElementInformation对象 - for (ElementInformation element : elementMap.keySet()) { - if (element.name.equals(name)) { - return element; - } - } - - return null; - } - @Override boolean isExistElement(By by, long waitTime) { //TODO 修改等待方法,改为获取到元素后才返回相应的状态 diff --git a/src/main/java/pres/auxiliary/work/selenium/element/Element.java b/src/main/java/pres/auxiliary/work/selenium/element/Element.java index 25a5daa..d29a32a 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/Element.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/Element.java @@ -52,9 +52,6 @@ public class Element { this.index = index; this.driver = driver; this.elementType = elementType; - - //对元素进行一次查找 - findElement(); } /** @@ -71,6 +68,12 @@ public class Element { * @return 返回元素对应的WebElement对象 */ public WebElement getWebElement() { + //若元素未进行查找,则查找一次元素 + if(element == null) { + //对元素进行一次查找 + findElement(); + } + return element; } @@ -90,36 +93,4 @@ public class Element { throw new IllegalArgumentException("Unexpected value: " + elementType); } } - - /** - *

文件名:Element.java

- *

用途: - * 用于标记当前传入的元素是以何种方式进行获取 - *

- *

编码时间:2020年5月20日上午7:43:38

- *

修改时间:2020年5月20日上午7:43:38

- * @author - * @version Ver1.0 - * @since JDK 12 - * - */ - public enum ElementType { - /** - * 指向普通类型元素 - */ - COMMON_ELEMENT, - /** - * 指向数据列表类型元素 - */ - DATA_LIST_ELEMENT, - /** - * 指向标准下拉框选择类型元素 - */ - SELECT_OPTION_ELEMENT, - /** - * 指向列表型下拉框选择类型元素 - */ - SELECT_DATAS_ELEMENT; - - } } diff --git a/src/main/java/pres/auxiliary/work/selenium/element/ElementType.java b/src/main/java/pres/auxiliary/work/selenium/element/ElementType.java new file mode 100644 index 0000000..31323c5 --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/element/ElementType.java @@ -0,0 +1,32 @@ +package pres.auxiliary.work.selenium.element; + +/** + *

文件名:EelementType.java

+ *

用途: + * 用于标记当前传入的元素是以何种方式进行获取 + *

+ *

编码时间:2020年5月22日上午7:57:32

+ *

修改时间:2020年5月22日上午7:57:32

+ * @author + * @version Ver1.0 + * @since JDK 12 + * + */ +public enum ElementType { + /** + * 指向普通类型元素 + */ + COMMON_ELEMENT, + /** + * 指向数据列表类型元素 + */ + DATA_LIST_ELEMENT, + /** + * 指向标准下拉框选择类型元素 + */ + SELECT_OPTION_ELEMENT, + /** + * 指向列表型下拉框选择类型元素 + */ + SELECT_DATAS_ELEMENT; +} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/ListElement.java b/src/main/java/pres/auxiliary/work/selenium/element/ListElement.java new file mode 100644 index 0000000..f9c943e --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/element/ListElement.java @@ -0,0 +1,192 @@ +package pres.auxiliary.work.selenium.element; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebDriver; + +import pres.auxiliary.work.selenium.brower.AbstractBrower; + +/** + *

文件名:ListElement.java

+ *

用途: + * 提供获取列表类型元素时的基本方法 + *

+ *

编码时间:2020年5月22日上午7:54:55

+ *

修改时间:2020年5月22日上午7:54:55

+ * @author 彭宇琦 + * @version Ver1.0 + * @since JDK 12 + * + */ +public abstract class ListElement extends MultiElement { + /** + * 用于存储获取到的列表一列元素,key为列表名称,value为列表元素 + */ + LinkedHashMap> elementMap = new LinkedHashMap<>(16); + + /** + * 通过浏览器对象{@link AbstractBrower}进行构造 + * @param brower {@link AbstractBrower}对象 + */ + public ListElement(AbstractBrower brower) { + super(brower); + } + + /** + * 构造对象并存储浏览器的{@link WebDriver}对象 + * + * @param driver 浏览器的{@link WebDriver}对象 + */ + public ListElement(WebDriver driver) { + super(driver); + } + + /** + * 返回列表名称对应的元素个数,若该列未被获取,则返回-1 + * @param name 被获取的列名称 + * @return 列名对应列的元素个数 + */ + public int getSize(String name) { + ElementInformation element = nameToElementInformation(name); + if (element != null) { + return elementMap.get(element).size(); + } else { + return -1; + } + } + + /** + * 该方法用于返回所有列的名称 + * @return 所有列的名称 + */ + public ArrayList getNames() { + ArrayList nameList = new ArrayList<>(); + elementMap.forEach((key, value) -> { + nameList.add(key.name); + }); + + return nameList; + } + + @Override + void add(ElementInformation elementInformation) { + List elementList = new ArrayList(); + //获取元素 + By by = recognitionElement(elementInformation); + 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 = driver.findElements(recognitionElement(elementInformation)); + //添加元素 + elementMap.put(elementInformation, elementList); + } + + /** + * 用于清除或移除指定的列及列中的元素,当参数传入false时,则只清理列表中存储的元素,不移除 + * 整个列,若传入true时,则直接移除整个列。若列名称对应的列未被获取,则返回null + * @param name 已被获取的元素列名称 + * @param isRemove 是否需要将该列移除 + * @return 被移除列中存储的所有元素 + */ + public List clearColumn(String name, boolean isRemove) { + ElementInformation element = nameToElementInformation(name); + //若元素不存在,则直接返回null + if (element == null) { + return null; + } + + //用于存储被移除的元素 + List elementList = elementMap.get(element); + //判断元素是否需要被完全移除 + if (isRemove) { + //若元素需要被完全移除,则直接移除元素 + elementMap.remove(element); + //由于元素被移除,若该列存在元素个数统计,则同样将该元素移除 + /* + if (elementSizeMap.containsKey(name)) { + elementSizeMap.remove(name); + } + */ + } else { + //若元素无需移除,则将元素存储的列表内容清空 + elementMap.get(element).clear(); + } + + return elementList; + } + + @Override + public void againGetElement() { + // 读取elements中的元素 + elementMap.forEach((key, value) -> { + // 清空元素中的内容 + clearColumn(key.name, false); + // 对页面内容重新进行获取 + add(key); + }); + } + + /** + * 根据元素名称反推元素信息类对象,用于根据列名称查找数据以及判断列是否存在,若列名不存在,则返回null + * @return ElementInformation对象 + */ + ElementInformation nameToElementInformation(String name) { + //遍历elementMap,若查找与name一致的名称,则结束循环并返回相应的ElementInformation对象 + for (ElementInformation element : elementMap.keySet()) { + if (element.name.equals(name)) { + return element; + } + } + + return null; + } + + /** + * 该方法用于根据列名称,查找到相应的列,并返回与传入下标对应的元素。下标支持从后向前获取,传入的下标 + * 与元素实际所在位置一致,当传入0时,则表示随机获取一个元素,如:
+ * {@code getWebElement("姓名", 1)}表示获取名称为“姓名”的列中的第1个元素
+ * {@code getWebElement("姓名", 0)}表示获取名称为“姓名”的列中在长度范围内随机一个元素
+ * {@code getWebElement("//*[@id='name']", -1)}表示获取“//*[@id='name']”对应列中的倒数第1个元素
+ * + * @param name 列名称 + * @param index 元素下标(即列表中对应的某一个元素) + * @return 对应列指定的元素 + * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 + */ + public Element getElement(String name, int index) { + //获取元素信息,并判断元素是否存在,不存在则抛出异常 + ElementInformation element = nameToElementInformation(name); + if (element == null) { + throw new NoSuchElementException("不存在的定位方式:" + name); + } + + // 转义下标 + index = getIndex(elementMap.get(element).size(), index); + + // 转义下标后,返回对应的元素 + return elementMap.get(element).get(index); + } + + /** + * 该方法用于根据列名称,获取该列下所有的元素 + * + * @param name 列名称 + * @return 对应列元素 + * @throws NoSuchElementException 当未对name列进行获取数据时抛出的异常 + */ + public List getAllElement(String name) { + //获取元素信息,并判断元素是否存在,不存在则抛出异常 + ElementInformation element = nameToElementInformation(name); + if (element == null) { + throw new NoSuchElementException("不存在的定位方式:" + name); + } + + return elementMap.get(element); + } +} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/MultiElement.java b/src/main/java/pres/auxiliary/work/selenium/element/MultiElement.java new file mode 100644 index 0000000..a7f1bf1 --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/element/MultiElement.java @@ -0,0 +1,111 @@ +package pres.auxiliary.work.selenium.element; + +import java.util.Random; + +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.TimeoutException; +import org.openqa.selenium.WebDriver; + +import pres.auxiliary.selenium.xml.ByType; +import pres.auxiliary.work.selenium.brower.AbstractBrower; + +/** + *

文件名:MultiElement.java

+ *

用途: + * 提供获取多个元素时使用的基本方法 + *

+ *

编码时间:2020年5月22日上午7:54:28

+ *

修改时间:2020年5月22日上午7:54:28

+ * @author 彭宇琦 + * @version Ver1.0 + * @since JDK 12 + * + */ +public abstract class MultiElement extends AbstractElement { + /** + * 通过浏览器对象{@link AbstractBrower}进行构造 + * @param brower {@link AbstractBrower}对象 + */ + public MultiElement(AbstractBrower brower) { + super(brower); + } + + /** + * 构造对象并存储浏览器的{@link WebDriver}对象 + * + * @param driver 浏览器的{@link WebDriver}对象 + */ + public MultiElement(WebDriver driver) { + super(driver); + } + + /** + * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,添加元素。由于该方法不指定元素的定位 + * 方式,若传入的参数不是xml元素且非xpath路径或绝对css路径时,其识别效率较慢,建议在该情况下 + * 调用{@link #add(String, ByType)}方法,指定元素定位方法 + * @param name 元素在xml文件或者元素的定位内容 + * @see #add(String, ByType) + * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 + */ + public void add(String name) { + add(name, null); + } + + /** + * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,以及元素的定位方式,添加元素。 + * @param name 元素在xml文件或者元素的定位内容 + * @param byType 元素定位方式枚举对象({@link ByType}枚举) + * @see #add(String) + * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 + */ + public abstract void add(String name, ByType byType); + + /** + * 添加元素的底层方法 + * @param elementInformation 元素信息类对象 + * @param isAddSize 是否需要统计 + */ + abstract void add(ElementInformation elementInformation); + + /** + * 该方法用于根据存入的元素名称或定位方式,对元素进行重新获取的操作。主要用于当列表数据翻页后, + * 其原存入的数据将会失效,必须重新获取。注意,调用该方法后会清空原存储的数据。 + */ + public abstract void againGetElement(); + + /** + * 用于清除或移除指定的列及列中的元素,当参数传入false时,则只清理列表中存储的元素,不移除 + * 整个列,若传入true时,则直接移除整个列。若列名称对应的列未被获取,则返回null + * @param name 已被获取的元素列名称 + * @param isRemove 是否需要将该列移除 + * @return 被移除列中存储的所有元素 + */ +// public abstract List clearColumn(String name, boolean isRemove); + + /** + * 由于方法允许传入负数和特殊数字0为下标,并且下标的序号由1开始, + * 故可通过该方法对下标的含义进行转义,得到java能识别的下标 + * @param length 元素的个数 + * @param index 传入的下标 + * @return 可识别的下标 + * @throws NoSuchElementException 当元素无法查找到时抛出的异常 + */ + int getIndex(int length, int index) { + //判断元素下标是否超出范围,由于可以传入负数,故需要使用绝对值 + if (Math.abs(index) > length) { + throw new NoSuchElementException("指定的选项值大于选项的最大值。选项总个数:" + length + ",指定项:" + index); + } + + //判断index的值,若大于0,则从前向后遍历,若小于0,则从后往前遍历,若等于0,则随机输入 + if (index > 0) { + //选择元素,正数的选项值从1开始,故需要减小1 + return index - 1; + } else if (index < 0) { + //选择元素,由于index为负数,则长度加上选项值即可得到需要选择的选项 + return length + index; + } else { + //为0,则随机进行选择 + return new Random().nextInt(length); + } + } +} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/SelectElement.java b/src/main/java/pres/auxiliary/work/selenium/element/SelectElement.java new file mode 100644 index 0000000..8981548 --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/element/SelectElement.java @@ -0,0 +1,131 @@ +package pres.auxiliary.work.selenium.element; + +import java.util.ArrayList; +import java.util.List; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; +import org.openqa.selenium.support.ui.WebDriverWait; + +import pres.auxiliary.selenium.xml.ByType; +import pres.auxiliary.work.selenium.brower.AbstractBrower; + +public class SelectElement extends MultiElement { + /** + * 用于存储获取下拉选项时的信息 + */ + ElementInformation elementInfo; + /** + * 用于存储下拉选项的元素 + */ + ArrayList option = new ArrayList<>(); + /** + * 用于存储下拉选项的文本 + */ + ArrayList optionText = new ArrayList<>(); + + /** + * 设置获取的下拉选项的类型,0表示标准的select-option型;1表示非标准的下拉选项型 + */ + private ElementType elementType; + + /** + * 通过浏览器对象{@link AbstractBrower}进行构造 + * @param brower {@link AbstractBrower}对象 + */ + public SelectElement(AbstractBrower brower) { + super(brower); + } + + /** + * 构造对象并存储浏览器的{@link WebDriver}对象 + * + * @param driver 浏览器的{@link WebDriver}对象 + */ + public SelectElement(WebDriver driver) { + super(driver); + } + + @Override + public void add(String name, ByType byType) { + add(new ElementInformation(name, byType)); + } + + @Override + void add(ElementInformation elementInformation) { + //获取元素的By对象 + By by = recognitionElement(elementInformation); + //根据By获取元素 + List elementList = driver.findElements(by); + //获取元素个数 + int size = elementList.size(); + + //根据获取到的元素个数,来判断下拉选项的类型 + if (size == 1) { + elementInformation.elementType = ElementType.SELECT_OPTION_ELEMENT; + + //若是标准下拉选项型,则需要改变size的值,方便后续添加数据 + Select select = new Select(driver.findElement(by)); + //获取所有的选项内容,并计算元素个数 + elementList = select.getOptions(); + size = elementList.size(); + } else { + elementInformation.elementType = ElementType.SELECT_DATAS_ELEMENT; + } + + //构造Element对象 + for (int i = 0; i < size; i++) { + //获取元素 + option.add(new Element(driver, elementType, by, i)); + //获取元素的文本内容 + optionText.add(elementList.get(0).getText()); + } + } + + /** + * 根据选项下标,返回相应的选项元素。下标与选项元素真实下标一致,支持传入负数,表示从后向前遍历元素; + * 当传入0时,表示随机选择一个选项。 + * @param index 选项下标 + * @return 相应的选项元素 + */ + public Element getElement(int index) { + return option.get(getIndex(option.size(), index)); + } + + /** + * 根据选项内容,返回相应的选项元素,当传入的元素名称不存在时,则返回null;当存在重复的选项 + * 名称时,则选择第一个选项 + * + * @param elementName 选项名称 + * @return 相应的选项元素 + */ + public Element getElement(String elementName) { + //根据名称获取元素下标 + int index = optionText.indexOf(elementName); + //判断下标是否为-1(元素是否存在),若不存在则返回null + if (index == -1) { + return null; + } + + return option.get(optionText.indexOf(elementName)); + } + + @Override + public void againGetElement() { + option.clear(); + optionText.clear(); + add(elementInfo); + } + + @Override + boolean isExistElement(By by, long waitTime) { + //当查找到元素时,则返回true,若查不到元素,则会抛出异常,故返回false + return new WebDriverWait(driver, waitTime, 200). + until((driver) -> { + WebElement element = driver.findElement(by); + return element != null; + }); + } +} 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 bbec357..b33bb75 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java @@ -29,7 +29,7 @@ public abstract class AbstractEvent { /** * 设置显示等待的超时时间(默认3秒) */ - long waitTime = 3; + long waitTime = 5; /** * 用于在记录步骤时需要替换的元素名称文本 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 da654c0..45a556a 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java @@ -14,10 +14,10 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import pres.auxiliary.work.selenium.element.Element; -import pres.auxiliary.work.selenium.element.Element.ElementType; +import pres.auxiliary.work.selenium.element.ElementType; /** - *

+ *

* 文件名:JsEvent.java *

*

diff --git a/src/main/java/pres/auxiliary/work/selenium/event/SelectEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/SelectEvent.java index afdb600..99e34d7 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/SelectEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/SelectEvent.java @@ -88,7 +88,7 @@ public class SelectEvent extends AbstractEvent { */ private int getIndex(int length, int index) { //判断元素下标是否超出范围,由于可以传入负数,故需要使用绝对值 - if (Math.abs(index) >= length) { + if (Math.abs(index) > length) { throw new NoSuchElementException("指定的选项值大于选项的最大值。选项总个数:" + length + ",指定项:" + index); }