修改元素获取逻辑
This commit is contained in:
parent
b5b45b9563
commit
5753292621
|
@ -0,0 +1,775 @@
|
|||
package pres.auxiliary.work.selenium.element;
|
||||
|
||||
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>对辅助化测试工具selenium的获取元素代码进行的二次封装,通过类中提供的方法以及配合相应存储元素的
|
||||
* xml文件,以更简便的方式对页面元素进行获取,减少编程时的代码量。
|
||||
* </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 1.8
|
||||
*/
|
||||
public abstract class AbstractElement {
|
||||
/**
|
||||
* 用于存储浏览器的WebDriver对象
|
||||
*/
|
||||
WebDriver driver;
|
||||
/**
|
||||
* 用于存储元素信息,由于
|
||||
*/
|
||||
static ElementData elementData;
|
||||
|
||||
/**
|
||||
* 用于存储浏览器对象
|
||||
*/
|
||||
static AbstractBrower brower;
|
||||
/**
|
||||
* 存储单个控件的等待时间
|
||||
*/
|
||||
private HashMap<String, Long> controlWaitTime = new HashMap<String, Long>();
|
||||
/**
|
||||
* 用于存储当前浏览器窗口的Handles值
|
||||
*/
|
||||
private String browserHandles;
|
||||
/**
|
||||
* 存储当前定位的窗体层级,由于多个子类之间需要相互通信,故此处标记为static
|
||||
*/
|
||||
private static ArrayList<String> iframeNameList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 用于当元素获取失败时执行的方法
|
||||
*/
|
||||
ExceptionAction action;
|
||||
|
||||
/**
|
||||
* 用于存储元素通用的等待时间,默认5秒
|
||||
*/
|
||||
private long waitTime = 5;
|
||||
|
||||
/**
|
||||
* 控制是否自动切换窗体,由于通过Event类调用时会构造另一个事件类
|
||||
*/
|
||||
boolean isAutoSwitchIframe = true;
|
||||
|
||||
/**
|
||||
* 通过元素信息类对象({@link ElementData})构造对象
|
||||
* @param brower {@link AbstractBrower}类对象
|
||||
* @param elementData {@link ElementData}类对象
|
||||
*/
|
||||
public AbstractElement(AbstractBrower brower, ElementData elementData) {
|
||||
this.brower = brower;
|
||||
this.driver = brower.getDriver();
|
||||
this.elementData = elementData;
|
||||
}
|
||||
|
||||
public AbstractElement(AbstractBrower brower, String elemenetName) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置元素查找失败时需要执行的方法
|
||||
* @param action 执行方法
|
||||
*/
|
||||
public void setAction(ExceptionAction action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于清除元素查找失败时执行的方法
|
||||
*/
|
||||
public void clearAction() {
|
||||
this.action = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置元素等待时间,默认时间为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;
|
||||
|
||||
/**
|
||||
* 构造元素信息
|
||||
* @param name 元素名称
|
||||
* @param byType 元素定位的By类型,枚举
|
||||
* @param elementType 元素类型,枚举
|
||||
* @param linkKeyList xml文件中需要外部替换的词语
|
||||
*/
|
||||
public ElementInformation(String name, ByType byType, ElementType elementType) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.byType = byType;
|
||||
this.elementType = elementType;
|
||||
splitLinkKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于判断其元素的使用的外链xml文件词语是否与存储的内容一致
|
||||
* @param linkKey 需要判断的外链xml文件词语
|
||||
* @return 是否与类中存储的词语一致
|
||||
*/
|
||||
public boolean linkKeyEquals(List<String> linkKey) {
|
||||
//判断传入的linkKey是否为null,或未传入的linkKey为空,为空,则直接判断linkKeyList的状态
|
||||
if (linkKey == null || linkKey.size() == 0) {
|
||||
//若linkKeyList为null或为空,则可直接返回true;反之,则返回false
|
||||
if (linkKeyList == null || linkKeyList.size() == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//判断linkKey中的元素是否完全存在于linkKeyList,且两个集合的长度一致,若存在一项判断不符合,则返回false
|
||||
if (linkKeyList.containsAll(linkKey) && linkKeyList.size() == linkKey.size()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于对在名称后存在的外链词语进行切分
|
||||
*/
|
||||
private void splitLinkKey() {
|
||||
int index = name.indexOf("=");
|
||||
//判断名称是否存在需要外部替换xml文件的词语
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//对词语按照分隔符进行切分,并去除空格
|
||||
String linkKeyText = name.substring(index).replaceAll(" ", "");
|
||||
//再次按照词语分隔符进行切分
|
||||
linkKeyList = new ArrayList<>(Arrays.asList(linkKeyText.split("\\,")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getEnclosingInstance().hashCode();
|
||||
result = prime * result + ((byType == null) ? 0 : byType.hashCode());
|
||||
result = prime * result + ((elementType == null) ? 0 : elementType.hashCode());
|
||||
result = prime * result + ((linkKeyList == null) ? 0 : linkKeyList.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@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 (!getEnclosingInstance().equals(other.getEnclosingInstance()))
|
||||
return false;
|
||||
if (byType != other.byType)
|
||||
return false;
|
||||
if (elementType != other.elementType)
|
||||
return false;
|
||||
if (linkKeyList == null) {
|
||||
if (other.linkKeyList != null)
|
||||
return false;
|
||||
} else if (!linkKeyList.equals(other.linkKeyList))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private AbstractElement getEnclosingInstance() {
|
||||
return AbstractElement.this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package pres.auxiliary.work.selenium.element;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import pres.auxiliary.work.selenium.location.AbstractRead;
|
||||
import pres.auxiliary.work.selenium.xml.ByType;
|
||||
import pres.auxiliary.work.selenium.location.ByType;
|
||||
|
||||
/**
|
||||
* <p><b>文件名:</b>ElementData.java</p>
|
||||
|
@ -40,22 +40,28 @@ public class ElementData {
|
|||
* 存储元素
|
||||
*/
|
||||
private long waitTime;
|
||||
/**
|
||||
* 存储当前采用的读取文件的方式
|
||||
*/
|
||||
private AbstractRead read;
|
||||
|
||||
/**
|
||||
* 根据元素名称,在配置文件中查找元素,将元素的信息进行存储
|
||||
* @param name 元素名称
|
||||
* @AbstractReadConfig 配置文件类对象
|
||||
* @param AbstractRead 配置文件类对象
|
||||
*/
|
||||
public ElementData(String name, AbstractRead arc) {
|
||||
public ElementData(String name, AbstractRead read) {
|
||||
//存储元素名称
|
||||
this.name = name;
|
||||
//存储读取文件的方式
|
||||
this.read = read;
|
||||
|
||||
//根据传入的读取配置文件类对象,使用其中的返回方法,初始化元素信息
|
||||
byTypeList = arc.findElementByTypeList(name);
|
||||
valueList = arc.findValueList(name);
|
||||
elementType = arc.findElementType(name);
|
||||
iframeNameList = arc.findIframeNameList(name);
|
||||
waitTime = arc.findWaitTime(name);
|
||||
byTypeList = read.findElementByTypeList(name);
|
||||
valueList = read.findValueList(name);
|
||||
elementType = read.findElementType(name);
|
||||
iframeNameList = read.findIframeNameList(name);
|
||||
waitTime = read.findWaitTime(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,5 +112,12 @@ public class ElementData {
|
|||
return waitTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回元素读取方式类对象
|
||||
* @return {@link AbstractRead}子类对象
|
||||
*/
|
||||
public AbstractRead getRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue