From a72e5a2034e77bb5888b200887f37a9bef68c8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com> Date: Wed, 5 Aug 2020 20:52:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=83=E7=B4=A0=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UndefinedDirectoryException.java | 28 + .../work/selenium/element/AbstractBy.java | 17 +- .../work/selenium/element/CommonBy.java | 1 + .../work/selenium/element/DataListBy.java | 236 +++--- .../work/selenium/element/Element.java | 193 +++-- .../work/selenium/element/ElementType.java | 8 +- .../work/selenium/element/ListBy.java | 143 ++-- .../work/selenium/element/SelectBy.java | 123 +++ .../UnrecognizableLocationModeException.java | 2 +- .../work/selenium/element/old/AbstractBy.java | 721 ------------------ .../work/selenium/element/old/CommonBy.java | 127 --- .../work/selenium/element/old/DataListBy.java | 267 ------- .../work/selenium/element/old/Element.java | 128 ---- .../selenium/element/old/ElementType.java | 32 - .../work/selenium/element/old/ListBy.java | 205 ----- .../work/selenium/element/old/MultiBy.java | 149 ---- .../element/old/NoSuchWindownException.java | 28 - .../work/selenium/element/old/SelectBy.java | 313 -------- .../work/selenium/event/ClickEvent.java | 2 +- .../work/selenium/event/EventAction.java | 2 +- .../work/selenium/event/EventInformation.java | 2 +- .../work/selenium/event/EventProxy.java | 2 +- .../work/selenium/event/EventWait.java | 2 +- .../work/selenium/event/JsEvent.java | 10 +- .../work/selenium/event/TextEvent.java | 4 +- .../tool/IncorrectDirectoryException.java | 28 + .../work/selenium/tool/Screenshot.java | 123 +-- .../work/selenium/element/CommonByTest.java | 5 +- 28 files changed, 543 insertions(+), 2358 deletions(-) create mode 100644 src/main/java/pres/auxiliary/work/old/testcase/writecase/UndefinedDirectoryException.java create mode 100644 src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java rename src/main/java/pres/auxiliary/work/selenium/element/{old => }/UnrecognizableLocationModeException.java (95%) delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/AbstractBy.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/CommonBy.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/DataListBy.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/Element.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/ElementType.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/ListBy.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/MultiBy.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/NoSuchWindownException.java delete mode 100644 src/main/java/pres/auxiliary/work/selenium/element/old/SelectBy.java create mode 100644 src/main/java/pres/auxiliary/work/selenium/tool/IncorrectDirectoryException.java diff --git a/src/main/java/pres/auxiliary/work/old/testcase/writecase/UndefinedDirectoryException.java b/src/main/java/pres/auxiliary/work/old/testcase/writecase/UndefinedDirectoryException.java new file mode 100644 index 0000000..ecc1f07 --- /dev/null +++ b/src/main/java/pres/auxiliary/work/old/testcase/writecase/UndefinedDirectoryException.java @@ -0,0 +1,28 @@ +package pres.auxiliary.work.old.testcase.writecase; + +public class UndefinedDirectoryException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public UndefinedDirectoryException() { + super(); + } + + public UndefinedDirectoryException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public UndefinedDirectoryException(String message, Throwable cause) { + super(message, cause); + } + + public UndefinedDirectoryException(String message) { + super(message); + } + + public UndefinedDirectoryException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java b/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java index b1f95f3..c04e32c 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java @@ -2,7 +2,6 @@ package pres.auxiliary.work.selenium.element; import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -12,7 +11,6 @@ import org.openqa.selenium.By; import org.openqa.selenium.TimeoutException; import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.element.old.UnrecognizableLocationModeException; import pres.auxiliary.work.selenium.xml.ByType; import pres.auxiliary.work.selenium.xml.ReadXml; @@ -81,12 +79,17 @@ public abstract class AbstractBy { * @param xmlFile 存储元素定位方式的xml文件对象 * @param isBreakRootFrame 是否需要将窗体切回到顶层 */ - public void setXmlFile(File xmlFile) { + public void setXmlFile(File xmlFile, boolean isBreakRootFrame) { if (xml == null) { xml = new ReadXml(xmlFile); } else { xml.setXmlPath(xmlFile); } + + //若需要切回顶层,则切换到顶层窗体 + if (isBreakRootFrame) { + brower.getDriver().switchTo().defaultContent(); + } } /** @@ -298,7 +301,7 @@ public abstract class AbstractBy { //设置父层元素的获取方式及等待时间 iframeElement.setWaitTime(getWaitTime(iframeName)); iframeElement.setByList(getXmlElementBy(iframeName, null)); - iframeElement.setElementIndex(0); + iframeElement.setElementIndex(1); //设置父层 childElement.setIframeElement(iframeElement); @@ -360,9 +363,9 @@ public abstract class AbstractBy { * @param linkKey 需要判断的外链xml文件词语 * @return 是否与类中存储的词语一致 */ - public boolean linkKeyEquals(String...linkKey) { + public boolean linkKeyEquals(List linkKey) { //判断传入的linkKey是否为null,或未传入的linkKey为空,为空,则直接判断linkKeyList的状态 - if (linkKey == null) { + if (linkKey == null || linkKey.size() == 0) { //若linkKeyList为null或为空,则可直接返回true;反之,则返回false if (linkKeyList == null || linkKeyList.size() == 0) { return true; @@ -373,7 +376,7 @@ public abstract class AbstractBy { } //判断linkKey中的元素是否完全存在于linkKeyList,且两个集合的长度一致,若存在一项判断不符合,则返回false - if (linkKeyList.containsAll(Arrays.asList(linkKey)) && linkKeyList.size() == linkKey.length) { + if (linkKeyList.containsAll(linkKey) && linkKeyList.size() == linkKey.size()) { return true; } else { return false; diff --git a/src/main/java/pres/auxiliary/work/selenium/element/CommonBy.java b/src/main/java/pres/auxiliary/work/selenium/element/CommonBy.java index 090e9bd..13c177d 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/CommonBy.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/CommonBy.java @@ -85,6 +85,7 @@ public class CommonBy extends AbstractBy { Element element = new Element(brower, elementInformation.name, elementInformation.elementType); element.setWaitTime(getWaitTime(elementInformation.name)); element.setByList(recognitionElement(elementInformation)); + element.setElementIndex(1); //构造元素的父层元素,若元素不存在窗体结构,则不进行构造 if (elementInformation.iframeList != null && elementInformation.iframeList.size() != 0) { diff --git a/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java b/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java index 149e2e1..9030c81 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java @@ -1,17 +1,12 @@ package pres.auxiliary.work.selenium.element; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Random; -import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.WebDriverWait; import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.xml.ByType; /** *

文件名:DataListElement.java

@@ -24,40 +19,10 @@ import pres.auxiliary.work.selenium.xml.ByType; *

修改时间:2020年4月29日下午6:18:46

* @author 彭宇琦 * @version Ver1.0 - * @since JDK 12 + * @since JDK 8 */ public class DataListBy extends ListBy { - /** - * 存储获取到的元素列表中最多元素列的元素个数 - */ - private int maxColumnSize = -1; - /** - * 存储获取到的元素列表中最多元素列的名称 - */ - private ArrayList maxColumnNameList = new ArrayList<>(); - /** - * 存储获取到的元素列表中最少元素列的元素个数 - */ - private int minColumnSize = Integer.MAX_VALUE; - /** - * 存储获取到的元素列表中最少元素列的名称 - */ - private ArrayList minColumnNameList = new ArrayList<>(); - - /** - * 用于判断列表的第一行元素是否为标题元素 - */ - boolean isFristRowTitle = false; - - /** - * 用于存储元素列累计的个数 - */ -// private HashMap elementSizeMap = new HashMap(16); - - /** - * 用于存储是否开始累加列表元素的个数 - */ -// private boolean isStartAddSize = false; + //TODO 添加获取最大列方法 /** * 通过浏览器对象{@link AbstractBrower}进行构造 @@ -67,63 +32,37 @@ public class DataListBy extends ListBy { super(brower); } - /** - * 用于设置首行元素是否为标题元素 - * @param isFristRowTitle 首行是否为标题元素 - */ - public void setFristRowTitle(boolean isFristRowTitle) { - this.isFristRowTitle = isFristRowTitle; - } - - /** - * 用于设置是否开始计算元素个数 - * @param isStartAddSize 是否开始计算元素个数 - */ - /* - public void setStartAddSize(boolean isStartAddSize) { - this.isStartAddSize = isStartAddSize; - } - */ - /** * 返回元素最多列的元素个数 * @return 元素最多列的元素个数 */ - public int getMaxColumnSize() { - return maxColumnSize; - } +// public int getMaxColumnSize() { +// return maxColumnSize; +// } /** * 返回元素最多列的列名称 * @return 元素最多列的列名称 */ - public List getMaxColumnName() { - return maxColumnNameList; - } +// public List getMaxColumnName() { +// return maxColumnNameList; +// } /** * 返回元素最少列的元素个数 * @return 元素最少列的元素个数 */ - public int getMinColumnSize() { - return minColumnSize; - } +// public int getMinColumnSize() { +// return minColumnSize; +// } /** * 返回元素最少列的列名称 * @return 元素最少列的列名称 */ - public List getMinColumnName() { - return minColumnNameList; - } - - @Override - void add(ElementInformation elementInformation) { - //重写父类的add方法,使元素能进行极值的统计 - super.add(elementInformation); - //判断当前获取到的元素是否大于当前存储的元素的最大值或小于当前存储的最小值,若是,则将最大值或最小值进行替换 - findLimitColumn(elementInformation); - } +// public List getMinColumnName() { +// return minColumnNameList; +// } /** * 用于返回列表多个指定的元素,传入的下标可参见{@link #getWebElement(String, int)} @@ -134,82 +73,95 @@ public class DataListBy extends ListBy { * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 * @see #getWebElement(String, int) */ - public List getElements(String name, int... indexs) { - // 存储所有获取到的事件 - ArrayList events = new ArrayList<>(); - - // 循环,解析所有的下标,并调用getEvent()方法,存储至events - for (int index : indexs) { - events.add(getElement(name, index)); +// public List getElements(String name, int... indexs) { +// // 存储所有获取到的事件 +// ArrayList events = new ArrayList<>(); +// +// // 循环,解析所有的下标,并调用getEvent()方法,存储至events +// for (int index : indexs) { +// events.add(getElement(name, index)); +// } +// +// return events; +// } + + /** + * 根据元素列名称与外链词语,查找并返回该列所有的元素对象,。注意,调用该方法时,若未对元素 + * 进行查找,则会先查找一次元素,此时,若元素无法找到,则可能抛出异常 + * @param name 元素名称 + * @param linkKey 外链的词语,若不存在,则不传入 + * @return 指定列中所有的元素对象 + * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 + */ + public List getAllElement(String name, String...linkKey) { + //根据元素名称和外链词语,获取元素信息,用于获取元素 + ElementInformation elementInfo = nameToElementInformation(name, Arrays.asList(linkKey)); + + //若元素不存在,则抛出异常 + if (elementInfo == null) { + throw new NoSuchElementException("不存在的元素或外链词语不正确:" + name + "=" + Arrays.asList(linkKey)); } - - return events; + + //获取名称对应的元素 + Element element = elementMap.get(elementInfo); + //获取元素能查找到的个数 + int size = element.getSize(); + //判断获取到的元素其长度是否为-1,若是-1,则表示未对元素进行获取,需要先对元素进行一次获取,再重新获取元素个数 + if (element.getSize() == -1) { + element.getWebElement(); + size = element.getSize(); + } + + // 存储克隆的元素 + ArrayList elementList = new ArrayList<>(); + //循环,克隆并存储元素 + for (int index = 0; index < size; index++) { + Element cloneElement = element.clone(); + //下标从1开始,0为随机 + cloneElement.setElementIndex(index + 1); + elementList.add(cloneElement); + } + + return elementList; } /** - * 用于返回列表中指定随机个数的元素 + * 用于根据列名称,查找并返回相应列的第一个元素 + * @param name 元素名称 + * @param linkKey 外链的词语,若不存在,则不传入 + * @return 对应列指定的元素 + */ + public Element getElement(String name, String...linkKey) { + return getElement(name, 0, linkKey); + } + + /** + * 该方法用于根据列名称,查找到相应的列,并返回与传入下标对应的元素。下标支持从后向前获取,传入的下标 + * 与元素实际所在位置一致,当传入0时,则表示随机获取一个元素,如:
+ * {@code getWebElement("姓名", 1)}表示获取名称为“姓名”的列中的第1个元素
+ * {@code getWebElement("姓名", 0)}表示获取名称为“姓名”的列中在长度范围内随机一个元素
+ * {@code getWebElement("//*[@id='name']", -1)}表示获取“//*[@id='name']”对应列中的倒数第1个元素
+ * 注意,若使用了外链xml词语,则需要将词语写入到传参中,否则无法获取到相应的元素 * * @param name 列名称 - * @param length 需要返回列表事件的个数 - * @return 列表事件组 + * @param index 元素下标(即列表中对应的某一个元素) + * @param linkKey 外链的词语,若不存在,则不传入 + * @return 对应列指定的元素 */ - public List getRandomElements(String name, int length) { + public Element getElement(String name, int index, String...linkKey) { //获取元素信息,并判断元素是否存在,不存在则抛出异常 - ElementInformation element = nameToElementInformation(name); - if (element == null) { - throw new NoSuchElementException("不存在的定位方式:" + name); + ElementInformation elementInfo = nameToElementInformation(name, Arrays.asList(linkKey)); + if (elementInfo == null) { + throw new NoSuchElementException("不存在的元素:" + name); } - - // 判断传入的长度是否大于等于当前 - if (length >= elementMap.get(element).size()) { - return getAllElement(name); - } - - // 存储通过随机得到的数字 - ArrayList indexsList = new ArrayList(); - int randomLength = elementMap.get(element).size() + 1; - // 循环,随机获取下标数字 - for (int i = 0; i < length; i++) { - int randomIndex = 0; - // 循环,直到生成的随机数不在indexs中为止 - while (indexsList.contains(randomIndex = new Random().nextInt(randomLength))) { - } - indexsList.add(randomIndex); - } - - // 将indexsList转换成int[] - int[] indexs = new int[indexsList.size()]; - for (int i = 0; i < indexsList.size(); i++) { - indexs[i] = indexsList.get(i); - } - - return getElements(name, indexs); + + Element element = elementMap.get(elementInfo); + element.setElementIndex(index); + return element; } - /** - * 用于根据参数,求取elementMap中最多或最少列表的元素个数以及列表的名称 - * @param key 需要计算的最小值 - * @return 极值以及极值所在的列 - */ - private void findLimitColumn(ElementInformation key) { - //获取指向的元素列表的元素个数 - int size = elementMap.get(key).size(); - - //根据参数,判断获取的列是否为最大值所在的列,并对极值做进一步判断 - if (maxColumnSize < size) { - maxColumnNameList.clear(); - maxColumnSize = size; - maxColumnNameList.add(key.name); - } else if (maxColumnSize == size) { - maxColumnNameList.add(key.name); - } - - if (minColumnSize > size) { - minColumnNameList.clear(); - minColumnSize = size; - minColumnNameList.add(key.name); - } else if (minColumnSize == size) { - minColumnNameList.add(key.name); - } + @Override + ElementType setElementType() { + return ElementType.DATA_LIST_ELEMENT; } } 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 faead12..9a54f26 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/Element.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/Element.java @@ -3,8 +3,10 @@ package pres.auxiliary.work.selenium.element; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Random; import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; @@ -26,7 +28,12 @@ import pres.auxiliary.work.selenium.brower.AbstractBrower; * @since JDK 8 * */ -public class Element { +public class Element implements Cloneable { + /** + * 用于对文本进行分隔 + */ + private final String SPILT_SIGN = ","; + /** * 存储元素 */ @@ -46,7 +53,7 @@ public class Element { /** * 存储获取需要获取的元素下标 */ - private int elementIndex; + private String elementIndex = "0"; /** * 存储WebDriver对象,以查找相应元素 @@ -65,6 +72,11 @@ public class Element { */ private ElementType elementType; + /** + * 表示当前通过有效By对象能获取到的元素个数 + */ + private int size = -1; + /** * 用于存储元素查找等待时间,默认3秒 */ @@ -76,9 +88,9 @@ public class Element { private boolean isReplaceFind = false; /** - * 用于表示当前通过By对象能获取到的元素总个数 + * 控制是否允许在随机时出现第一个元素 */ - private int size = -1; + private boolean isRandomZero = true; /** * TODO 确定构造后添加注释 @@ -90,6 +102,17 @@ public class Element { this.name = name; this.elementType = elementType; } + + /** + * TODO 确定构造后添加注释 + */ + public Element(WebDriver driver, String name, ElementType elementType) { + super(); + //存储Driver对象 + this.driver = driver; + this.name = name; + this.elementType = elementType; + } /** * 用于根据存储的元素信息,在相应的页面中查找,并返回一个{@link WebElement}对象 @@ -101,10 +124,9 @@ public class Element { //若element为null,则对元素进行一次查找 if (element == null || isReplaceFind || isPageRefresh()) { - findElemen(); + findElement(); } - //返回相应的内容 return element; } @@ -168,21 +190,34 @@ public class Element { } /** - * 用于返回元素在列表中的下标 - * @return 元素下标 - */ - public int getElementIndex() { - return elementIndex; - } - - /** - * 用于设置元素的下标 + * 用于以数字方式设置元素的下标 * @param elementIndex 元素下标 */ public void setElementIndex(int elementIndex) { - this.elementIndex = elementIndex; + this.elementIndex = String.valueOf(elementIndex); isReplaceFind = true; } + + /** + * 用于以文本方式设置元素下标,该下标用于以文本的形式查找元素 + * @param elementIndex 元素下标 + */ + public void setElementIndex(String... elementIndexs) { + //拼接词语 + this.elementIndex = ""; + for (String elementIndex : elementIndexs) { + this.elementIndex += elementIndex; + } + isReplaceFind = true; + } + + /** + * 用于设置是否允许随机出元素组的第一个元素,默认为允许 + * @param isRandomZero 是否允许随机第一个元素 + */ + public void setRandomZero(boolean isRandomZero) { + this.isRandomZero = isRandomZero; + } /** * 用于返回元素所在的所有父窗体 @@ -261,7 +296,7 @@ public class Element { /** * 用于根据By对象集合,查找有效的By对象,并根据有效的By对象,查找相应的元素集合 */ - public void findElemen() { + public void findElement() { //遍历By集合,查找有效的By对象,若所有的By对象均无法查到页面元素,则直接抛出超时异常 for (int i = 0; i < byList.size(); i++) { //查找元素,若抛出异常,则移除该元素,保证有效的By对象在第一个元素上 @@ -284,26 +319,36 @@ public class Element { } //获取元素 - List elementList; + List elementList = getWebElementList(); + + //记录元素个数 + size = elementList.size(); + + //转换下标,若下标能转换成数字,则以数字方式获取下标,若不能则以文本的形式转换下标,根据下标返回元素 + try { + element = elementList.get(getIndex(elementList, Integer.valueOf(elementIndex))); + } catch (NumberFormatException e) { + element = elementList.get(getIndex(elementList, elementIndex)); + } + } + + private List getWebElementList() { //根据正确的By对象,通过Webdriver,查找到WebElement对象,存储 //由于在遍历byList时,无效的By对象被剔除,查找到By对象时会返回,故此时可直接使用第一个元素为有效的By对象 switch (elementType) { case COMMON_ELEMENT: case DATA_LIST_ELEMENT: - case SELECT_DATAS_ELEMENT: - elementList = driver.findElements(byList.get(0)); - break; - case SELECT_OPTION_ELEMENT: - elementList = new Select(driver.findElement(byList.get(0))).getOptions(); - break; + return driver.findElements(byList.get(0)); + case SELECT_ELEMENT: + //判断第一个元素的TagName是否为select,若是select,则按照下拉选项进行获取 + if (driver.findElement(byList.get(0)).getTagName().equals("select")) { + return new Select(driver.findElement(byList.get(0))).getOptions(); + } else { + return driver.findElements(byList.get(0)); + } default: throw new IllegalArgumentException("Unexpected value: " + elementType); } - - //记录获取的元素个数 - size = elementList.size(); - //获取相应下标的元素 - element = elementList.get(elementIndex); } /** @@ -360,7 +405,7 @@ public class Element { private WebElement findIframeElement() { //若elementList为null或其内无元素,则对元素进行一次查找 if (element == null) { - findElemen(); + findElement(); } //返回相应的内容 @@ -395,21 +440,79 @@ public class Element { } } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Element other = (Element) obj; - if (element == null) { - if (other.element != null) - return false; - } else if (!element.equals(other.element)) - return false; - return true; + /** + * 由于方法允许传入负数和特殊数字0为下标,并且下标的序号由1开始, + * 故可通过该方法对下标的含义进行转义,得到java能识别的下标 + * @param index 传入的下标 + * @param randomZero 标记是否可以随机出数字0 + * @return 可识别的下标 + * @throws NoSuchElementException 当元素无法查找到时抛出的异常 + */ + int getIndex(List elementList, int index) { + //存储传入的元素组长度 + int size = elementList.size(); + + //若当前元素组中只有一个元素,则直接返回0 + if (size == 1) { + return 0; + } + + //判断元素下标是否超出范围,由于可以传入负数,故需要使用绝对值 + if (Math.abs(index) > size) { + throw new NoSuchElementException("指定的选项值大于选项的最大值。选项总个数:" + size + ",指定项:" + index); + } + + //判断index的值,若大于0,则从前向后遍历,若小于0,则从后往前遍历,若等于0,则随机输入 + if (index > 0) { + //选择元素,正数的选项值从1开始,故需要减小1 + return index - 1; + } else if (index < 0) { + //选择元素,由于index为负数,则长度加上选项值即可得到需要选择的选项 + return size + index; + } else { + //为0,则进行随机选择,但需要判断是否允许随机出0(第一个元素) + int newindex = 0; + do { + newindex = new Random().nextInt(size); + } while(newindex == 0 && !isRandomZero); + + return newindex; + } } + /** + * 以文本形式查找元素,返回文本对应元素的下标 + * @param elementList 元素组 + * @param text 需要查找的文本 + * @return 文本对应元素的下标 + */ + int getIndex(List elementList, String text) { + //切分文本 + String[] keys = text.split(SPILT_SIGN); + //遍历元素组,若存在文本为所传文本的元素,则进行返回 + for (int index = 0; index < getSize(); index++) { + //遍历词语,将词语与元素的文本一一比对 + for(String key : keys) { + //若存在不包含在元素文本的词语,则结束当前循环,查找下一个 + if (elementList.get(index).getText().indexOf(key) < 0) { + break; + } + + //若所有的词语均包含在文本中,则直接返回当前下标 + return index; + } + } + + //若所有词语均不包含文本,则抛出异常 + throw new NoSuchElementException("无法找到指定文本的元素:" + text); + } + + @Override + public Element clone() { + try { + return (Element)super.clone(); + } catch (CloneNotSupportedException e) { + return this; + } + } } diff --git a/src/main/java/pres/auxiliary/work/selenium/element/ElementType.java b/src/main/java/pres/auxiliary/work/selenium/element/ElementType.java index 31323c5..79f04cb 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/ElementType.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/ElementType.java @@ -22,11 +22,7 @@ public enum ElementType { */ DATA_LIST_ELEMENT, /** - * 指向标准下拉框选择类型元素 + * 指向下拉框选择类型元素 */ - SELECT_OPTION_ELEMENT, - /** - * 指向列表型下拉框选择类型元素 - */ - SELECT_DATAS_ELEMENT; + SELECT_ELEMENT, } diff --git a/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java b/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java index 834957b..b68b98b 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java @@ -3,9 +3,9 @@ package pres.auxiliary.work.selenium.element; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; -import java.util.Random; +import java.util.List; -import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.TimeoutException; import pres.auxiliary.work.selenium.brower.AbstractBrower; import pres.auxiliary.work.selenium.xml.ByType; @@ -22,12 +22,17 @@ import pres.auxiliary.work.selenium.xml.ByType; * @since JDK 12 * */ -public class ListBy extends AbstractBy { +public abstract class ListBy extends AbstractBy { /** * 用于存储获取到的列表一列元素,key为列表名称,value为列表元素 */ LinkedHashMap elementMap = new LinkedHashMap<>(16); + /** + * 控制元素首行是否为 + */ + private boolean fristIsEmpty = false; + /** * 通过浏览器对象{@link AbstractBrower}进行构造 * @param brower {@link AbstractBrower}对象 @@ -49,28 +54,84 @@ public class ListBy extends AbstractBy { return nameList; } + /** + * 设置首个选项是否为不可选择的选项 + * @param fristIsEmpty 首个选项是否为不可选择 + */ + public void setFristIsEmpty(boolean fristIsEmpty) { + this.fristIsEmpty = fristIsEmpty; + } + + /** + * 用于清空存储的内容 + */ + public void clear() { + elementMap.clear(); + } + + /** + * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,添加元素。由于该方法不指定元素的定位 + * 方式,若传入的参数不是xml元素且非xpath路径或绝对css路径时,其识别效率较慢,建议在该情况下 + * 调用{@link #add(String, ByType)}方法,指定元素定位方法 + * @param name 元素在xml文件或者元素的定位内容 + * @see #add(String, ByType) + * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 + */ public void add(String name) { - add(new ElementInformation(name, null, ElementType.DATA_LIST_ELEMENT, null)); + add(new ElementInformation(name, null, setElementType(), null)); } + /** + * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,以及元素的定位方式,添加元素。 + * @param name 元素在xml文件或者元素的定位内容 + * @param byType 元素定位方式枚举对象({@link ByType}枚举) + * @see #add(String) + * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 + */ public void add(String name, ByType byType) { - add(new ElementInformation(name, byType, ElementType.DATA_LIST_ELEMENT, null)); + add(new ElementInformation(name, byType, setElementType(), null)); } + /** + * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,以及元素的定位方式,添加元素。 + * 该方法可对由xml文件读取的内容进行词语替换,根据 + * 传参中词语的顺序,对需要替换的词语进行替换 + * @param name 元素在xml文件或者元素的定位内容 + * @param byType 元素定位方式枚举对象({@link ByType}枚举) + * @param links 替换词语 + * @see #add(String, ByType) + * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 + */ public void add(String name, ByType byType, String... links) { - add(new ElementInformation(name, byType, ElementType.DATA_LIST_ELEMENT, Arrays.asList(links))); + add(new ElementInformation(name, byType, setElementType(), Arrays.asList(links))); } + /** + * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,添加元素。由于该方法不指定元素的定位 + * 方式,若传入的参数不是xml元素且非xpath路径或绝对css路径时,其识别效率较慢,建议在该情况下 + * 调用{@link #add(String, ByType)}方法,指定元素定位方法。该方法可对由xml文件读取的内容进 + * 行词语替换,根据传参中词语的顺序,对需要替换的词语进行替换 + * @param name 元素在xml文件或者元素的定位内容 + * @param links 替换词语 + * @see #add(String) + * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 + */ public void add(String name, String... links) { add(new ElementInformation(name, null, ElementType.DATA_LIST_ELEMENT, Arrays.asList(links))); } + /** + * 添加元素的底层方法 + * @param elementInformation 元素信息类对象 + */ void add(ElementInformation elementInformation) { Element element = new Element(brower, elementInformation.name, elementInformation.elementType); element.setWaitTime(getWaitTime(elementInformation.name)); element.setByList(recognitionElement(elementInformation)); + //若首元素为空元素或不允许选择的选项,则表示随机时不允许出现第一个选项 + element.setRandomZero(!fristIsEmpty); //构造元素的父层元素,若元素不存在窗体结构,则不进行构造 if (elementInformation.iframeList != null && elementInformation.iframeList.size() != 0) { @@ -81,11 +142,17 @@ public class ListBy extends AbstractBy { elementMap.put(elementInformation, element); } + /** + * 用于设置元素的类型,根据该类型来存储元素信息 + * @return + */ + abstract ElementType setElementType(); + /** * 根据元素名称反推元素信息类对象,用于根据列名称查找数据以及判断列是否存在,若列名不存在,则返回null * @return ElementInformation对象 */ - ElementInformation nameToElementInformation(String name, String...linkKey) { + ElementInformation nameToElementInformation(String name, List linkKey) { //遍历elementMap,若查找与name一致的名称,则结束循环并返回相应的ElementInformation对象 for (ElementInformation elementInfo : elementMap.keySet()) { if (elementInfo.name.equals(name) && elementInfo.linkKeyEquals(linkKey)) { @@ -95,66 +162,4 @@ public class ListBy extends AbstractBy { return null; } - - /** - * 该方法用于根据列名称,查找到相应的列,并返回与传入下标对应的元素。下标支持从后向前获取,传入的下标 - * 与元素实际所在位置一致,当传入0时,则表示随机获取一个元素,如:
- * {@code getWebElement("姓名", 1)}表示获取名称为“姓名”的列中的第1个元素
- * {@code getWebElement("姓名", 0)}表示获取名称为“姓名”的列中在长度范围内随机一个元素
- * {@code getWebElement("//*[@id='name']", -1)}表示获取“//*[@id='name']”对应列中的倒数第1个元素
- * 注意,若使用了外链xml词语,则需要将词语写入到传参中,否则无法获取到相应的元素 - * - * @param name 列名称 - * @param index 元素下标(即列表中对应的某一个元素) - * @param linkKey 外链的词语,若不存在,则不传入 - * @return 对应列指定的元素 - * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 - */ - public Element getElement(String name, int index, String...linkKey) { - //获取元素信息,并判断元素是否存在,不存在则抛出异常 - ElementInformation elementInfo = nameToElementInformation(name, linkKey); - if (elementInfo == null) { - throw new NoSuchElementException("不存在的定位方式:" + name); - } - - // 转义下标 -// index = getIndex(elementMap.get(elementInfo).getSize(), index, true); - Element element = elementMap.get(elementInfo); - element.setElementIndex(index); - // 转义下标后,返回对应的元素 - return element; - } - - /** - * 由于方法允许传入负数和特殊数字0为下标,并且下标的序号由1开始, - * 故可通过该方法对下标的含义进行转义,得到java能识别的下标 - * @param length 元素的个数 - * @param index 传入的下标 - * @param randomZero 标记是否可以随机出数字0 - * @return 可识别的下标 - * @throws NoSuchElementException 当元素无法查找到时抛出的异常 - */ - int getIndex(int length, int index, boolean randomZero) { - //判断元素下标是否超出范围,由于可以传入负数,故需要使用绝对值 - 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,则进行随机选择,但需要判断是否允许随机出0(第一个元素) - int newindex = 0; - do { - newindex = new Random().nextInt(length); - } while(newindex == 0 && !randomZero); - - return newindex; - } - } } diff --git a/src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java b/src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java new file mode 100644 index 0000000..854c62d --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java @@ -0,0 +1,123 @@ +package pres.auxiliary.work.selenium.element; + +import java.util.List; + +import org.openqa.selenium.NoSuchElementException; + +import pres.auxiliary.work.selenium.brower.AbstractBrower; + +/** + *

文件名:SelectBy.java

+ *

用途: + * 提供获取下拉框中选项元素的方法,支持标准型下拉框选项(由select与option标签组成的下拉框)以及 + * 非标准型下拉框选项(由普通的div、li等元素组成的选项),并支持根据关键词查找选项。需要注意的是, + * 标准下拉选项和非标准下拉选项需要传入的参数不同,例如,
+ * 标准下拉框:
+ * <select id='test'>
+ *  <option>男</option>
+ *  <option>女</option>
+ *  <option>其他</option>
+ * </select>
+ * 对于该标准的下拉框选项,只需要定位到//select[@id='test'],得到其WebElement对象即可,但对于非标准的下拉框其下拉框是由input和button标签构成:
+ * <div>
+ *  <span><input/></span>
+ *  <span><button/></span>
+ * </div>
+ * 点击button对应的按钮后,其下也能弹出选项,但其选项是由div标签写入text构成:
+ * <div id='test'>
+ *  <div>男</div>
+ *  <div>女</div>
+ *  <div>其他</div>
+ * </div>
+ * 对于这种非标准的下拉框选项,需要传入选项所在的所有div标签对应的WebElement元素,在上例,则需要定位到//div[@id='test']/div, + * 注意,末尾的div不指定数字,则可以代表整个选项。
+ *

+ *

编码时间:2020年5月24日下午3:30:00

+ *

修改时间:2020年5月24日下午3:30:00

+ * @author 彭宇琦 + * @version Ver1.0 + * @since JDK 12 + * + */ +public class SelectBy extends ListBy { + /** + * 用于指向存储的元素名称 + */ + private String name; + /** + * 用于指向存储的外链词语 + */ + private List linkKey; + + /** + * 通过浏览器对象{@link AbstractBrower}进行构造 + * + * @param brower {@link AbstractBrower}对象 + */ + public SelectBy(AbstractBrower brower) { + super(brower); + } + + @Override + void add(ElementInformation elementInformation) { + //存储元素信息 + name = elementInformation.name; + linkKey = elementInformation.linkKeyList; + + //清空父类中的链表,重新插入数据 + clear(); + + super.add(elementInformation); + } + + /** + * 该方法用于根据列名称,查找到相应的列,并返回与传入下标对应的元素。下标支持从后向前获取,传入的下标 + * 与元素实际所在位置一致,当传入0时,则表示随机获取一个元素,如:
+ * {@code getWebElement(1)}表示获取第1个选项
+ * {@code getWebElement(0)}表示获取随机一个选项
+ * {@code getWebElement(-1)}表示获取倒数第1个选项
+ * + * @param index 元素下标(即列表中对应的某一个元素) + * @return 对应的选项 + * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 + */ + public Element getElement(int index) { + Element element = findElement(); + element.setElementIndex(index); + return element; + } + + /** + * 根据关键词组查找选项,并返回选项元素,当传入的元素名称不存在时,则抛出NoSuchElementException异常; + * 当查询到有多个包含关键词的选项时,则选择第一个选项
+ * 注意,当传入多个关键词时其选项需要全部满足才会返回相应的选项。 + * + * @param keys 查询选项的关键词组 + * @return 相应的选项元素 + * @throws NoSuchElementException 查找的选项不存在时抛出的异常 + */ + public Element getElement(String...keys) { + Element element = findElement(); + element.setElementIndex(keys); + return element; + } + + /** + * 用于查找相应的元素 + * @return 需要查找的元素 + */ + private Element findElement() { + //获取元素信息,并判断元素是否存在,不存在则抛出异常 + ElementInformation elementInfo = nameToElementInformation(name, linkKey); + if (elementInfo == null) { + throw new NoSuchElementException("不存在的定位方式:" + name); + } + + return elementMap.get(elementInfo); + } + + @Override + ElementType setElementType() { + return ElementType.SELECT_ELEMENT; + } +} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/old/UnrecognizableLocationModeException.java b/src/main/java/pres/auxiliary/work/selenium/element/UnrecognizableLocationModeException.java similarity index 95% rename from src/main/java/pres/auxiliary/work/selenium/element/old/UnrecognizableLocationModeException.java rename to src/main/java/pres/auxiliary/work/selenium/element/UnrecognizableLocationModeException.java index b1b9964..a46ac37 100644 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/UnrecognizableLocationModeException.java +++ b/src/main/java/pres/auxiliary/work/selenium/element/UnrecognizableLocationModeException.java @@ -1,4 +1,4 @@ -package pres.auxiliary.work.selenium.element.old; +package pres.auxiliary.work.selenium.element; /** *

文件名:UnrecognizableLocationModeException.java

diff --git a/src/main/java/pres/auxiliary/work/selenium/element/old/AbstractBy.java b/src/main/java/pres/auxiliary/work/selenium/element/old/AbstractBy.java deleted file mode 100644 index ad368a4..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/AbstractBy.java +++ /dev/null @@ -1,721 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.openqa.selenium.By; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.WebDriver; - -import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.brower.Page; -import pres.auxiliary.work.selenium.xml.ByType; -import pres.auxiliary.work.selenium.xml.ReadXml; - -/** - *

文件名:AbstractElement.java

- *

用途:

- *

- *   对辅助化测试工具selenium的获取元素代码进行的二次封装,通过类中提供的方法以及配合相应存储元素的
- * xml文件,以更简便的方式对页面元素进行获取,减少编程时的代码量。
- * 

- *

编码时间:2020年4月25日 下午4:18:37

- *

修改时间:2020年4月25日 下午4:18:37

- * @author 彭宇琦 - * @version Ver1.0 - * @since JDK 12 - */ -public abstract class AbstractBy { - /** - * 用于存储浏览器的WebDriver对象,设为静态,保证所有的子类只使用一个WebDriver对象,以避免造成WebDriver不正确导致的Bug - */ - WebDriver driver; - /** - * 用于指向存储控件定位方式的xml文件 - */ - ReadXml xml; - - /** - * 用于存储浏览器对象 - */ - AbstractBrower brower; - /** - * 存储单个控件的等待时间 - */ - private HashMap controlWaitTime = new HashMap(); - /** - * 用于存储当前浏览器窗口的Handles值 - */ - private String browserHandles; - /** - * 存储当前定位的窗体层级,由于多个子类之间需要相互通信,故此处标记为static - */ - private static ArrayList iframeNameList = new ArrayList<>(); - - /** - * 用于存储元素通用的等待时间,默认5秒 - */ - private long waitTime = 5; - - /** - * 控制是否自动切换窗体,由于通过Event类调用时会构造另一个事件类,但每个类都应共享一个开关,故需要加上static - */ - boolean isAutoSwitchIframe = true; - - /** - * 通过{@link WebDriver}对象进行构造 - * - * @param driver {@link WebDriver}对象 - */ - public AbstractBy(WebDriver driver) { - this.driver = driver; - browserHandles = this.driver.getWindowHandle(); - } - - /** - * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中 - * @param brower {@link AbstractBy}对象 - */ - public AbstractBy(AbstractBy by) { - this.brower = by.brower; - this.driver = by.driver; - this.xml = by.xml; - } - - /** - * 通过浏览器对象{@link AbstractBrower}进行构造 - * @param brower {@link AbstractBrower}对象 - */ - public AbstractBy(AbstractBrower brower) { - this.brower = brower; - this.driver = brower.getDriver(); - } - - /** - * 用于设置事件等待时间,默认时间为5秒 - * - * @param waitTime 事件等待时间 - */ - public void setWaitTime(long waitTime) { - this.waitTime = waitTime; - } - - /** - * 用于对符合正则表达式的控件名称设置等待时间 - * - * @param regex 正则表达式 - * @param waitTime 等待时间 - */ - public void setContorlWaitTime(String regex, long waitTime) { - controlWaitTime.put(regex, waitTime); - } - - /** - * 设置是否自动切换窗体 - * @param switchIframe 是否自动切换窗体 - */ - public void setAutoSwitchIframe(boolean isAutoSwitchIframe) { - this.isAutoSwitchIframe = isAutoSwitchIframe; - } - - /** - * 该方法用于返回浏览器的WebDriver对象 - * - * @return 浏览器的WebDriver对象 - */ - public WebDriver getDriver() { - return driver; - } - - /** - * 用于设置指向存储元素定位方式的xml文件对象,并根据传参,判断窗体是否需要回到顶层 - * @param xmlFile 存储元素定位方式的xml文件对象 - * @param isBreakRootFrame 是否需要将窗体切回到顶层 - */ - public void setXmlFile(File xmlFile, boolean isBreakRootFrame) { - if (xml == null) { - xml = new ReadXml(xmlFile); - } else { - xml.setXmlPath(xmlFile); - } - - if (isBreakRootFrame) { - switchRootFrame(); - } - } - - /** - * 该方法用于将窗体切回顶层,当本身是在最顶层时,则该方法将使用无效 - */ - public void switchRootFrame() { - //切换窗口至顶层 - driver.switchTo().defaultContent(); - //清空iframeNameList中的内容 - iframeNameList.clear(); - } - - /** - * 该方法用于将窗体切换到上一层(父层)。若当前层只有一层,则调用方法后切回顶层; - * 若当前层为最顶层时,则该方法将使用无效 - */ - public void switchParentFrame() { - //若iframeNameList大于1层,则向上切换窗体 - if (iframeNameList.size() > 1) { - driver.switchTo().parentFrame(); - iframeNameList.remove(iframeNameList.size() - 1); - } else if (iframeNameList.size() == 1) { - //若iframeNameList等于1层,则调用切换至顶层的方法 - switchRootFrame(); - } else { - //若iframeNameList小于1层,则不做操作 - return; - } - } - - /** - *

- * 通过传入在xml文件中的控件名称,到类中指向的xml文件中查找控件 - * 名称对应的定位方式,或直接传入xpath与css定位方式, - * 根据定位方式对相应的窗体进行定位。当传入的窗体为当前窗体的前层(父层)窗体时, - * 通过该方法将调用切换父层的方法,将窗体切换到父层上,例如:
- * 当前存在f1, f2, f3, f4四层窗体,则调用方法:
{@code - * switchFrame("f2"); - * }
- * 此时窗体将回到f2层,无需再从顶层开始向下切换。 - *

- *

- * 若传入该方法的名称存在于xml文件中,且该元素存在父窗体时,调用 - * 该方法会从xml文件中获取相应所有父窗体,并对相应的父窗体进行切换, - * 从而达到无须切换父窗体的目的,例如,存在以下xml文件片段:

{@code
-	 * ...
-	 * 
-	 * 	
-	 * 
-	 * ...
-	 * }
- * 当调用该方法:
{@code - * switchFrame("f3"); - * }
- * 时,则会先将窗体从f1开始切换,至窗体f2,最后再切换为窗体f3 - *

- * - * @param name 窗体的名称或xpath与css定位方式 - */ - public void switchFrame(String name) { - switchFrame(new ElementInformation(name, null, ElementType.COMMON_ELEMENT)); - } - - /** - * 通过传入在xml文件中的控件名称,到类中指向的xml文件中查找控件 - * 名称对应的定位方式,或直接传入xpath与css定位方式, - * 根据定位方式对相应的窗体进行定位。通过该方法可以指定使用的定位类型,一般用于 - * 传入非xml文件的元素,也可用于指定xml文件元素的定位方式,其他说明参见{@link #switchFrame(String)} - * @param name 窗体的名称或xpath与css定位方式 - * @param byType 元素的定位方式 - * @see #switchFrame(String) - */ - public void switchFrame(String name, ByType byType) { - switchFrame(new ElementInformation(name, byType, ElementType.COMMON_ELEMENT)); - } - - /** - * 切换窗体的底层方法 - * @param elementInformation 元素信息类对象 - */ - private void switchFrame(ElementInformation elementInformation) { - List nameList = new ArrayList(); - //判断传入的元素名称是否存在于xml文件中,若存在,则将该元素的父层名称存储至nameList - if (isXmlElement(elementInformation.name) && isAutoSwitchIframe) { - nameList.addAll(getParentFrameName(elementInformation.name)); - } - - //调用切换窗体的方法 - switchFrame(nameList); - - driver.switchTo().frame(driver.findElement(recognitionElement(elementInformation))); - //切换窗体 - iframeNameList.add(elementInformation.name); - } - - /** - * 通过传入在xml文件中的控件名称,到类中指向的xml文件中查找控件 - * 名称对应的定位方式,或直接传入xpath与css定位方式, - * 根据定位方式对相应的窗体进行定位。当传入的窗体为当前窗体的前层(父层)窗体时, - * 通过该方法将调用切换父层的方法,将窗体切换到父层上,例如:
- * 当前存在f1, f2, f3, f4四层窗体,则调用方法:
{@code
-	 * List nameList = new ArrayList();
-	 * nameList.add("f2");
-	 * switchFrame(nameList);
-	 * }
- * 此时窗体将回到f2层,无需再从顶层开始向下切换。
- * 注意: - *
    - *
  1. 窗体的切换按照从前向后的顺序进行切换,切换顺序不能相反
  2. - *
  3. 传入的参数若在xml文件中且存在父窗体,调用该方法也不会对窗体进行切换
  4. - *
- * - * @param elementInformationList 存储窗体的名称或xpath与css定位方式的List集合 - */ - void switchFrame(List frameNameList) { - //若传参为空,则切回到顶层 - if (frameNameList.isEmpty()) { - switchRootFrame(); - return; - } - - //若原窗体和需要切换的窗体的最后一个元素一致,则无需切换 - if (!iframeNameList.isEmpty() && frameNameList.get(frameNameList.size() - 1).equals(iframeNameList.get(iframeNameList.size() - 1))) { - return; - } - - //若需要切换的窗体第一层均不在iframeNameList时,则需要切回到顶层 - if (!iframeNameList.contains(frameNameList.get(0))) { - switchRootFrame(); - } - - //若不为空,则列表进行切换 - frameNameList.forEach(frameName -> { - //判断name指向的窗体是否在iframeNameList中,若存在,则向上切换父层,直到切换到name指向的窗体;若不存在,则直接切换,并添加窗体名称 - if (iframeNameList.contains(frameName)) { - //获取name窗体在iframeNameList中的位置 - int index = iframeNameList.indexOf(frameName); - //获取需要向上切换窗体的次数,公式为推断出来 - int count = iframeNameList.size() - index - 1; - for (int i = 0; i < count; i++) { - switchParentFrame(); - } - } else { - //切换窗体 - driver.switchTo().frame(driver.findElement(recognitionElement(new ElementInformation(frameName, null, ElementType.COMMON_ELEMENT)))); - iframeNameList.add(frameName); - } - }); - } - - /** - * 该方法用于将窗口切换回最原始的窗口上。 - */ - public void switchOldWindow() { - driver.switchTo().window(browserHandles); - } - - /** - * 该方法可根据控件名称,之后对比每一个弹窗,若某一个弹窗上存在元素名对应的元素,则返回相应 - * 窗口的WebDriver对象,若无新窗口,则返回当前的窗口的WebDriver对象。当所有的窗体都 - * 不包含相应的元素时,则抛出NoSuchWindownException异常 - * - * @param controlName 控件名称 - * @throws NoSuchWindownException 窗口未找到时抛出的异常 - */ - public void switchWindow(String controlName) { - Set handles = driver.getWindowHandles(); - // 判断是否只存在一个窗体,若只存在一个,则直接返回当前浏览器的WebDriver对象 - if (handles.size() == 1) { - return; - } - - List pageList = new ArrayList<>(); - //若浏览器对象存在,则将已打开的页面的handle进行存储,优先遍历新打开的标签 - if (brower != null) { - pageList.addAll(brower.getOpenPage()); - } - - //移除已打开的窗口 - handles.removeAll(pageList.stream().map(page -> { - return page.getHandle(); - }).collect(Collectors.toList())); - - // 循环,获取所有的页面handle - for (String newWinHandle : handles) { - //切换窗口,并查找元素是否在窗口上,若存在,则结束切换 - driver.switchTo().window(newWinHandle); - try { - //构造信息,因为在构造过程中会判断元素是否存在, - recognitionElement(new ElementInformation(controlName, null, ElementType.COMMON_ELEMENT)); - return; - }catch (Exception e) { - continue; - } - } - - //若不在新打开的窗口上,则遍历已打开的窗口 - if (brower != null) { - for (Page page : pageList) { - //切换窗口,并查找元素是否在窗口上,若存在,则结束切换 - brower.switchWindow(page); - try { - recognitionElement(new ElementInformation(controlName, null, ElementType.COMMON_ELEMENT)); - return; - }catch (Exception e) { - continue; - } - } - } - - //若遍历所有窗口后均未能查到元素,则抛出异常 - throw new NoSuchWindownException("未找到存在元素" + controlName + "所在的窗体"); - } - - /** - * 定位到弹框上并且点击确定按钮,并返回弹框上的文本 - * - * @return 弹框上的文本 - */ - public String alertAccept() { - String text = alertGetText(); - driver.switchTo().alert().accept(); - - return text; - - } - - /** - * 定位到弹框上并且点击取消按钮,并返回弹框上的文本 - * - * @return 弹框上的文本 - */ - public String alertDimiss() { - String text = alertGetText(); - driver.switchTo().alert().dismiss(); - - return text; - } - - /** - * 定位到弹框上并且在其文本框中输入信息 - * - * @param content 需要输入的信息 - * @return 弹框上的文本 - */ - public String alertInput(String content) { - String text = alertGetText(); - driver.switchTo().alert().sendKeys(""); - - return text; - } - - /** - * 获取弹框上的文本 - * - * @return 弹框上的文本 - */ - public String alertGetText() { - return driver.switchTo().alert().getText(); - } - - /** - *

- * 用于根据传入的控件名称或定位方式,对控件在页面上定位,返回其WebElement对象。形参可以传入在xml文件中元素的名称, - * 亦可以传入页面元素的定位方式,但目前识别只支持xpath和css两种方式。 - * 该方法获取的是一组元素,可用于对列表元素事件中。 - *

- *

- * 元素识别判断方式按照以下步骤进行:
- * 1.先对xml文件进行扫描,若存在该元素对应的标签,则读取xml文件的定位方式,并识别有效的定位方式一一匹配,直到正确为止;
- * 2.若在xml文件中查找不到该元素,则按照xpath和css的规则进行匹配,直到判断出该元素的定位方式位置;
- * 3.若仍找不到元素,则抛出UnrecognizableLocationModeException - *

- * - * @param name 元素名称或元素的定位方式 - * @return 返回页面一组元素WebElement的对象 - * @throws TimeoutException 元素在指定时间内未查找到时,抛出的异常 - * @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常 - */ - By recognitionElement(ElementInformation elementInformation) { - By by; - if (isXmlElement(elementInformation.name)) { - //若指定了xml文件,且传入的元素名称存在与xml文件中,则判断元素相应的定位方式及定位内容 - by = recognitionXmlElement(elementInformation); - } else { - //若未指定xml文件,或者在xml文件中无法查到相应的元素时,则将name的值赋给value,且根据value判断相应定位方式 - by = recognitionCommonElement(elementInformation); - } - -// return driver.findElements(by); - return by; - } - - /** - * 获取普通元素的By对象 - * @param elementInformation 元素信息类对象 - * @return 元素信息指向的By对象 - */ - private By recognitionCommonElement(ElementInformation elementInformation) { - //判断传入的ByType对象是否为null - if (elementInformation.byType == null) { - return judgeCommonElementBy(elementInformation.name); - } else { - By by = getBy(elementInformation.name, elementInformation.byType); - if (isExistElement(by, getWaitTime(elementInformation.name))) - return by; - else - throw new TimeoutException("普通元素定位方式类型无法识别:" + by); - } - } - - /** - * 获取xml文件内元素的By对象 - * @param elementInformation 元素信息类对象 - * @return 元素信息指向的By对象 - */ - private By recognitionXmlElement(ElementInformation elementInformation) { - //判断传入的ByType对象是否为null - if (elementInformation.byType == null) { - return judgeXmlElementBy(elementInformation.name, elementInformation.linkKeyList); - } else { - By by = xml.getBy(elementInformation.name, elementInformation.byType, elementInformation.linkKeyList); - if (isExistElement(by, getWaitTime(elementInformation.name))) - return by; - else - throw new TimeoutException("普通元素定位方式类型无法识别:" + by); - } - } - - /** - * 用于返回控件的等待时间,若设置单个控件的等待时间(使用{@link #setContorlWaitTime(String, long)}方法设置), - * 则返回设置的控件等待时间;若未设置单个控件的等待时间,则返回设置的通用等待时间(使用{@link #setWaitTime(long)}方法) - * ;若未对通用时间进行设置,则返回默认时间({@link #waitTime}) - * @param name 控件名称 - * @return 相应控件的等待时间 - * @see #setContorlWaitTime(String, long) - * @see #setWaitTime(long) - */ - long getWaitTime(String name) { - for (String regex : controlWaitTime.keySet()) { - if (Pattern.compile(regex).matcher(name).matches()) { - return controlWaitTime.get(regex); - } - } - - return waitTime; - } - - /** - * 用于获取元素在xml文件中所有的父窗体,并以集合的形式返回,存储的顺序为父窗体在前,子窗体在后,若当前元素没有窗体, - * 则集合的长度为0 - * @param name 元素在xml文件中的名称 - * @return 元素在xml文件中所有的父窗体集合 - */ - List getParentFrameName(String name) { - //存储获取到的父层窗体名称 - List nameList = new ArrayList(); - - //获取元素所在窗体的名称 - String iframeName = xml.getIframeName(name); - //循环,判断窗体是否存在(方法返回不为空),若存在,则再将父窗体进行存储 - while(!iframeName.isEmpty()) { - //存储窗体 - nameList.add(iframeName); - //再以当前窗体的名称再次获取该窗体的父窗体 - iframeName = xml.getIframeName(iframeName); - } - - //将nameList的内容倒序,保证父窗体在子窗体之前 - Collections.reverse(nameList); - - return nameList; - } - - /** - * 用于根据传入的参数,识别非xml文件内的元素定位方式。 - * 该方法能快速识别xpath定位方式以及绝对css定位方式,若不是以上两种定位方式 - * 则会遍历所有的定位方式,此时会降低运行速度,建议在不是以上两种定位方式的 - * 情况下,直接指定元素的定位方式,以提高效率 - */ - By judgeCommonElementBy(String value) { - // 如果抛出元素名称查找不到的的异常,则对应匹配xpath和绝对css路径两种定位方式 - // 匹配xpath定位,判定方法,判断text的第一个字符是否是“/” - //由于是识别普通元素,非xml元素其value就是元素的名称name, 故获取等待时间时可直接将value传入 - if (value.indexOf("/") == 0) { - //在页面中查找元素,若元素能找到,则结束查找 - By by = getBy(value, ByType.XPATH); - if (isExistElement(by, getWaitTime(value))) { - return by; - } - } else if (value.indexOf("html") == 0) { - //在页面中查找元素,若元素能找到,则结束查找 - By by = getBy(value, ByType.CSS); - if (isExistElement(by, getWaitTime(value))) { - return by; - } - } - - //若元素无法识别,则将所有的定位类型(排除xpath类型)与之进行对比,直到在页面上找到元素为止 - for(ByType type : ByType.values()) { - if (type == ByType.XPATH) { - continue; - } - - By by = getBy(value, type); - - //在页面中查找元素,若元素能找到,则结束查找 - if (isExistElement(by, getWaitTime(value))) { - return by; - } - } - - //若所有的定位方式均无法查找到元素,则抛出异常 - throw new TimeoutException("普通元素定位方式类型无法识别:" + value); - } - - /** - * 用于设置xml文件内的元素的定位方式及定位内容 - */ - By judgeXmlElementBy(String name, List linkList) { - By by; - // 循环,逐个在页面上配对有效的标签对应的定位方式 - for (ByType mode : xml.getElementMode(name)) { - by = getBy(xml.getValue(name, mode, linkList), mode); - - //若元素能被找到,则返回相应的By对象,若未找到,则再次循环 - if (isExistElement(by, getWaitTime(name))) { - return by; - } else { - continue; - } - } - - // 若循环结束后仍未能找到该元素,则抛出异常 - throw new TimeoutException("xml文件内元素“" + name + "”无法查找,请核对xml文件:" + xml.getXmlFile().getName() + "\n文件路径:" + xml.getXmlFile().getAbsolutePath()); - } - - /** - * 根据元素的参数,返回元素的By对象 - * @return 元素的By对象 - */ - By getBy(String value, ByType byType) { - //根据元素的定位方式,对定位内容进行选择,返回相应的By对象 - switch (byType) { - case XPATH: - return By.xpath(value); - case CLASSNAME: - return By.className(value); - case CSS: - return By.cssSelector(value); - case ID: - return By.id(value); - case LINKTEXT: - return By.linkText(value); - case NAME: - return By.name(value); - case TAGNAME: - return By.tagName(value); - default: - throw new UnrecognizableLocationModeException("无法识别的定位类型:" + byType); - } - } - - /** - * 根据页面的等待时间和元素定位方式,在页面上查找相应的元素,返回是否能查到元素 - * @param time 控件等待时间 - * @param by 元素定位方式 - * @return 是否能查找到的元素 - */ - abstract boolean isExistElement(By by, long waitTime); - - /** - * 用于判断元素是否为xml文件内的元素 - * @param name 元素名称 - * @return 是否为xml文件内的元素 - */ - boolean isXmlElement(String name) { - return (xml != null && xml.isElement(name)); - } - - /** - *

文件名:AbstractElement.java

- *

用途: - * 存储获取元素时的信息 - *

- *

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

- *

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

- * @author 彭宇琦 - * @version Ver1.1 - * @since JDK 1.8 - * - */ - class ElementInformation { - /** - * 存储元素的名称或定位内容 - */ - public String name; - /** - * 存储元素的定位方式 - */ - public ByType byType; - /** - * 用于标记元素的类型 - */ - public ElementType elementType; - /** - * - */ - public ArrayList linkKeyList = new ArrayList<>(); - /** - * 初始化信息 - * @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) { - this.name = name; - this.byType = byType; - } - - /** - * 初始化信息 - * @param name 元素名称或定位内容 - * @param byType 元素定位 - * @param elementType 元素类型 - * @param links 元素外链信息 - */ - public ElementInformation(String name, ByType byType, ElementType elementType, String...links) { - this.name = name; - this.byType = byType; - - linkKeyList.addAll(Arrays.asList(links)); - } - - @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/old/CommonBy.java b/src/main/java/pres/auxiliary/work/selenium/element/old/CommonBy.java deleted file mode 100644 index 68a4a9f..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/CommonBy.java +++ /dev/null @@ -1,127 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.WebDriverWait; - -import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.xml.ByType; - -/** - *

文件名:CommonElement.java

- *

用途: - * 提供在辅助化测试中,对页面单一元素获取的方法。类中获取元素的方法兼容传入定位方式对 - * 元素进行查找,建议使用xml对页面元素的定位方式进行存储,以简化编码时的代码量,也便于 - * 对代码的维护 - *

- *

编码时间:2020年4月26日下午10:34:55

- *

修改时间:2020年4月26日下午10:34:55

- * @author 彭宇琦 - * @version Ver1.0 - * @since JDK 12 - * - */ -public class CommonBy extends AbstractBy { - /** - * 构造对象并存储浏览器的WebDriver对象 - * - * @param driver 浏览器的WebDriver对象 - */ - public CommonBy(WebDriver driver) { - super(driver); - } - - /** - * 通过浏览器对象{@link AbstractBrower}进行构造 - * @param brower {@link AbstractBrower}对象 - */ - public CommonBy(AbstractBrower brower) { - super(brower); - } - - /** - * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中 - * @param brower {@link AbstractBy}对象 - */ - public CommonBy(AbstractBy by) { - super(by); - } - - /** - * 用于根据xml文件中元素的名称,返回对应的{@link Element}对象。该方法亦可传入元素 - * 定位内容,通过遍历所有的定位方式,在页面上查找元素,来获取元素的WebElement对象。 - * 建议传入的定位内容为xpath路径或绝对的css路径,若非这两路径,则在识别元素时会很慢,降低 - * 程序运行速度。若非xml文件中的元素,且不是xpath路径或绝对的css路径,建议使用{@link #getElement(String, ByType)}方法 - * @param name 元素的名称或元素定位内容 - * @return {@link Element}对象 - */ - public Element getElement(String name) { - return getElement(new ElementInformation(name, null, ElementType.COMMON_ELEMENT)); - } - - /** - * 用于根据xml文件中元素的名称,与定位方式,返回对应的{@link Element}对象。该方法亦可传入元素 - * 定位内容,并根据定位方式,对页面数据进行查找 - * @param name 元素的名称或元素定位内容 - * @return {@link Element}对象 - */ - public Element getElement(String name, ByType byType) { - return getElement(new ElementInformation(name, byType, ElementType.COMMON_ELEMENT)); - } - - /** - * 用于根据xml文件中元素的名称,与定位方式,返回对应的{@link Element}对象。该方法亦可传入元素 - * 定位内容,并根据定位方式,对页面数据进行查找。该方法可对由xml文件读取的内容进行词语替换,根据 - * 传参中词语的顺序,对需要替换的词语进行替换 - * @param name 元素名称或定位方式内容 - * @param byType 元素定位方式 - * @param links 替换词语 - * @return {@link Element}对象 - */ - public Element getElement(String name, ByType byType, String...links) { - return getElement(new ElementInformation(name, byType, ElementType.COMMON_ELEMENT, links)); - } - - /** - * 用于根据xml文件中元素的名称,返回对应的{@link Element}对象。该方法亦可传入元素 - * 定位内容,通过遍历所有的定位方式,在页面上查找元素,来获取元素的WebElement对象。 - * 建议传入的定位内容为xpath路径或绝对的css路径,若非这两路径,则在识别元素时会很慢,降低 - * 程序运行速度。若非xml文件中的元素,且不是xpath路径或绝对的css路径,建议使用{@link #getElement(String, ByType, String...)}方法 - * @param name 元素的名称或元素定位内容 - * @param links 替换词语 - * @return {@link Element}对象 - */ - public Element getElement(String name, String...links) { - return getElement(name, null, links); - } - - /** - * 获取元素的底层方法 - * @param elementInformation 元素信息类对象 - * @return WebElement对象 - */ - private Element getElement(ElementInformation elementInformation) { - //判断传入的元素是否在xml文件中,若存在再判断是否自动切换窗体,若需要,则获取元素的所有父窗体并进行切换 - if (xml != null && xml.isElement(elementInformation.name) && isAutoSwitchIframe) { - switchFrame(getParentFrameName(elementInformation.name)); - } - - return new Element(driver, ElementType.COMMON_ELEMENT, recognitionElement(elementInformation), elementInformation.name); - } - - @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; - }); - /* - 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/old/DataListBy.java b/src/main/java/pres/auxiliary/work/selenium/element/old/DataListBy.java deleted file mode 100644 index 1cab76e..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/DataListBy.java +++ /dev/null @@ -1,267 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.WebDriverWait; - -import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.xml.ByType; - -/** - *

文件名:DataListElement.java

- *

用途: - * 提供在辅助化测试中,对页面列表元素获取的方法,并对列表元素的获取做了优化。 - * 类中获取元素的方法兼容传入定位方式对元素进行查找,建议使用xml对页面元素的 - * 定位方式进行存储,以简化编码时的代码量,也便于对代码的维护。 - *

- *

编码时间:2020年4月29日下午6:18:46

- *

修改时间:2020年4月29日下午6:18:46

- * @author 彭宇琦 - * @version Ver1.0 - * @since JDK 12 - */ -public class DataListBy extends ListBy { - /** - * 存储获取到的元素列表中最多元素列的元素个数 - */ - private int maxColumnSize = -1; - /** - * 存储获取到的元素列表中最多元素列的名称 - */ - private ArrayList maxColumnNameList = new ArrayList<>(); - /** - * 存储获取到的元素列表中最少元素列的元素个数 - */ - private int minColumnSize = Integer.MAX_VALUE; - /** - * 存储获取到的元素列表中最少元素列的名称 - */ - private ArrayList minColumnNameList = new ArrayList<>(); - - /** - * 用于判断列表的第一行元素是否为标题元素 - */ - boolean isFristRowTitle = false; - - /** - * 用于存储元素列累计的个数 - */ -// private HashMap elementSizeMap = new HashMap(16); - - /** - * 用于存储是否开始累加列表元素的个数 - */ -// private boolean isStartAddSize = false; - - /** - * 通过浏览器对象{@link AbstractBrower}进行构造 - * @param brower {@link AbstractBrower}对象 - */ - public DataListBy(AbstractBrower brower) { - super(brower); - } - - /** - * 构造对象并存储浏览器的{@link WebDriver}对象 - * - * @param driver 浏览器的{@link WebDriver}对象 - */ - public DataListBy(WebDriver driver) { - super(driver); - } - - /** - * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中 - * @param brower {@link AbstractBy}对象 - */ - public DataListBy(AbstractBy by) { - super(by); - } - - /** - * 用于设置首行元素是否为标题元素 - * @param isFristRowTitle 首行是否为标题元素 - */ - public void setFristRowTitle(boolean isFristRowTitle) { - this.isFristRowTitle = isFristRowTitle; - } - - /** - * 用于设置是否开始计算元素个数 - * @param isStartAddSize 是否开始计算元素个数 - */ - /* - public void setStartAddSize(boolean isStartAddSize) { - this.isStartAddSize = isStartAddSize; - } - */ - - /** - * 返回元素最多列的元素个数 - * @return 元素最多列的元素个数 - */ - public int getMaxColumnSize() { - return maxColumnSize; - } - - /** - * 返回元素最多列的列名称 - * @return 元素最多列的列名称 - */ - public List getMaxColumnName() { - return maxColumnNameList; - } - - /** - * 返回元素最少列的元素个数 - * @return 元素最少列的元素个数 - */ - public int getMinColumnSize() { - return minColumnSize; - } - - /** - * 返回元素最少列的列名称 - * @return 元素最少列的列名称 - */ - public List getMinColumnName() { - return minColumnNameList; - } - - @Override - public void add(String name, ByType byType) { - add(new ElementInformation(name, byType, ElementType.DATA_LIST_ELEMENT)); - - } - - @Override - public void add(String name, ByType byType, String... links) { - add(new ElementInformation(name, byType, ElementType.DATA_LIST_ELEMENT, links)); - - } - - @Override - public void add(String name, String... links) { - add(new ElementInformation(name, null, ElementType.DATA_LIST_ELEMENT, links)); - - } - - @Override - void add(ElementInformation elementInformation) { - //重写父类的add方法,使元素能进行极值的统计 - super.add(elementInformation); - //判断当前获取到的元素是否大于当前存储的元素的最大值或小于当前存储的最小值,若是,则将最大值或最小值进行替换 - findLimitColumn(elementInformation); - } - - /** - * 用于返回列表多个指定的元素,传入的下标可参见{@link #getWebElement(String, int)} - * - * @param name 列名称 - * @param indexs 一组元素下标(即列表中对应的某一个元素) - * @return 对应列多个指定下标的元素 - * @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常 - * @see #getWebElement(String, int) - */ - public List getElements(String name, int... indexs) { - // 存储所有获取到的事件 - ArrayList events = new ArrayList<>(); - - // 循环,解析所有的下标,并调用getEvent()方法,存储至events - for (int index : indexs) { - events.add(getElement(name, index)); - } - - return events; - } - - /** - * 用于返回列表中指定随机个数的元素 - * - * @param name 列名称 - * @param length 需要返回列表事件的个数 - * @return 列表事件组 - */ - public List getRandomElements(String name, int length) { - //获取元素信息,并判断元素是否存在,不存在则抛出异常 - ElementInformation element = nameToElementInformation(name); - if (element == null) { - throw new NoSuchElementException("不存在的定位方式:" + name); - } - - // 判断传入的长度是否大于等于当前 - if (length >= elementMap.get(element).size()) { - return getAllElement(name); - } - - // 存储通过随机得到的数字 - ArrayList indexsList = new ArrayList(); - int randomLength = elementMap.get(element).size() + 1; - // 循环,随机获取下标数字 - for (int i = 0; i < length; i++) { - int randomIndex = 0; - // 循环,直到生成的随机数不在indexs中为止 - while (indexsList.contains(randomIndex = new Random().nextInt(randomLength))) { - } - indexsList.add(randomIndex); - } - - // 将indexsList转换成int[] - int[] indexs = new int[indexsList.size()]; - for (int i = 0; i < indexsList.size(); i++) { - indexs[i] = indexsList.get(i); - } - - return getElements(name, indexs); - } - - /** - * 用于根据参数,求取elementMap中最多或最少列表的元素个数以及列表的名称 - * @param key 需要计算的最小值 - * @return 极值以及极值所在的列 - */ - private void findLimitColumn(ElementInformation key) { - //获取指向的元素列表的元素个数 - int size = elementMap.get(key).size(); - - //根据参数,判断获取的列是否为最大值所在的列,并对极值做进一步判断 - if (maxColumnSize < size) { - maxColumnNameList.clear(); - maxColumnSize = size; - maxColumnNameList.add(key.name); - } else if (maxColumnSize == size) { - maxColumnNameList.add(key.name); - } - - if (minColumnSize > size) { - minColumnNameList.clear(); - minColumnSize = size; - minColumnNameList.add(key.name); - } else if (minColumnSize == size) { - minColumnNameList.add(key.name); - } - } - - @Override - boolean isExistElement(By by, long waitTime) { - //TODO 修改等待方法,改为获取到元素后才返回相应的状态 - //当查找到元素时,则返回true,若查不到元素,则会抛出异常,故返回false - return new WebDriverWait(driver, waitTime, 200). - until((driver) -> { - List elementList = driver.findElements(by); - - //若获取的标题首行为标题行时,则判断为获取到大于1个元素时返回true,否则则大于0个元素返回true - if (isFristRowTitle) { - return elementList.size() > 1; - } else { - return elementList.size() > 0; - } - }); - } -} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/old/Element.java b/src/main/java/pres/auxiliary/work/selenium/element/old/Element.java deleted file mode 100644 index 914d88a..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/Element.java +++ /dev/null @@ -1,128 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.ui.Select; - -/** - *

文件名:Element.java

- *

用途: - * 用于返回和查找页面元素,以方便在元素过期时能进行重新获取 - *

- *

编码时间:2020年5月18日上午8:39:05

- *

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

- * @author 彭宇琦 - * @version Ver1.0 - * @since JDK 12 - * - */ -public class Element { - /** - * 存储元素 - */ - private WebElement element = null; - /** - * 存储查找元素的By对象 - */ - private By by; - /** - * 存储获取需要获取的元素下标 - */ - private int index; - - /** - * 存储WebDriver对象,以查找相应元素 - */ - private WebDriver driver; - - /** - * 用于存储元素的名称 - */ - private String name; - - /** - * 标记元素的类型,以用于重新获取时 - */ - private ElementType elementType; - - /** - * 初始化信息,并添加需要获取元素的下标,用于需要获取列表时使用 - * @param name 元素名称或定位内容 - * @param byType 元素定位 - */ - 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; - } - - /** - * 初始化信息,指定获取第一个元素,用于只获取单个元素时使用 - * @param name 元素名称或定位内容 - * @param byType 元素定位 - */ - public Element(WebDriver driver, ElementType elementType, By by, String name) { - this(driver, elementType, by, name, 0); - } - - /** - * 用于返回元素对应的WebElement对象 - * @return 返回元素对应的WebElement对象 - */ - public WebElement getWebElement() { - //若元素未进行查找,则查找一次元素 - if(element == null) { - //对元素进行一次查找 - findElement(); - } - - return element; - } - - /** - * 根据存储的WebDriver对象对元素进行更新 - */ - public void findElement() { - switch (elementType) { - case COMMON_ELEMENT: - case DATA_LIST_ELEMENT: - case SELECT_DATAS_ELEMENT: - element = driver.findElements(by).get(index); - break; - case SELECT_OPTION_ELEMENT: - element = new Select(driver.findElement(by)).getOptions().get(index); - break; - default: - 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); - } - } -} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/old/ElementType.java b/src/main/java/pres/auxiliary/work/selenium/element/old/ElementType.java deleted file mode 100644 index fcd28dc..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/ElementType.java +++ /dev/null @@ -1,32 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -/** - *

文件名: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/old/ListBy.java b/src/main/java/pres/auxiliary/work/selenium/element/old/ListBy.java deleted file mode 100644 index c2373db..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/ListBy.java +++ /dev/null @@ -1,205 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -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 ListBy extends MultiBy { - /** - * 用于存储获取到的列表一列元素,key为列表名称,value为列表元素 - */ - LinkedHashMap> elementMap = new LinkedHashMap<>(16); - - /** - * 通过浏览器对象{@link AbstractBrower}进行构造 - * @param brower {@link AbstractBrower}对象 - */ - public ListBy(AbstractBrower brower) { - super(brower); - } - - /** - * 构造对象并存储浏览器的{@link WebDriver}对象 - * - * @param driver 浏览器的{@link WebDriver}对象 - */ - public ListBy(WebDriver driver) { - super(driver); - } - - /** - * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中 - * @param brower {@link AbstractBy}对象 - */ - public ListBy(AbstractBy by) { - super(by); - } - - /** - * 返回列表名称对应的元素个数,若该列未被获取,则返回-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) { - //判断传入的元素是否在xml文件中,若存在再判断是否自动切换窗体,若需要,则获取元素的所有父窗体并进行切换 - if (xml != null && xml.isElement(elementInformation.name) && isAutoSwitchIframe) { - switchFrame(getParentFrameName(elementInformation.name)); - } - - 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, elementInformation.name, 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, true); - - // 转义下标后,返回对应的元素 - 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/old/MultiBy.java b/src/main/java/pres/auxiliary/work/selenium/element/old/MultiBy.java deleted file mode 100644 index 7873b14..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/MultiBy.java +++ /dev/null @@ -1,149 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -import java.util.Random; - -import org.openqa.selenium.NoSuchElementException; -import org.openqa.selenium.TimeoutException; -import org.openqa.selenium.WebDriver; - -import pres.auxiliary.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.xml.ByType; - -/** - *

文件名:MultiElement.java

- *

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

- *

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

- *

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

- * @author 彭宇琦 - * @version Ver1.0 - * @since JDK 12 - * - */ -public abstract class MultiBy extends AbstractBy { - /** - * 通过浏览器对象{@link AbstractBrower}进行构造 - * @param brower {@link AbstractBrower}对象 - */ - public MultiBy(AbstractBrower brower) { - super(brower); - } - - /** - * 构造对象并存储浏览器的{@link WebDriver}对象 - * - * @param driver 浏览器的{@link WebDriver}对象 - */ - public MultiBy(WebDriver driver) { - super(driver); - } - - /** - * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中 - * @param brower {@link AbstractBy}对象 - */ - public MultiBy(AbstractBy by) { - super(by); - } - - /** - * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,添加元素。由于该方法不指定元素的定位 - * 方式,若传入的参数不是xml元素且非xpath路径或绝对css路径时,其识别效率较慢,建议在该情况下 - * 调用{@link #add(String, ByType)}方法,指定元素定位方法 - * @param name 元素在xml文件或者元素的定位内容 - * @see #add(String, ByType) - * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 - */ - public void add(String name) { - add(new ElementInformation(name, null)); - } - - /** - * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,以及元素的定位方式,添加元素。 - * @param name 元素在xml文件或者元素的定位内容 - * @param byType 元素定位方式枚举对象({@link ByType}枚举) - * @see #add(String) - * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 - */ - public abstract void add(String name, ByType byType); - - /** - * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,以及元素的定位方式,添加元素。 - * 该方法可对由xml文件读取的内容进行词语替换,根据 - * 传参中词语的顺序,对需要替换的词语进行替换 - * @param name 元素在xml文件或者元素的定位内容 - * @param byType 元素定位方式枚举对象({@link ByType}枚举) - * @param links 替换词语 - * @see #add(String, ByType) - * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 - */ - public abstract void add(String name, ByType byType, String...links); - - /** - * 用于根据传入的元素在xml文件中的名称或者元素的定位内容,添加元素。由于该方法不指定元素的定位 - * 方式,若传入的参数不是xml元素且非xpath路径或绝对css路径时,其识别效率较慢,建议在该情况下 - * 调用{@link #add(String, ByType)}方法,指定元素定位方法。该方法可对由xml文件读取的内容进 - * 行词语替换,根据传参中词语的顺序,对需要替换的词语进行替换 - * @param name 元素在xml文件或者元素的定位内容 - * @param links 替换词语 - * @see #add(String) - * @throws TimeoutException 元素在指定时间内无法找到时抛出的异常 - */ - public abstract void add(String name, String...links); - - /** - * 添加元素的底层方法 - * @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 传入的下标 - * @param randomZero 标记是否可以随机出数字0 - * @return 可识别的下标 - * @throws NoSuchElementException 当元素无法查找到时抛出的异常 - */ - int getIndex(int length, int index, boolean randomZero) { - //判断元素下标是否超出范围,由于可以传入负数,故需要使用绝对值 - 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,则进行随机选择,但需要判断是否允许随机出0(第一个元素) - int newindex = 0; - do { - newindex = new Random().nextInt(length); - } while(newindex == 0 && !randomZero); - - return newindex; - } - } -} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/old/NoSuchWindownException.java b/src/main/java/pres/auxiliary/work/selenium/element/old/NoSuchWindownException.java deleted file mode 100644 index 0eb8d8b..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/NoSuchWindownException.java +++ /dev/null @@ -1,28 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -public class NoSuchWindownException extends RuntimeException { - - private static final long serialVersionUID = 1L; - - public NoSuchWindownException() { - super(); - } - - public NoSuchWindownException(String arg0, Throwable arg1, boolean arg2, boolean arg3) { - super(arg0, arg1, arg2, arg3); - } - - public NoSuchWindownException(String arg0, Throwable arg1) { - super(arg0, arg1); - } - - public NoSuchWindownException(String arg0) { - super(arg0); - } - - public NoSuchWindownException(Throwable arg0) { - super(arg0); - } - - -} diff --git a/src/main/java/pres/auxiliary/work/selenium/element/old/SelectBy.java b/src/main/java/pres/auxiliary/work/selenium/element/old/SelectBy.java deleted file mode 100644 index 6ede739..0000000 --- a/src/main/java/pres/auxiliary/work/selenium/element/old/SelectBy.java +++ /dev/null @@ -1,313 +0,0 @@ -package pres.auxiliary.work.selenium.element.old; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import org.openqa.selenium.By; -import org.openqa.selenium.NoSuchElementException; -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.work.selenium.brower.AbstractBrower; -import pres.auxiliary.work.selenium.xml.ByType; - -/** - *

文件名:SelectBy.java

- *

用途: - * 提供获取下拉框中选项元素的方法,支持标准型下拉框选项(由select与option标签组成的下拉框)以及 - * 非标准型下拉框选项(由普通的div、li等元素组成的选项),并支持根据关键词查找选项。需要注意的是, - * 标准下拉选项和非标准下拉选项需要传入的参数不同,例如,
- * 标准下拉框:
- * <select id='test'>
- *  <option>男</option>
- *  <option>女</option>
- *  <option>其他</option>
- * </select>
- * 对于该标准的下拉框选项,只需要定位到//select[@id='test'],得到其WebElement对象即可,但对于非标准的下拉框其下拉框是由input和button标签构成:
- * <div>
- *  <span><input/></span>
- *  <span><button/></span>
- * </div>
- * 点击button对应的按钮后,其下也能弹出选项,但其选项是由div标签写入text构成:
- * <div id='test'>
- *  <div>男</div>
- *  <div>女</div>
- *  <div>其他</div>
- * </div>
- * 对于这种非标准的下拉框选项,需要传入选项所在的所有div标签对应的WebElement元素,在上例,则需要定位到//div[@id='test']/div, - * 注意,末尾的div不指定数字,则可以代表整个选项。
- *

- *

编码时间:2020年5月24日下午3:30:00

- *

修改时间:2020年5月24日下午3:30:00

- * @author 彭宇琦 - * @version Ver1.0 - * @since JDK 12 - * - */ -public class SelectBy extends MultiBy { - /** - * 用于存储获取下拉选项时的信息 - */ - ElementInformation elementInfo; - /** - * 用于存储下拉选项的元素 - */ - ArrayList option = new ArrayList<>(); - /** - * 用于存储下拉选项的文本 - */ - ArrayList optionText = new ArrayList<>(); - - /** - * 设置标记的下拉选项的类型 - */ - private ElementType elementType; - - /** - * 控制元素首行是否为 - */ - private boolean fristIsEmpty = false; - - /** - * 通过浏览器对象{@link AbstractBrower}进行构造 - * - * @param brower {@link AbstractBrower}对象 - */ - public SelectBy(AbstractBrower brower) { - super(brower); - } - - /** - * 构造对象并存储浏览器的{@link WebDriver}对象 - * - * @param driver 浏览器的{@link WebDriver}对象 - */ - public SelectBy(WebDriver driver) { - super(driver); - } - - /** - * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中 - * @param brower {@link AbstractBy}对象 - */ - public SelectBy(AbstractBy by) { - super(by); - } - - @Override - public void add(String name, ByType byType) { - elementInfo = new ElementInformation(name, byType); - add(elementInfo); - } - - /** - * 用于添加选项并指明首个选项是否为不可选择的选项或者文本为空的选项,其他效果与{@link #add(String)}一致 - * @param name 元素在xml文件或者元素的定位内容 - * @param fristIsEmpty 首个选项是否为不可选择的选项或者文本为空的选项 - * @see #add(String) - */ - /* - public void add(String name, boolean fristIsEmpty) { - this.fristIsEmpty = fristIsEmpty; - add(name); - } - */ - - /** - * 用于添加选项并指明首个选项是否为不可选择的选项或者文本为空的选项,其他效果与{@link #add(String, ByType)}一致 - * @param name 元素在xml文件或者元素的定位内容 - * @param byType 元素定位方式枚举对象({@link ByType}枚举) - * @param fristIsEmpty 首个选项是否为不可选择的选项或者文本为空的选项 - * @see #add(String, ByType) - */ - /* - public void add(String name, ByType byType, boolean fristIsEmpty) { - this.fristIsEmpty = fristIsEmpty; - add(name, byType); - } - */ - - @Override - public void add(String name, ByType byType, String... links) { - elementInfo = new ElementInformation(name, byType, ElementType.DATA_LIST_ELEMENT, links); - add(elementInfo); - - } - - @Override - public void add(String name, String... links) { - elementInfo = new ElementInformation(name, null, ElementType.DATA_LIST_ELEMENT, links); - add(elementInfo); - } - - /** - * 可用于指明首行是否为空选项,其他说明可参考{@link #add(String, ByType, String...)} - * @param name 元素在xml文件或者元素的定位内容 - * @param byType 元素定位方式枚举对象({@link ByType}枚举) - * @param fristIsEmpty 首个选项是否为不可选择的选项或者文本为空的选项 - * @param links 替换词语 - */ - /* - public void add(String name, ByType byType, boolean fristIsEmpty, String... links) { - this.fristIsEmpty = fristIsEmpty; - add(name, byType, links); - - } - */ - - /** - * 可用于指明首行是否为空选项,其他说明可参考{@link #add(String, String...)} - * @param name 元素在xml文件或者元素的定位内容 - * @param fristIsEmpty 首个选项是否为不可选择的选项或者文本为空的选项 - * @param links 替换词语 - */ - /* - public void add(String name, boolean fristIsEmpty, String... links) { - this.fristIsEmpty = fristIsEmpty; - add(name, null, links); - - } - */ - - /** - * 设置首个选项是否为不可选择的选项 - * @param fristIsEmpty 首个选项是否为不可选择 - */ - public void setFristIsEmpty(boolean fristIsEmpty) { - this.fristIsEmpty = fristIsEmpty; - } - - @Override - void add(ElementInformation elementInformation) { - //判断传入的元素是否在xml文件中,若存在再判断是否自动切换窗体,若需要,则获取元素的所有父窗体并进行切换 - if (xml != null && xml.isElement(elementInformation.name) && isAutoSwitchIframe) { - switchFrame(getParentFrameName(elementInformation.name)); - } - - //清除原存储的内容 - clear(); - - //获取元素的By对象 - By by = recognitionElement(elementInformation); - //根据By获取元素 - List elementList = driver.findElements(by); - //获取元素个数 - int size = elementList.size(); - - //根据第一个元素的tagname来判断是否为标准下拉元素 - if ("select".equalsIgnoreCase(elementList.get(0).getTagName())) { - elementType = ElementType.SELECT_OPTION_ELEMENT; - - //若是标准下拉选项型,则需要改变size的值,方便后续添加数据 - Select select = new Select(driver.findElement(by)); - //获取所有的选项内容,并计算元素个数 - elementList = select.getOptions(); - size = elementList.size(); - } else { - elementType = ElementType.SELECT_DATAS_ELEMENT; - } - - //构造Element对象 - for (int i = 0; i < size; i++) { - //获取元素 - option.add(new Element(driver, elementType, by, elementInformation.name, i)); - //获取元素的文本内容 - optionText.add(elementList.get(i).getText()); - } - } - - /** - * 根据选项下标,返回相应的选项元素。下标与选项元素真实下标一致,支持传入负数,表示从后向前遍历元素; - * 当传入0时,表示随机选择一个选项。 - * @param index 选项下标 - * @return 相应的选项元素 - */ - public Element getElement(int index) { - //当首选项为空时,则在随机时不允许产生0 - return option.get(getIndex(option.size(), index, !fristIsEmpty)); - } - - /** - * 根据关键词组查找选项,并返回选项元素,当传入的元素名称不存在时,则抛出NoSuchElementException异常; - * 当查询到有多个包含关键词的选项时,则选择第一个选项
- * 注意,当传入多个关键词时其选项需要全部满足才会返回相应的选项。 - * - * @param keys 查询选项的关键词组 - * @return 相应的选项元素 - * @throws NoSuchElementException 查找的选项不存在时抛出的异常 - */ - public Element getElement(String...keys) { - //查找完全符合关键词的元素 - String elementName = optionText.stream().filter(text -> { - //遍历关键词,若元素不符合条件,则返回false - for (String key : keys) { - if (text.indexOf(key) < 0) { - return false; - } - } - - //若条件均符合,则返回true - return true; - }).findFirst().orElseThrow(() -> { - //若不存在符合条件的选项,则抛出NoSuchElementException异常,并返回相应的消息 - StringBuilder keyText = new StringBuilder("["); - //拼接查询条件 - Arrays.stream(keys).forEach(key -> { - keyText.append(key + ", "); - }); - - return new NoSuchElementException("不存在符合条件的选项:" + keyText.substring(0, keyText.length() - ", ".length()) + "]"); - }); - - return option.get(optionText.indexOf(elementName)); - } - - @Override - public void againGetElement() { - clear(); - add(elementInfo); - } - - @Override - boolean isExistElement(By by, long waitTime) { - //当查找到元素时,则返回true,若查不到元素,则会抛出异常,故返回false - return new WebDriverWait(driver, waitTime, 200). - until((driver) -> { - List elements = driver.findElements(by); - //根据是否能查找到元素进行判断 - if (elements.size() > 0) { - //若获取到的第一个元素的标签名为select(标准下拉),则可以直接返回true - if ("select".equals(elements.get(0).getTagName())) { - return true; - } - - //若查到元素,再进一步判断元素内容是否完全加载 - int textSize = elements.stream().filter(element -> { - return !element.getText().isEmpty(); - }).collect(Collectors.toList()).size(); - - //若首选项为空时,则加载的内容必须大于或等于总选项个数-1 - //若首选项不为空时,则加载的内容必须与原选项个数一致 - if (fristIsEmpty) { - return textSize >= elements.size() - 1; - } else { - return textSize == elements.size(); - } - } else { - return false; - } - }); - } - - /** - * 用于清除原存储的内容 - */ - void clear() { - option.clear(); - optionText.clear(); - } -} 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 307c826..5526b6e 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/ClickEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/ClickEvent.java @@ -6,7 +6,7 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.ui.ExpectedConditions; -import pres.auxiliary.work.selenium.element.old.Element; +import pres.auxiliary.work.selenium.element.Element; /** *

文件名:ClickEvent.java

diff --git a/src/main/java/pres/auxiliary/work/selenium/event/EventAction.java b/src/main/java/pres/auxiliary/work/selenium/event/EventAction.java index a74433d..9c8a968 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/EventAction.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/EventAction.java @@ -1,6 +1,6 @@ package pres.auxiliary.work.selenium.event; -import pres.auxiliary.work.selenium.element.old.Element; +import pres.auxiliary.work.selenium.element.Element; /** *

文件名:EventAction.java

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 4c0069f..56f2c48 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java @@ -4,7 +4,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; -import pres.auxiliary.work.selenium.element.old.Element; +import pres.auxiliary.work.selenium.element.Element; /** *

文件名:EventInformation.java

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 e474baf..d097dca 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java @@ -12,7 +12,7 @@ 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.old.Element; +import pres.auxiliary.work.selenium.element.Element; /** *

文件名:EventProxy.java

diff --git a/src/main/java/pres/auxiliary/work/selenium/event/EventWait.java b/src/main/java/pres/auxiliary/work/selenium/event/EventWait.java index 761a17e..33c76a2 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/EventWait.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/EventWait.java @@ -5,7 +5,7 @@ import java.time.Duration; import org.openqa.selenium.WebDriver; import org.openqa.selenium.support.ui.WebDriverWait; -import pres.auxiliary.work.selenium.element.old.Element; +import pres.auxiliary.work.selenium.element.Element; public class EventWait { /** 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 4149498..a6cc54e 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/JsEvent.java @@ -2,6 +2,7 @@ package pres.auxiliary.work.selenium.event; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.UUID; import org.openqa.selenium.By; @@ -13,8 +14,8 @@ import org.openqa.selenium.WebElement; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import pres.auxiliary.work.selenium.element.old.Element; -import pres.auxiliary.work.selenium.element.old.ElementType; +import pres.auxiliary.work.selenium.element.Element; +import pres.auxiliary.work.selenium.element.ElementType; /** *

@@ -145,7 +146,10 @@ public class JsEvent extends AbstractEvent { // 获取新添加元素的xpath String xpath = addElement(element, elementName); // 查找新添加的元素(由于是新添加的元素,肯定能查找到,故无需编写等待) - Element newElement = new Element(driver, ElementType.COMMON_ELEMENT, By.xpath(xpath), "TeamElement"); + Element newElement = new Element(driver, "TeamElement", ElementType.COMMON_ELEMENT); + List byList = new ArrayList<>(); + byList.add(By.xpath(xpath)); + newElement.setByList(byList); // 获取元素的所有属性 JSONArray attributes = elementJson.getJSONArray("attributes"); 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 62066f1..9827db3 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/TextEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/TextEvent.java @@ -13,7 +13,7 @@ import org.openqa.selenium.support.ui.ExpectedConditions; import pres.auxiliary.tool.randomstring.RandomString; import pres.auxiliary.tool.randomstring.StringMode; -import pres.auxiliary.work.selenium.element.old.Element; +import pres.auxiliary.work.selenium.element.Element; import pres.auxiliary.work.selenium.tool.RecognitionImage; import pres.auxiliary.work.selenium.tool.Screenshot; @@ -137,7 +137,7 @@ public class TextEvent extends AbstractEvent { // 判断验证码信息是否加载,加载后,获取其Rectang对象 Rectangle r = codeImageElement.getWebElement().getRect(); // 构造截图对象,并创建截图 - Screenshot sc = new Screenshot(driver, "Temp"); + Screenshot sc = new Screenshot(driver, new File("Temp")); File image = null; try { image = sc.creatImage("code"); diff --git a/src/main/java/pres/auxiliary/work/selenium/tool/IncorrectDirectoryException.java b/src/main/java/pres/auxiliary/work/selenium/tool/IncorrectDirectoryException.java new file mode 100644 index 0000000..b56972b --- /dev/null +++ b/src/main/java/pres/auxiliary/work/selenium/tool/IncorrectDirectoryException.java @@ -0,0 +1,28 @@ +package pres.auxiliary.work.selenium.tool; + +public class IncorrectDirectoryException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public IncorrectDirectoryException() { + super(); + } + + public IncorrectDirectoryException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public IncorrectDirectoryException(String message, Throwable cause) { + super(message, cause); + } + + public IncorrectDirectoryException(String message) { + super(message); + } + + public IncorrectDirectoryException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/pres/auxiliary/work/selenium/tool/Screenshot.java b/src/main/java/pres/auxiliary/work/selenium/tool/Screenshot.java index 5b6ab0f..b8f3b17 100644 --- a/src/main/java/pres/auxiliary/work/selenium/tool/Screenshot.java +++ b/src/main/java/pres/auxiliary/work/selenium/tool/Screenshot.java @@ -2,8 +2,6 @@ package pres.auxiliary.work.selenium.tool; import java.io.File; import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; import org.apache.commons.io.FileUtils; import org.openqa.selenium.OutputType; @@ -21,40 +19,20 @@ import org.openqa.selenium.WebDriverException; */ public class Screenshot { // 用于存储截图保存的路径 - private StringBuilder savePath = new StringBuilder("C:\\AutoTest\\Screenshot\\"); - // 用于存储截图的文件名称 - private StringBuilder imageName = new StringBuilder("Image"); + private File savePathFolder = new File("Screenshot/"); // 用于存储指定的WebDriver对象 private WebDriver driver; // 用于存储截图的时间 private long time = 500; /** - * 用于按默认的方式创建截图保存位置及截图文件名称
- * 默认位置为:C:/AutoTest/Screenshot/
- * 默认文件名为(不带后缀):Image + * 用于按默认的方式创建截图,默认截图保存位置为项目目录下的“Screenshot”文件夹
* - * @param driver - * WebDriver对象 + * @param driver {@link WebDriver}对象 */ public Screenshot(WebDriver driver) { setDriver(driver); } - - /** - * 构造对象,
- * 默认位置为:C:/AutoTest/Screenshot/
- * 默认文件名为(不带后缀):Image
- * 注意:该方法只构建对象,由于未传入WebDriver对象,故不能直接用于截图 - * - * @param driver - * WebDriver对象 - * @throws IncorrectDirectoryException - * 传入路径不合法时抛出的异常 - */ - public Screenshot(String savePath) { - setSavePath(savePath); - } /** * 用于按指定的路径以及默认的文件名保存截图
@@ -69,71 +47,26 @@ public class Screenshot { * @throws IncorrectDirectoryException * 传入路径不合法时抛出的异常 */ - public Screenshot(WebDriver driver, String savePath) { + public Screenshot(WebDriver driver, File savePathFolder) { setDriver(driver); - setSavePath(savePath); + setSavePathFolder(savePathFolder); } - - /** - * 该方法用于返回截图的名称(不带后缀) - * - * @return 返回截图的名称(不带后缀) - */ - public String getImageName() { - return imageName.toString(); - } - - /** - * 该方法用于设置截图的文件名称,若传入的文件名不符合windows下文件的命名规则, 则抛出IncorrectDirectoryException异常 - * - * @param imageName - * 指定的截图名称 - * @throws IncorrectDirectoryException - * 文件命名不正确时抛出的异常 - */ - public void setImageName(String imageName) { - // 判断传入的截图名称是否符合windows下的命名规则,若不符合,则抛出IncorrectDirectoryException异常 - if (!MakeDirectory.isFileName(imageName)) { - throw new IncorrectDirectoryException("不合理的文件名称,文件名称:" + imageName); - } - - // 通过判断后,则清空imageName存储的信息并将新的文件名称放入imageName种属性中 - this.imageName.delete(0, this.imageName.length()); - this.imageName.append(new SimpleDateFormat("yyyyMMddHHmmss_").format(new Date())); - this.imageName.append(imageName); - } - + /** * 该方法用于返回截图保存的路径 * * @return 返回截图保存的路径 */ - public String getSavePath() { - return savePath.toString(); + public File getSavePathFolder() { + return savePathFolder; } /** - * 该方法用于设置截图保存的位置,可传入相对路径,也可传入绝对路径, - * 若传入的路径不符合windows下文件夹名称的命名规则时,则抛出IncorrectDirectoryException异常 - * - * @param savePath - * 传入的截图保存路径 - * @throws IncorrectDirectoryException - * 传入路径不合法时抛出的异常 + * 该方法用于设置截图文件保存路径 + * @param savePathFolder */ - public void setSavePath(String savePath) { - // 将传入的路径封装成StringBuilder,以便格式化 - StringBuilder sb = new StringBuilder(savePath); - // 格式化传入的路径 - sb = MakeDirectory.formatPath(sb); - - // 判断传入的路径是否符合windows下对文件夹名称命名的规则,如果不符合则抛出IncorrectDirectoryException异常 - if (!MakeDirectory.isPath(sb.toString())) { - throw new IncorrectDirectoryException("不合理的文件夹路径,文件路径:" + sb.toString()); - } - - // 将通过判断的sb赋给savePath属性 - this.savePath = sb; + public void setSavePathFolder(File savePathFolder) { + this.savePathFolder = savePathFolder; } /** @@ -181,10 +114,8 @@ public class Screenshot { * @see #creatImage() */ public synchronized File creatImage(String imageName) throws WebDriverException, IOException { - // 将名称放入属性中 - setImageName(imageName); // 调用无参方法 - return saveScreenshot(); + return saveScreenshot(imageName); } /** @@ -217,24 +148,14 @@ public class Screenshot { * @throws WebDriverException * WebDriver引用错误时抛出的异常 */ - private File saveScreenshot() throws WebDriverException, IOException { + private File saveScreenshot(String fileName) throws WebDriverException, IOException { // 判断driver对象是否为空, if (driver == null) { throw new NullPointerException("无效的WebDriver对象"); } - - // 判断截图保存路径和截图文件名是否存在,若不存在则抛出UndefinedDirectoryException异常 - if ("".equals(savePath.toString()) || "".equals(imageName.toString())) { - throw new UndefinedDirectoryException( - "未定义文件路径或者文件名,文件路径:" + savePath.toString() + ",文件名:" + imageName.toString()); - } // 将savePath中保存的路径作为截图保存路径创建文件夹 - File f = new File(savePath.toString()); - f.mkdirs(); - - // 在imageName的后面加上当前时间以及后缀名 - imageName.append(".png"); + savePathFolder.mkdirs(); // 判断是否有设置截图等待时间,若设置了,则加上等待时间 if (time != 0) { @@ -244,19 +165,13 @@ public class Screenshot { e.printStackTrace(); } } - - f = new File(f + "\\" + imageName.toString()); + + File imageFile = new File(savePathFolder + fileName + ".png"); // 截图,并将得到的截图转移到指定的目录下 // 由于通过selenium的getScreenshotAs()得到的截图会不知道存储在哪,故需要通过文件流的方式将截图复制到指定的文件夹下 - FileUtils.copyFile(((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE), f); + FileUtils.copyFile(((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE), imageFile); - return f; + return imageFile; } - - @Override - public String toString() { - return "savePath=" + savePath + "\r\nimageName=" + imageName + "\r\ndriver=" + driver; - } - } diff --git a/src/test/java/pres/auxiliary/work/selenium/element/CommonByTest.java b/src/test/java/pres/auxiliary/work/selenium/element/CommonByTest.java index 42912d3..5aa381e 100644 --- a/src/test/java/pres/auxiliary/work/selenium/element/CommonByTest.java +++ b/src/test/java/pres/auxiliary/work/selenium/element/CommonByTest.java @@ -4,13 +4,10 @@ import java.io.File; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; 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.element.old.DataListBy; /** *

文件名:CommonElementTest.java

@@ -83,7 +80,7 @@ public class CommonByTest { @Test public void exceptAutoLocationElementTest() { File xmlFile = new File("src/test/java/pres/auxiliary/work/selenium/element/测试文件.xml"); - ce.setXmlFile(xmlFile, false); + ce.setXmlFile(xmlFile); //先切主窗体 ce.switchFrame("主窗体"); //在获取元素前,会判断元素所在窗体,由于主窗体是爷爷辈窗体,获取元素前会切换工资发放详情窗体