修改元素获取机制

This commit is contained in:
彭宇琦 2020-08-05 20:52:23 +08:00
parent 6f7ade88f6
commit a72e5a2034
28 changed files with 543 additions and 2358 deletions

View File

@ -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);
}
}

View File

@ -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<String> 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;

View File

@ -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) {

View File

@ -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;
/**
* <p><b>文件名</b>DataListElement.java</p>
@ -24,40 +19,10 @@ import pres.auxiliary.work.selenium.xml.ByType;
* <p><b>修改时间</b>2020年4月29日下午6:18:46</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
* @since JDK 8
*/
public class DataListBy extends ListBy {
/**
* 存储获取到的元素列表中最多元素列的元素个数
*/
private int maxColumnSize = -1;
/**
* 存储获取到的元素列表中最多元素列的名称
*/
private ArrayList<String> maxColumnNameList = new ArrayList<>();
/**
* 存储获取到的元素列表中最少元素列的元素个数
*/
private int minColumnSize = Integer.MAX_VALUE;
/**
* 存储获取到的元素列表中最少元素列的名称
*/
private ArrayList<String> minColumnNameList = new ArrayList<>();
/**
* 用于判断列表的第一行元素是否为标题元素
*/
boolean isFristRowTitle = false;
/**
* 用于存储元素列累计的个数
*/
// private HashMap<String, Integer> elementSizeMap = new HashMap<String, Integer>(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<String> getMaxColumnName() {
return maxColumnNameList;
}
// public List<String> getMaxColumnName() {
// return maxColumnNameList;
// }
/**
* 返回元素最少列的元素个数
* @return 元素最少列的元素个数
*/
public int getMinColumnSize() {
return minColumnSize;
}
// public int getMinColumnSize() {
// return minColumnSize;
// }
/**
* 返回元素最少列的列名称
* @return 元素最少列的列名称
*/
public List<String> getMinColumnName() {
return minColumnNameList;
}
@Override
void add(ElementInformation elementInformation) {
//重写父类的add方法使元素能进行极值的统计
super.add(elementInformation);
//判断当前获取到的元素是否大于当前存储的元素的最大值或小于当前存储的最小值若是则将最大值或最小值进行替换
findLimitColumn(elementInformation);
}
// public List<String> 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<Element> getElements(String name, int... indexs) {
// 存储所有获取到的事件
ArrayList<Element> events = new ArrayList<>();
// 循环解析所有的下标并调用getEvent()方法存储至events
for (int index : indexs) {
events.add(getElement(name, index));
// public List<Element> getElements(String name, int... indexs) {
// // 存储所有获取到的事件
// ArrayList<Element> 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<Element> 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<Element> 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时则表示随机获取一个元素<br>
* {@code getWebElement("姓名", 1)}表示获取名称为姓名的列中的第1个元素<br>
* {@code getWebElement("姓名", 0)}表示获取名称为姓名的列中在长度范围内随机一个元素<br>
* {@code getWebElement("//*[@id='name']", -1)}表示获取//*[@id='name']对应列中的倒数第1个元素<br>
* 注意若使用了外链xml词语则需要将词语写入到传参中否则无法获取到相应的元素
*
* @param name 列名称
* @param length 需要返回列表事件的个数
* @return 列表事件组
* @param index 元素下标即列表中对应的某一个元素
* @param linkKey 外链的词语若不存在则不传入
* @return 对应列指定的元素
*/
public List<Element> 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<Integer> indexsList = new ArrayList<Integer>();
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;
}
}

View File

@ -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<WebElement> elementList;
List<WebElement> 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<WebElement> 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<WebElement> 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<WebElement> 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;
}
}
}

View File

@ -22,11 +22,7 @@ public enum ElementType {
*/
DATA_LIST_ELEMENT,
/**
* 指向标准下拉框选择类型元素
* 指向下拉框选择类型元素
*/
SELECT_OPTION_ELEMENT,
/**
* 指向列表型下拉框选择类型元素
*/
SELECT_DATAS_ELEMENT;
SELECT_ELEMENT,
}

View File

@ -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<ElementInformation, Element> 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<String> 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时则表示随机获取一个元素<br>
* {@code getWebElement("姓名", 1)}表示获取名称为姓名的列中的第1个元素<br>
* {@code getWebElement("姓名", 0)}表示获取名称为姓名的列中在长度范围内随机一个元素<br>
* {@code getWebElement("//*[@id='name']", -1)}表示获取//*[@id='name']对应列中的倒数第1个元素<br>
* 注意若使用了外链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;
}
}
}

View File

@ -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;
/**
* <p><b>文件名</b>SelectBy.java</p>
* <p><b>用途</b>
* 提供获取下拉框中选项元素的方法支持标准型下拉框选项由select与option标签组成的下拉框以及
* 非标准型下拉框选项由普通的divli等元素组成的选项并支持根据关键词查找选项需要注意的是
* 标准下拉选项和非标准下拉选项需要传入的参数不同例如<br>
* 标准下拉框<br>
* &lt;select&nbsp;id='test'&gt;<br>
* &emsp;&lt;option&gt;&lt;/option&gt;<br>
* &emsp;&lt;option&gt;&lt;/option&gt;<br>
* &emsp;&lt;option&gt;其他&lt;/option&gt;<br>
* &lt;/select&gt;<br>
* 对于该标准的下拉框选项只需要定位到//select[@id='test']得到其WebElement对象即可但对于非标准的下拉框其下拉框是由input和button标签构成<br>
* &lt;div&gt;<br>
* &emsp;&lt;span&gt;&lt;input/&gt;&lt;/span&gt;<br>
* &emsp;&lt;span&gt;&lt;button/&gt;&lt;/span&gt;<br>
* &lt;/div&gt;<br>
* 点击button对应的按钮后其下也能弹出选项但其选项是由div标签写入text构成<br>
* &lt;div&nbsp;id='test'&gt;<br>
* &emsp;&lt;div&gt;&lt;/div&gt;<br>
* &emsp;&lt;div&gt;&lt;/div&gt;<br>
* &emsp;&lt;div&gt;其他&lt;/div&gt;<br>
* &lt;/div&gt;<br>
* 对于这种非标准的下拉框选项需要传入选项所在的所有div标签对应的WebElement元素在上例则需要定位到//div[@id='test']/div
* 注意末尾的div不指定数字则可以代表整个选项<br>
* </p>
* <p><b>编码时间</b>2020年5月24日下午3:30:00</p>
* <p><b>修改时间</b>2020年5月24日下午3:30:00</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*
*/
public class SelectBy extends ListBy {
/**
* 用于指向存储的元素名称
*/
private String name;
/**
* 用于指向存储的外链词语
*/
private List<String> 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时则表示随机获取一个元素<br>
* {@code getWebElement(1)}表示获取第1个选项<br>
* {@code getWebElement(0)}表示获取随机一个选项<br>
* {@code getWebElement(-1)}表示获取倒数第1个选项<br>
*
* @param index 元素下标即列表中对应的某一个元素
* @return 对应的选项
* @throws NoSuchElementException 当未对name列进行获取数据或index的绝对值大于列表最大值时抛出的异常
*/
public Element getElement(int index) {
Element element = findElement();
element.setElementIndex(index);
return element;
}
/**
* 根据关键词组查找选项并返回选项元素当传入的元素名称不存在时则抛出NoSuchElementException异常
* 当查询到有多个包含关键词的选项时则选择第一个选项<br>
* 注意当传入多个关键词时其选项需要全部满足才会返回相应的选项
*
* @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;
}
}

View File

@ -1,4 +1,4 @@
package pres.auxiliary.work.selenium.element.old;
package pres.auxiliary.work.selenium.element;
/**
* <p><b>文件名</b>UnrecognizableLocationModeException.java</p>

View File

@ -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;
/**
* <p><b>文件名</b>AbstractElement.java</p>
* <p><b>用途</b></p>
* <p><pre>
* 对辅助化测试工具selenium的获取元素代码进行的二次封装通过类中提供的方法以及配合相应存储元素的
* xml文件以更简便的方式对页面元素进行获取减少编程时的代码量
* </pre></p>
* <p><b>编码时间</b>2020年4月25日 下午4:18:37</p>
* <p><b>修改时间</b>2020年4月25日 下午4:18:37</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*/
public abstract class AbstractBy {
/**
* 用于存储浏览器的WebDriver对象设为静态保证所有的子类只使用一个WebDriver对象以避免造成WebDriver不正确导致的Bug
*/
WebDriver driver;
/**
* 用于指向存储控件定位方式的xml文件
*/
ReadXml xml;
/**
* 用于存储浏览器对象
*/
AbstractBrower brower;
/**
* 存储单个控件的等待时间
*/
private HashMap<String, Long> controlWaitTime = new HashMap<String, Long>();
/**
* 用于存储当前浏览器窗口的Handles值
*/
private String browserHandles;
/**
* 存储当前定位的窗体层级由于多个子类之间需要相互通信故此处标记为static
*/
private static ArrayList<String> 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;
}
}
/**
* <p>
* 通过传入在xml文件中的控件名称到类中指向的xml文件中查找控件
* 名称对应的定位方式或直接传入xpath与css定位方式
* 根据定位方式对相应的窗体进行定位当传入的窗体为当前窗体的前层父层窗体时
* 通过该方法将调用切换父层的方法将窗体切换到父层上例如<br>
* 当前存在f1, f2, f3, f4四层窗体则调用方法<br>{@code
* switchFrame("f2");
* }<br>
* 此时窗体将回到f2层无需再从顶层开始向下切换
* </p>
* <p>
* 若传入该方法的名称存在于xml文件中且该元素存在父窗体时调用
* 该方法会从xml文件中获取相应所有父窗体并对相应的父窗体进行切换
* 从而达到无须切换父窗体的目的例如存在以下xml文件片段<pre>{@code
* ...
* <iframe name='f1'>
* <xpath>...</xpath>
* <iframe name='f2'>
* <xpath>...</xpath>
* <iframe name='f3'>
* <xpath>...</xpath>
* </iframe>
* </iframe>
* </iframe>
* ...
* }</pre>
* 当调用该方法<br>{@code
* switchFrame("f3");
* }<br>
* 则会先将窗体从f1开始切换至窗体f2最后再切换为窗体f3
* </p>
*
* @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<String> nameList = new ArrayList<String>();
//判断传入的元素名称是否存在于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定位方式
* 根据定位方式对相应的窗体进行定位当传入的窗体为当前窗体的前层父层窗体时
* 通过该方法将调用切换父层的方法将窗体切换到父层上例如<br>
* 当前存在f1, f2, f3, f4四层窗体则调用方法<pre>{@code
* List<String> nameList = new ArrayList<String>();
* nameList.add("f2");
* switchFrame(nameList);
* }</pre>
* 此时窗体将回到f2层无需再从顶层开始向下切换<br>
* <b>注意</b>
* <ol>
* <li>窗体的切换按照从前向后的顺序进行切换切换顺序不能相反</li>
* <li>传入的参数若在xml文件中且存在父窗体调用该方法也不会对窗体进行切换</li>
* </ol>
*
* @param elementInformationList 存储窗体的名称或xpath与css定位方式的List集合
*/
void switchFrame(List<String> 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<String> handles = driver.getWindowHandles();
// 判断是否只存在一个窗体若只存在一个则直接返回当前浏览器的WebDriver对象
if (handles.size() == 1) {
return;
}
List<Page> 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();
}
/**
* <p>
* 用于根据传入的控件名称或定位方式对控件在页面上定位返回其WebElement对象形参可以传入在xml文件中元素的名称
* 亦可以传入页面元素的定位方式但目前识别只支持xpath和css两种方式
* 该方法获取的是一组元素可用于对列表元素事件中
* </p>
* <p>
* 元素识别判断方式按照以下步骤进行<br>
* 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止<br>
* 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置<br>
* 3.若仍找不到元素则抛出UnrecognizableLocationModeException
* </p>
*
* @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<String> getParentFrameName(String name) {
//存储获取到的父层窗体名称
List<String> nameList = new ArrayList<String>();
//获取元素所在窗体的名称
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<String> 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));
}
/**
* <p><b>文件名</b>AbstractElement.java</p>
* <p><b>用途</b>
* 存储获取元素时的信息
* </p>
* <p><b>编码时间</b>2020年5月9日上午7:57:24</p>
* <p><b>修改时间</b>2020年5月22日上午8:18:39</p>
* @author 彭宇琦
* @version Ver1.1
* @since JDK 1.8
*
*/
class ElementInformation {
/**
* 存储元素的名称或定位内容
*/
public String name;
/**
* 存储元素的定位方式
*/
public ByType byType;
/**
* 用于标记元素的类型
*/
public ElementType elementType;
/**
*
*/
public ArrayList<String> 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;
}
}
}

View File

@ -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;
/**
* <p><b>文件名</b>CommonElement.java</p>
* <p><b>用途</b>
* 提供在辅助化测试中对页面单一元素获取的方法类中获取元素的方法兼容传入定位方式对
* 元素进行查找建议使用xml对页面元素的定位方式进行存储以简化编码时的代码量也便于
* 对代码的维护
* </p>
* <p><b>编码时间</b>2020年4月26日下午10:34:55</p>
* <p><b>修改时间</b>2020年4月26日下午10:34:55</p>
* @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)));
*/
}
}

View File

@ -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;
/**
* <p><b>文件名</b>DataListElement.java</p>
* <p><b>用途</b>
* 提供在辅助化测试中对页面列表元素获取的方法并对列表元素的获取做了优化
* 类中获取元素的方法兼容传入定位方式对元素进行查找建议使用xml对页面元素的
* 定位方式进行存储以简化编码时的代码量也便于对代码的维护
* </p>
* <p><b>编码时间</b>2020年4月29日下午6:18:46</p>
* <p><b>修改时间</b>2020年4月29日下午6:18:46</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*/
public class DataListBy extends ListBy {
/**
* 存储获取到的元素列表中最多元素列的元素个数
*/
private int maxColumnSize = -1;
/**
* 存储获取到的元素列表中最多元素列的名称
*/
private ArrayList<String> maxColumnNameList = new ArrayList<>();
/**
* 存储获取到的元素列表中最少元素列的元素个数
*/
private int minColumnSize = Integer.MAX_VALUE;
/**
* 存储获取到的元素列表中最少元素列的名称
*/
private ArrayList<String> minColumnNameList = new ArrayList<>();
/**
* 用于判断列表的第一行元素是否为标题元素
*/
boolean isFristRowTitle = false;
/**
* 用于存储元素列累计的个数
*/
// private HashMap<String, Integer> elementSizeMap = new HashMap<String, Integer>(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<String> getMaxColumnName() {
return maxColumnNameList;
}
/**
* 返回元素最少列的元素个数
* @return 元素最少列的元素个数
*/
public int getMinColumnSize() {
return minColumnSize;
}
/**
* 返回元素最少列的列名称
* @return 元素最少列的列名称
*/
public List<String> 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<Element> getElements(String name, int... indexs) {
// 存储所有获取到的事件
ArrayList<Element> events = new ArrayList<>();
// 循环解析所有的下标并调用getEvent()方法存储至events
for (int index : indexs) {
events.add(getElement(name, index));
}
return events;
}
/**
* 用于返回列表中指定随机个数的元素
*
* @param name 列名称
* @param length 需要返回列表事件的个数
* @return 列表事件组
*/
public List<Element> 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<Integer> indexsList = new ArrayList<Integer>();
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<WebElement> elementList = driver.findElements(by);
//若获取的标题首行为标题行时则判断为获取到大于1个元素时返回true否则则大于0个元素返回true
if (isFristRowTitle) {
return elementList.size() > 1;
} else {
return elementList.size() > 0;
}
});
}
}

View File

@ -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;
/**
* <p><b>文件名</b>Element.java</p>
* <p><b>用途</b>
* 用于返回和查找页面元素以方便在元素过期时能进行重新获取
* </p>
* <p><b>编码时间</b>2020年5月18日上午8:39:05</p>
* <p><b>修改时间</b>2020年5月18日上午8:39:05</p>
* @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);
}
}
}

View File

@ -1,32 +0,0 @@
package pres.auxiliary.work.selenium.element.old;
/**
* <p><b>文件名</b>EelementType.java</p>
* <p><b>用途</b>
* 用于标记当前传入的元素是以何种方式进行获取
* </p>
* <p><b>编码时间</b>2020年5月22日上午7:57:32</p>
* <p><b>修改时间</b>2020年5月22日上午7:57:32</p>
* @author
* @version Ver1.0
* @since JDK 12
*
*/
public enum ElementType {
/**
* 指向普通类型元素
*/
COMMON_ELEMENT,
/**
* 指向数据列表类型元素
*/
DATA_LIST_ELEMENT,
/**
* 指向标准下拉框选择类型元素
*/
SELECT_OPTION_ELEMENT,
/**
* 指向列表型下拉框选择类型元素
*/
SELECT_DATAS_ELEMENT;
}

View File

@ -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;
/**
* <p><b>文件名</b>ListElement.java</p>
* <p><b>用途</b>
* 提供获取列表类型元素时的基本方法
* </p>
* <p><b>编码时间</b>2020年5月22日上午7:54:55</p>
* <p><b>修改时间</b>2020年5月22日上午7:54:55</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*
*/
public abstract class ListBy extends MultiBy {
/**
* 用于存储获取到的列表一列元素key为列表名称value为列表元素
*/
LinkedHashMap<ElementInformation, List<Element>> 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<String> getNames() {
ArrayList<String> 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<Element> elementList = new ArrayList<Element>();
//获取元素
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<Element> clearColumn(String name, boolean isRemove) {
ElementInformation element = nameToElementInformation(name);
//若元素不存在则直接返回null
if (element == null) {
return null;
}
//用于存储被移除的元素
List<Element> 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时则表示随机获取一个元素<br>
* {@code getWebElement("姓名", 1)}表示获取名称为姓名的列中的第1个元素<br>
* {@code getWebElement("姓名", 0)}表示获取名称为姓名的列中在长度范围内随机一个元素<br>
* {@code getWebElement("//*[@id='name']", -1)}表示获取//*[@id='name']对应列中的倒数第1个元素<br>
*
* @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<Element> getAllElement(String name) {
//获取元素信息并判断元素是否存在不存在则抛出异常
ElementInformation element = nameToElementInformation(name);
if (element == null) {
throw new NoSuchElementException("不存在的定位方式:" + name);
}
return elementMap.get(element);
}
}

View File

@ -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;
/**
* <p><b>文件名</b>MultiElement.java</p>
* <p><b>用途</b>
* 提供获取多个元素时使用的基本方法
* </p>
* <p><b>编码时间</b>2020年5月22日上午7:54:28</p>
* <p><b>修改时间</b>2020年5月22日上午7:54:28</p>
* @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<Element> 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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;
/**
* <p><b>文件名</b>SelectBy.java</p>
* <p><b>用途</b>
* 提供获取下拉框中选项元素的方法支持标准型下拉框选项由select与option标签组成的下拉框以及
* 非标准型下拉框选项由普通的divli等元素组成的选项并支持根据关键词查找选项需要注意的是
* 标准下拉选项和非标准下拉选项需要传入的参数不同例如<br>
* 标准下拉框<br>
* &lt;select&nbsp;id='test'&gt;<br>
* &emsp;&lt;option&gt;&lt;/option&gt;<br>
* &emsp;&lt;option&gt;&lt;/option&gt;<br>
* &emsp;&lt;option&gt;其他&lt;/option&gt;<br>
* &lt;/select&gt;<br>
* 对于该标准的下拉框选项只需要定位到//select[@id='test']得到其WebElement对象即可但对于非标准的下拉框其下拉框是由input和button标签构成<br>
* &lt;div&gt;<br>
* &emsp;&lt;span&gt;&lt;input/&gt;&lt;/span&gt;<br>
* &emsp;&lt;span&gt;&lt;button/&gt;&lt;/span&gt;<br>
* &lt;/div&gt;<br>
* 点击button对应的按钮后其下也能弹出选项但其选项是由div标签写入text构成<br>
* &lt;div&nbsp;id='test'&gt;<br>
* &emsp;&lt;div&gt;&lt;/div&gt;<br>
* &emsp;&lt;div&gt;&lt;/div&gt;<br>
* &emsp;&lt;div&gt;其他&lt;/div&gt;<br>
* &lt;/div&gt;<br>
* 对于这种非标准的下拉框选项需要传入选项所在的所有div标签对应的WebElement元素在上例则需要定位到//div[@id='test']/div
* 注意末尾的div不指定数字则可以代表整个选项<br>
* </p>
* <p><b>编码时间</b>2020年5月24日下午3:30:00</p>
* <p><b>修改时间</b>2020年5月24日下午3:30:00</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*
*/
public class SelectBy extends MultiBy {
/**
* 用于存储获取下拉选项时的信息
*/
ElementInformation elementInfo;
/**
* 用于存储下拉选项的元素
*/
ArrayList<Element> option = new ArrayList<>();
/**
* 用于存储下拉选项的文本
*/
ArrayList<String> 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<WebElement> 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异常
* 当查询到有多个包含关键词的选项时则选择第一个选项<br>
* 注意当传入多个关键词时其选项需要全部满足才会返回相应的选项
*
* @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<WebElement> 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();
}
}

View File

@ -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;
/**
* <p><b>文件名</b>ClickEvent.java</p>

View File

@ -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;
/**
* <p><b>文件名</b>EventAction.java</p>

View File

@ -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;
/**
* <p><b>文件名</b>EventInformation.java</p>

View File

@ -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;
/**
* <p><b>文件名</b>EventProxy.java</p>

View File

@ -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 {
/**

View File

@ -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;
/**
* <p>
@ -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<By> byList = new ArrayList<>();
byList.add(By.xpath(xpath));
newElement.setByList(byList);
// 获取元素的所有属性
JSONArray attributes = elementJson.getJSONArray("attributes");

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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;
/**
* 用于按默认的方式创建截图保存位置及截图文件名称<br>
* 默认位置为C:/AutoTest/Screenshot/<br>
* 默认文件名为不带后缀Image
* 用于按默认的方式创建截图默认截图保存位置为项目目录下的Screenshot文件夹<br>
*
* @param driver
* WebDriver对象
* @param driver {@link WebDriver}对象
*/
public Screenshot(WebDriver driver) {
setDriver(driver);
}
/**
* 构造对象<br>
* 默认位置为C:/AutoTest/Screenshot/<br>
* 默认文件名为不带后缀Image<br>
* <b>注意</b>该方法只构建对象由于未传入WebDriver对象故不能直接用于截图
*
* @param driver
* WebDriver对象
* @throws IncorrectDirectoryException
* 传入路径不合法时抛出的异常
*/
public Screenshot(String savePath) {
setSavePath(savePath);
}
/**
* 用于按指定的路径以及默认的文件名保存截图<br/>
@ -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;
}
}

View File

@ -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;
/**
* <p><b>文件名</b>CommonElementTest.java</p>
@ -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("主窗体");
//在获取元素前会判断元素所在窗体由于主窗体是爷爷辈窗体获取元素前会切换工资发放详情窗体