添加新的Element类,并改造相应的方法

This commit is contained in:
彭宇琦 2020-04-24 19:53:52 +08:00
parent ba6ba2120b
commit 6cb4ae5322
8 changed files with 315 additions and 359 deletions

View File

@ -40,7 +40,7 @@ import org.openqa.selenium.WebElement;
import pres.auxiliary.directory.exception.UndefinedDirectoryException;
import pres.auxiliary.selenium.browers.FirefoxBrower;
import pres.auxiliary.selenium.event.Event;
import pres.auxiliary.selenium.xml.PosMode;
import pres.auxiliary.selenium.xml.ElementLocationType;
import pres.auxiliary.selenium.xml.ReadXml;
/**
@ -1040,7 +1040,7 @@ public class TestReport extends AbstractReport {
// 由于禅道的项目搜索机制与其他页面不同即使搜索了其<ul>标签下也显示所有的<li>故不能通过搜索后获取第一个元素来对搜索到的项目进行定位
List<WebElement> l = null;
while (true) {
l = d.findElements(r.getBy("项目选项", PosMode.XPATH));
l = d.findElements(r.getBy("项目选项", ElementLocationType.XPATH));
if (l.size() != 0) {
break;
} else {
@ -1072,7 +1072,7 @@ public class TestReport extends AbstractReport {
event.getSelectEvent().select("编码格式下拉框", 1);
event.getSelectEvent().select("记录下拉框", 0);
// 禅道的导出按钮无法点击故需要通过提交表单的方法来导出
d.findElement(r.getBy("导出数据表单", PosMode.XPATH)).submit();
d.findElement(r.getBy("导出数据表单", ElementLocationType.XPATH)).submit();
d.close();
}
}

View File

@ -18,7 +18,7 @@ import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import pres.auxiliary.selenium.tool.RecordTool;
import pres.auxiliary.selenium.xml.PosMode;
import pres.auxiliary.selenium.xml.ElementLocationType;
import pres.auxiliary.selenium.xml.ReadXml;
import pres.auxiliary.selenium.xml.UndefinedElementException;
@ -175,7 +175,7 @@ public abstract class AbstractEvent {
// 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置
// 3.若仍找不到元素则抛出UnrecognizableLocationModeException
try {
PosMode mode = readXml(name);
ElementLocationType mode = readXml(name);
// 判断readXML()方法的返回值是否为空串若为空串则抛出TimeoutException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
@ -186,7 +186,7 @@ public abstract class AbstractEvent {
return mode + "=" + xml.getValue(name, mode);
}
} catch (UndefinedElementException | NullPointerException | InvalidXPathException e) {
PosMode mode = readValue(driver, name);
ElementLocationType mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
@ -197,9 +197,9 @@ public abstract class AbstractEvent {
//若有返回定位方式则根据定位方式类型获取其元素
switch (mode) {
case XPATH:
return PosMode.XPATH.getValue() + "=" + name;
return ElementLocationType.XPATH.getValue() + "=" + name;
case CSS:
return PosMode.CSS.getValue() + "=" + name;
return ElementLocationType.CSS.getValue() + "=" + name;
default:
return "";
}
@ -428,7 +428,7 @@ public abstract class AbstractEvent {
// 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置
// 3.若仍找不到元素则抛出UnrecognizableLocationModeException
try {
PosMode mode = readXml(name);
ElementLocationType mode = readXml(name);
// 判断readXML()方法的返回值是否为空串若为空串则抛出TimeoutException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
@ -439,7 +439,7 @@ public abstract class AbstractEvent {
elements = driver.findElements(xml.getBy(name, mode));
}
} catch (UndefinedElementException | NullPointerException | InvalidXPathException e) {
PosMode mode = readValue(driver, name);
ElementLocationType mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
@ -473,9 +473,9 @@ public abstract class AbstractEvent {
* @param name 控件名称
* @return 查找到的定位方式名称
*/
protected PosMode readXml(String name) {
protected ElementLocationType readXml(String name) {
// 循环逐个在页面上配对有效的标签对应的定位方式
for (PosMode mode : xml.getElementMode(name)) {
for (ElementLocationType mode : xml.getElementMode(name)) {
// 在页面上查找元素定位方式
try {
//自动定位元素所在的窗体
@ -545,7 +545,7 @@ public abstract class AbstractEvent {
* @param text 定位方式
* @return 定位方式的类型
*/
protected PosMode readValue(WebDriver driver, String text) {
protected ElementLocationType readValue(WebDriver driver, String text) {
// 定义判断参数为xpath的字符
String judgeXpath = "/";
@ -558,12 +558,12 @@ public abstract class AbstractEvent {
if (text.indexOf(judgeXpath) == 0) {
// 查找该定位方式在有限的时间内是否内被查到
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(text)));
return PosMode.XPATH;
return ElementLocationType.XPATH;
// 将等待时间设置回原来的
} else if (text.indexOf(judgeCss) == 0) {
// 匹配css判断方法判断text的前四个字符是否是html
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(text)));
return PosMode.CSS;
return ElementLocationType.CSS;
} else {
return null;
}

View File

@ -6,7 +6,7 @@ import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import pres.auxiliary.selenium.xml.PosMode;
import pres.auxiliary.selenium.xml.ElementLocationType;
/**
* <p><b>文件名</b>JsEvent.java</p>
@ -158,10 +158,10 @@ public class JsEvent extends AbstractEvent {
String[] element = getElementPosition(text).split("=");
// 判断定位方式若定位方式为css则按照querySelector()方式进行选择其他的方式均按照xpath来获取
if (PosMode.XPATH.getValue().equalsIgnoreCase(element[0])) {
if (ElementLocationType.XPATH.getValue().equalsIgnoreCase(element[0])) {
script = "document.evaluate('" + element[1]
+ "', document, null, XPathResult.ANY_TYPE, null).iterateNext()";
} else if (PosMode.CSS.getValue().equalsIgnoreCase(element[0])) {
} else if (ElementLocationType.CSS.getValue().equalsIgnoreCase(element[0])) {
script = "document.querySelector(" + element[1] + ")";
} else {
script = "document.evaluate('//*[@" + element[0] + "=\"" + element[1]

View File

@ -19,7 +19,7 @@ package pres.auxiliary.selenium.xml;
* @since JDK 12
*
*/
public enum PosMode {
public enum ElementLocationType {
/** 通过xpath方式进行定位 */
XPATH("xpath"),
/** 通过css方式进行定位 */
@ -40,7 +40,7 @@ public enum PosMode {
*/
private String value;
private PosMode(String value) {
private ElementLocationType(String value) {
this.value = value;
}
@ -52,26 +52,4 @@ public enum PosMode {
public String getValue() {
return value;
}
public static PosMode getMode(String modeName) {
switch (modeName) {
case "xpath":
return XPATH;
case "css":
return CSS;
case "classname":
return CLASSNAME;
case "id":
return ID;
case "linktext":
return LINKTEXT;
case "name":
return NAME;
case "tagname":
return TAGNAME;
default:
throw new IllegalArgumentException("Unexpected value: " + modeName);
}
}
}

View File

@ -55,6 +55,11 @@ public class ReadXml {
*/
private final String END_SIGN = "}";
/**
* 存储xml文件类对象
*/
private File xmlFile;
/**
* 用于构造对象并设置xml文件
*
@ -79,21 +84,30 @@ public class ReadXml {
// 重新构造Document对象使其指向新的XML文件
try {
dom = new SAXReader().read(xmlFile);
this.xmlFile = xmlFile;
} catch (DocumentException e) {
// 若抛出异常则将异常转换为自定义的IncorrectXMLFileException异常使其不需要在编译时处理
throw new IncorrectXmlPathException("XML文件不正确或XML路径不正确");
}
}
/**
* 用于返回相应的xml文件类对象
* @return xml文件类对象
*/
public File getXmlFile() {
return xmlFile;
}
/**
* 返回当前有效的元素定位标签
*
* @param name 元素名称
* @return 当前元素有效的定位名称多个标签名称以空格隔开
*/
public List<PosMode> getElementMode(String name) {
public List<ElementLocationType> getElementMode(String name) {
// 用于存储元素定位方式的标签名称
List<PosMode> modes = new ArrayList<>();
List<ElementLocationType> modes = new ArrayList<>();
try {
@SuppressWarnings("unchecked")
@ -105,7 +119,7 @@ public class ReadXml {
for (Element element : elements) {
// 若标签可用且标签内属性不为空则将该标签的名称存储在s中
if ((element.attribute("is_use") == null || element.attributeValue("is_use").equalsIgnoreCase("true"))) {
modes.add(PosMode.getMode(element.getName()));
modes.add(getMode(element.getName()));
}
}
} catch (NullPointerException e) {
@ -120,13 +134,13 @@ public class ReadXml {
* 根据元素名称在指定的xml文件中查找到相应的元素返回其元素的信息{@link By}类返回
*
* @param name 元素名称
* @param mode 定位方式枚举类对象参见{@link PosMode}
* @param mode 定位方式枚举类对象参见{@link ElementLocationType}
* @return 元素对应的{@link By}类对象
*
* @throws UndefinedElementException 未找到相应的模板元素时抛出的异常
* @throws NoSuchSignValueException 模板中存在为定义值的标志时抛出的异常
*/
public By getBy(String name, PosMode mode) {
public By getBy(String name, ElementLocationType mode) {
// 存储从xml文件中读取到的元素定位
String elementPos = getValue(name, mode);
@ -159,13 +173,13 @@ public class ReadXml {
* 用于根据元素名称及定位方式来返回其定位方式的值
*
* @param name 元素名称
* @param mode 定位方式枚举类对象参见{@link PosMode}
* @param mode 定位方式枚举类对象参见{@link ElementLocationType}
* @return xml文件中的相应元素的定位值
*
* @throws UndefinedElementException 未找到相应的模板元素时抛出的异常
* @throws NoSuchSignValueException 模板中存在为定义值的标志时抛出的异常
*/
public String getValue(String name, PosMode mode) {
public String getValue(String name, ElementLocationType mode) {
// 用于拼接读取XML中元素的xpath为了兼容iframe标签故此处使用*符号来查找元素
String xmlXpath = "//*[@name='" + name + "']/" + mode.getValue();
// 获取元素节点并将其转为Element对象以便于获取该元素的属性值
@ -200,6 +214,21 @@ public class ReadXml {
return iframeName;
}
/**
* 该方法用于判断当前查找的元素是否存在于xml文件中
* @return 元素是否存在于xml
*/
public boolean isElement(String name) {
//获取元素的xpath查找所有带name属性的与传入的name相同元素
String xpath = "//*[@name='" + name + "']";
//若不存在该节点则返回false反之则返回true
if (dom.getRootElement().selectSingleNode(xpath) == null) {
return false;
} else {
return true;
}
}
/**
* 用于模板的元素的定位查找返回其相应的定位
*
@ -212,7 +241,7 @@ public class ReadXml {
* @throws NoSuchSignValueException 模板中存在为定义值的标志时抛出的异常
*/
@SuppressWarnings("unchecked")
private String getTempletPath(Element element, String name, PosMode mode) {
private String getTempletPath(Element element, String name, ElementLocationType mode) {
// 通过元素的temp_id定位到模板的id上
Element templetElement = (Element) dom.selectSingleNode(
"//templet/" + mode.getValue() + "[@id='" + element.attribute("temp_id").getValue() + "']");
@ -246,4 +275,31 @@ public class ReadXml {
return path;
}
/**
* 根据xml内容标签名称获取相应的ElementLocationType枚举
* @param modeName 定位标签名称
* @return ElementLocationType枚举
*/
private static ElementLocationType getMode(String modeName) {
switch (modeName) {
case "xpath":
return ElementLocationType.XPATH;
case "css":
return ElementLocationType.CSS;
case "classname":
return ElementLocationType.CLASSNAME;
case "id":
return ElementLocationType.ID;
case "linktext":
return ElementLocationType.LINKTEXT;
case "name":
return ElementLocationType.NAME;
case "tagname":
return ElementLocationType.TAGNAME;
default:
throw new IllegalArgumentException("Unexpected value: " + modeName);
}
}
}

View File

@ -0,0 +1,39 @@
package pres.auxiliary.work.selenium.element;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class CommonElement extends Element {
/**
* 构造对象并存储浏览器的WebDriver对象
*
* @param driver 浏览器的WebDriver对象
*/
public CommonElement(WebDriver driver) {
super(driver);
}
/**
* 用于根据xml文件中元素的名称返回对应的WebElement对象该方法亦可传入元素
* 的xpath或css定位内容来获取元素的WebElement对象
* @param name 元素的名称或元素定位内容
* @return WebElement对象
*/
public WebElement getWebElement(String name) {
//TODO 编写返回元素的方法
//1.判断传入的参数在xml文件中是否能找到
//1.1 若能找到
//1.1.1 获取元素内容
//1.1.2 获取元素所在的frame以及父层的frame
//1.1.3 对元素的frame自动进行切换
//1.1.4 调用判断元素是否存在的方法对元素进行存在判断
//1.1.4.1 存在获取并返回
//1.1.4.2 不存在抛出异常
//1.2 若不能找到调用判断方法对传入的内容判断是xpath或css
//1.2.1 若均不是抛出异常
//1.2.2 若是则调用判断元素是否存在的方法对元素进行存在判断
return null;
}
}

View File

@ -2,28 +2,26 @@ 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.stream.Collectors;
import org.dom4j.InvalidXPathException;
import org.junit.rules.ExpectedException;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import pres.auxiliary.selenium.event.EventConstants;
import pres.auxiliary.selenium.event.NoSuchWindownException;
import pres.auxiliary.selenium.event.UnrecognizableLocationModeException;
import pres.auxiliary.selenium.tool.RecordTool;
import pres.auxiliary.selenium.xml.PosMode;
import pres.auxiliary.selenium.xml.ElementLocationType;
import pres.auxiliary.selenium.xml.ReadXml;
import pres.auxiliary.selenium.xml.UndefinedElementException;
public class Element {
/**
@ -35,13 +33,9 @@ public class Element {
*/
private ReadXml xml = new ReadXml();
/**
* 设置显示等待的超时时间默认3秒
* 全局控件等待时间
*/
private long waitTime = 3;
/**
* 用于构造显示等待类对象
*/
private WebDriverWait wait;
/**
* 存储单个控件的等待时间
*/
@ -53,21 +47,12 @@ public class Element {
/**
* 存储当前定位的窗体层级
*/
private ArrayList<String> iframeNames = new ArrayList<>();
private ArrayList<String> iframeNameList = new ArrayList<>();
/**
* 控制是否自动切换窗体由于通过Event类调用时会构造另一个事件类但每个类都应共享一个开关故需要加上static
*/
private boolean switchIframe = true;
/**
* 用于存储上一个获取到的元素
*/
private WebElement oldElement = null;
/**
* 用于存储上一个获取到的元素的style属性
*/
private String oldElementStyle = "";
boolean switchIframe = true;
/**
* 构造对象并存储浏览器的WebDriver对象
@ -77,7 +62,6 @@ public class Element {
public Element(WebDriver driver) {
this.driver = driver;
browserHandles = this.driver.getWindowHandle();
wait = new WebDriverWait(driver, waitTime, EventConstants.FIND_TIME);
}
/**
@ -86,8 +70,7 @@ public class Element {
* @param waitTime 等待时间
*/
public void setWaitTime(long waitTime) {
this.waitTime = waitTime;
wait = new WebDriverWait(driver, this.waitTime, 200);
// wait = new WebDriverWait(driver, waitTime, 200);
}
/**
@ -108,57 +91,18 @@ public class Element {
}
/**
* 用于设置指向存储元素定位方式的xml文件对象
*
* 用于设置指向存储元素定位方式的xml文件对象并根据传参判断窗体是否需要回到顶层
* @param xmlFile 存储元素定位方式的xml文件对象
* @param isBreakRootFrame 是否需要将窗体切回到顶层
*/
public void setXmlFile(File xmlFile) {
public void setXmlFile(File xmlFile, boolean isBreakRootFrame) {
xml.setXmlPath(xmlFile);
if (isBreakRootFrame) {
switchRootFrame();
}
}
/**
* 用于返回写入xml文件的或传入的元素定位方式mode=position的形式输出
*
* @param name 控件的名称或xpath与css定位方式
* @return 元素定位方式
*/
public String getElementPosition(String name) {
// 智能匹配方式
// 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止
// 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置
// 3.若仍找不到元素则抛出UnrecognizableLocationModeException
try {
PosMode mode = readXml(name);
// 判断readXML()方法的返回值是否为空串若为空串则抛出TimeoutException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
throw new TimeoutException("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
} else {
// 页面查找元素并存储该元素
return mode + "=" + xml.getValue(name, mode);
}
} catch (UndefinedElementException | NullPointerException | InvalidXPathException e) {
PosMode mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素定位方式类型无法识别:" + name);
// 若都不匹配则抛出异常
throw new UnrecognizableLocationModeException("元素定位方式类型无法识别:" + name);
} else {
//若有返回定位方式则根据定位方式类型获取其元素
switch (mode) {
case XPATH:
return PosMode.XPATH.getValue() + "=" + name;
case CSS:
return PosMode.CSS.getValue() + "=" + name;
default:
return "";
}
}
}
}
/**
* 用于对单个控件设置等待时间
@ -174,47 +118,77 @@ public class Element {
* 该方法用于将窗体切回顶层当本身是在最顶层时则该方法将使用无效
*/
public void switchRootFrame() {
//切换窗口至顶层
driver.switchTo().defaultContent();
iframeNames.clear();
//清空iframeNameList中的内容
iframeNameList.clear();
}
/**
* 该方法用于将窗体切换到上一层父层当本身是在最顶层时则该方法将使用无效
* 该方法用于将窗体切换到上一层父层若当前层只有一层则调用方法后切回顶层
* 若当前层为最顶层时则该方法将使用无效
*/
public void switchParentFrame() {
//若iframeNameList大于1层则向上切换窗体
if (iframeNameList.size() > 1) {
driver.switchTo().parentFrame();
iframeNames.remove(iframeNames.size() - 1);
iframeNameList.remove(iframeNameList.size() - 1);
} else if (iframeNameList.size() == 1) {
//若iframeNameList等于1层则调用切换至顶层的方法
switchRootFrame();
} else {
//若iframeNameList小于1层则不做操作
return;
}
}
/**
* 该方法用于通过悬浮窗名称使用xpath的定位方式将页面切换至悬浮窗iframe标签
* 通过传入在xml文件中的控件名称到类中指向的xml文件中查找控件
* 名称对应的定位方式或直接传入xpath与css定位方式
* 根据定位方式对相应的窗体进行定位当传入的窗体为当前窗体的前层父层窗体时
* 通过该方法将调用切换父层的方法将窗体切换到父层上例如<br>
* 当前存在f1, f2, f3, f4四层窗体则调用方法<br>
* switchFrame("f2")<br>
* 此时窗体将回到f2层无需再从顶层开始向下切换<br>
* 注意窗体的切换按照从前向后的顺序进行切换切换顺序不能相反
*
* @param name 悬浮窗的名称
* @param names 的名称或xpath与css定位方式
*/
public void switchFrame(String name) {
//获取父窗体的窗体名称
String parentIframeName = xml.getIframeName(name);
//判断窗体是否存在父窗体若不存在父窗体返回值为空则切换若有则递归调用该方法直到找到最顶层窗体为止
if (parentIframeName.isEmpty()) {
//清空iframeNames中的内容
iframeNames.clear();
//将窗体切换到顶层
driver.switchTo().defaultContent();
} else {
switchFrame(parentIframeName);
public void switchFrame(String...names) {
switchFrame(Arrays.asList(names));
}
//记录当前自动切换的窗体的状态
boolean isSwitchFrame = isSwitchIframe();
//切换窗体前设置不自动切换窗体避免窗体的循环切换
setSwitchIframe(false);
/**
* 通过传入在xml文件中的控件名称到类中指向的xml文件中查找控件
* 名称对应的定位方式或直接传入xpath与css定位方式
* 根据定位方式对相应的窗体进行定位当传入的窗体为当前窗体的前层父层窗体时
* 通过该方法将调用切换父层的方法将窗体切换到父层上例如<br>
* 当前存在f1, f2, f3, f4四层窗体则调用方法<br>
* List<String> nameList = new ArrayList<String>();<br>
* nameList.add("f2");<br>
* switchFrame(nameList)<br>
* 此时窗体将回到f2层无需再从顶层开始向下切换<br>
* 注意窗体的切换按照从前向后的顺序进行切换切换顺序不能相反
*
* @param nameList 存储窗体的名称或xpath与css定位方式的List集合
*/
public void switchFrame(List<String> nameList) {
nameList.forEach(name -> {
//判断name指向的窗体是否在iframeNameList中若存在则向上切换父层直到切换到name指向的窗体若不存在则直接切换并添加窗体名称
if (iframeNameList.contains(name)) {
//获取name窗体在iframeNameList中的位置
int index = iframeNameList.indexOf(name);
//获取需要向上切换窗体的次数公式为推断出来
int count = iframeNameList.size() - index - 1;
for (int i = 0; i < count; i++) {
switchParentFrame();
}
} else {
//切换窗体
driver.switchTo().frame(judgeElementMode(name));
//切换窗体后还原原始的切换窗体状态
setSwitchIframe(isSwitchFrame);
//存储窗体切换记录
iframeNames.add(name);
driver.switchTo().frame(recognitionElements(name).get(0));
iframeNameList.add(name);
}
});
}
/**
@ -268,7 +242,7 @@ public class Element {
driver.switchTo().window(newWinHandle);
// 调用judgeElementMode()方法来判断元素是否存在如果元素存在则返回相应页面的WebDriver对象若抛出异常元素不存在则返回当前
try {
judgeElementMode(controlName);
recognitionElements(controlName).get(0);
} catch (TimeoutException e) {
continue;
}
@ -324,29 +298,6 @@ public class Element {
return driver.switchTo().alert().getText();
}
/**
* <p>
* 用于根据传入的控件名称或定位方式对控件在页面上定位返回其WebElement对象形参可以传入在xml文件中元素的名称
* 亦可以传入页面元素的定位方式但目前识别只支持xpath和css两种方式
* 该方法获取的是单个元素但本质是调用了{@link #judgeElementModes(String)}方法只是将其容器中第一个元素进行返回
* 可用于普通元素事件获取页面元素中使用
* </p>
* <p>
* 元素识别判断方式按照以下步骤进行<br>
* 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止<br>
* 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置<br>
* 3.若仍找不到元素则抛出UnrecognizableLocationModeException
* </p>
*
* @param text 元素名称或元素的定位方式
* @return 返回页面元素WebElement对象
* @throws TimeoutException 元素在指定时间内未查找到时抛出的异常
* @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
*/
protected WebElement judgeElementMode(String name) {
return judgeElementModes(name).get(0);
}
/**
* <p>
* 用于根据传入的控件名称或定位方式对控件在页面上定位返回其WebElement对象形参可以传入在xml文件中元素的名称
@ -365,191 +316,123 @@ public class Element {
* @throws TimeoutException 元素在指定时间内未查找到时抛出的异常
* @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
*/
protected List<WebElement> judgeElementModes(String name) {
// 获取当前的等待时间若有对单个控件设置等待时间时此处可以将等待时间设置回原来的时间
long time = getWaitTime();
// 判断是否有设置对单个控件增加等待时间若存在该控件则将等待时间设置为该控件设置的等待时间
if (controlWaitTime.containsKey(name)) {
setWaitTime(controlWaitTime.get(name));
}
// 存储最终识别得到元素
List<WebElement> elements = null;
// 智能匹配方式
// 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止
// 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置
// 3.若仍找不到元素则抛出UnrecognizableLocationModeException
try {
PosMode mode = readXml(name);
// 判断readXML()方法的返回值是否为空串若为空串则抛出TimeoutException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
throw new TimeoutException("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
List<WebElement> recognitionElements(String name) {
//判断元素是否存在于xml文件中根据返回的状态来判断调用的方法
if (xml.isElement(name)) {
return findXmlElement(name);
} else {
// 页面查找元素并存储该元素
elements = driver.findElements(xml.getBy(name, mode));
return findCommonElement(name, judgeElementLocationMode(name));
}
} catch (UndefinedElementException | NullPointerException | InvalidXPathException e) {
PosMode mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素定位方式类型无法识别:" + name);
// 若都不匹配则抛出异常
throw new UnrecognizableLocationModeException("元素定位方式类型无法识别:" + name);
} else {
//若有返回定位方式则根据定位方式类型获取其元素
switch (mode) {
case XPATH:
elements = driver.findElements(By.xpath(name));
break;
case CSS:
elements = driver.findElements(By.cssSelector(name));
break;
default:
break;
}
}
}
// 设置等待时间为原来的等待时间
setWaitTime(time);
// 返回页面元素对象
return elements;
}
/**
* 该方法用于通过传入的控件名称在xml文件中查找其元素相应的定位方式并在页面上进行查找 若在相应的时间内查找到该元素则将其定位方式进行返回
*
* @param name 控件名称
* @return 查找到的定位方式名称
* 根据传入的元素定位方式返回在页面上查找到的WebElement对象
* @param name 元素内容
* @return
*/
protected PosMode readXml(String name) {
// 循环逐个在页面上配对有效的标签对应的定位方式
for (PosMode mode : xml.getElementMode(name)) {
// 在页面上查找元素定位方式
try {
//自动定位元素所在的窗体
if (isSwitchIframe()) {
autoSwitchIframe(xml.getIframeName(name));
}
//查找元素
wait.until(ExpectedConditions.presenceOfElementLocated(xml.getBy(name, mode)));
} catch (TimeoutException exception) {
// 若查找超时则重新查找
continue;
}
// 若在页面上找到该元素则将该元素的定位方式存储
return mode;
private List<WebElement> findCommonElement(String name, By by) {
if (isFindWebElement(controlWaitTime.containsKey(name) ? controlWaitTime.get(name) : waitTime, by)) {
return driver.findElements(by);
}
// 若循环结束后仍未能找到该元素则返回一个空串
return null;
throw new TimeoutException("元素“" + name + "”无法查找,请核对定位方式:" + by.toString());
}
/**
* 用于自动定位元素所在窗体
* @param iframeName 元素所在窗体名称
* 根据传入的元素名称到指定的xml文件中查找相应的有效的定位方式并在页面中查找返回查找到的元素对象
* @param name 需要查找的元素名称
* @return 页面中查找到的元素
* @throws TimeoutException 当元素不能找到时抛出的异常
*/
protected void autoSwitchIframe(String iframeName) {
//判断传入的窗体名称是否为空若为空说明元素在主窗体上
if (iframeName.isEmpty()) {
//判断当前定位是否在主窗体上iframeNames无元素时若不在主窗体上则切换到主窗体若在则直接结束
if (iframeNames.size() != 0) {
//将窗体切换到顶层
switchRootFrame();
return;
} else {
return;
private List<WebElement> findXmlElement(String name) {
// 循环逐个在页面上配对有效的标签对应的定位方式
for (ElementLocationType mode : xml.getElementMode(name)) {
if (isFindWebElement(controlWaitTime.containsKey(name) ? controlWaitTime.get(name) : waitTime, xml.getBy(name, mode))) {
driver.findElements(xml.getBy(name, mode));
}
}
//判断当前元素所在的窗体是否与已切换的窗体列表中最后一个元素当前窗体的内容相同相同则直接返回无需操作
//获取最后一层窗体的名称若iframeNames为空则返回空串
String nowIframeName = (iframeNames.isEmpty() ? "" : iframeNames.get(iframeNames.size() - 1));
if (iframeName.equals(nowIframeName)) {
return;
}
//若传入的字符串不为空则表示当前窗体不在主窗体上则判断其是否在已切换的窗体列表中若在则通过层级返回
//无需再次重新定位避免等待时间太长若不在则重新定位窗体
int index = 0;
if ((index = iframeNames.indexOf(iframeName)) > -1) {
//循环将窗体一层一层返回
for(int i = 1; i < iframeNames.size() - index; i++) {
switchParentFrame();
}
} else {
//若当前元素的窗体不在当前窗体的父窗体则重新定位窗体
switchFrame(iframeName);
}
// 若循环结束后仍未能找到该元素则返回一个空串
throw new TimeoutException("元素“" + name + "”无法查找请核对xml文件" + xml.getXmlFile().getName() + "\n文件路径" + xml.getXmlFile().getAbsolutePath());
}
/**
* 该方法用于在xml文件查找不到对应的元素时则再对传入的参数进行xpath和css的比较
* 以确认是否为直接传值若不为xpath和css中的一种则抛出UnrecognizableLocationModeException
*
* @param driver WebDriver对象
* @param text 定位方式
* @return 定位方式的类型
* 用于判断传入参数的定位方式只识别xpath与css两种定位方式需要注意的是该方法主要用于
* 识别xptah若元素的定位方式不是xpath定位则根据css方式来返回
* @param text 元素定位方式
* @return 相应的By对象
*/
protected PosMode readValue(WebDriver driver, String text) {
private By judgeElementLocationMode(String text) {
// 定义判断参数为xpath的字符
String judgeXpath = "/";
// 定义判断参数为css的字符
String judgeCss = "html";
try {
// 如果抛出元素名称查找不到的的异常则对应匹配xpath和css两种定位方式
// 匹配xpath定位判定方法判断text的第一个字符是否是/
if (text.indexOf(judgeXpath) == 0) {
// 查找该定位方式在有限的时间内是否内被查到
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(text)));
return PosMode.XPATH;
// 将等待时间设置回原来的
} else if (text.indexOf(judgeCss) == 0) {
// 匹配css判断方法判断text的前四个字符是否是html
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(text)));
return PosMode.CSS;
return By.xpath(text);
} else {
return null;
return By.cssSelector(text);
}
} catch (TimeoutException exception) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素查找超时或不存在,请检查“" + text + "”定位方式");
throw new TimeoutException("元素查找超时或不存在,请检查“" + text + "”定位方式");
}
/**
* 用于获取元素在xml文件中所有的父窗体并以集合的形式返回存储的顺序为父窗体在前子窗体在后若当前元素没有窗体
* 则集合的长度为0
* @param name 元素在xml文件中的名称
* @return 元素在xml文件中所有的父窗体集合
*/
private 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;
}
/**
* 用于将页面控件元素高亮显示
* @param newElement 当前指向的元素
*/
protected void elementHight(WebElement newElement) {
//判断当前指向的元素是否与原来存储的元素一致若不一致且有之前有存储元素则解除之前元素的控件高亮
if (oldElement != newElement && oldElement != null) {
// 解除控件高亮若因为页面跳转导致页面过期时则不处理其异常
try {
((JavascriptExecutor) getDriver()).executeScript("arguments[0].setAttribute('style',arguments[1])",
oldElement, oldElementStyle);
} catch (StaleElementReferenceException exception) {
}
}
void elementHight(WebElement newElement) {
//获取当前指向的元素的style属性
String newElementStyle = newElement.getAttribute("style");
// 控件高亮
((JavascriptExecutor) getDriver()).executeScript("arguments[0].setAttribute('style',arguments[1])", newElement,
newElementStyle + "background:yellow;solid:red;");
//将当前指向的元素及其属性存储至属性中
oldElement = newElement;
oldElementStyle = newElementStyle;
//解除高亮
((JavascriptExecutor) getDriver()).executeScript("arguments[0].setAttribute('style',arguments[1])",
newElement, newElementStyle + "background:yellow;solid:red;");
}
/**
* 根据页面的等待时间和元素定位方式在页面上查找相应的元素返回是否能查到元素
* @param time 控件等待时间
* @param by 元素定位方式
* @return 是否能查找到的元素
*/
boolean isFindWebElement(long time, By by) {
// new WebDriverWait(driver, time, 200).until(ExpectedConditions.elementToBeClickable(by));
//当查找到元素时则返回true若查不到元素则会抛出异常故返回false
try {
new WebDriverWait(driver, time, 200).until(ExpectedConditions.presenceOfElementLocated(by));
return true;
} catch (Exception e) {
return false;
}
}
}

View File

@ -7,7 +7,7 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import pres.auxiliary.selenium.xml.PosMode;
import pres.auxiliary.selenium.xml.ElementLocationType;
import pres.auxiliary.selenium.xml.ReadXml;
/**
@ -37,73 +37,73 @@ public class TestReadXml {
}
/**
* 用于测试{@link ReadXml#getBy(String, PosMode)}方法获取普通元素
* 用于测试{@link ReadXml#getBy(String, ElementLocationType)}方法获取普通元素
*/
@Test
public void getByTest_Element() {
System.out.println(r.getBy("XX控件7", PosMode.XPATH));
System.out.println(r.getBy("XX控件7", ElementLocationType.XPATH));
}
/**
* 用于测试{@link ReadXml#getBy(String, PosMode)}方法获取窗体元素
* 用于测试{@link ReadXml#getBy(String, ElementLocationType)}方法获取窗体元素
*/
@Test
public void getByTest_Iframe() {
System.out.println(r.getBy("窗体1.1", PosMode.XPATH));
System.out.println(r.getBy("窗体1.1", ElementLocationType.XPATH));
}
/**
* 用于测试{@link ReadXml#getBy(String, PosMode)}方法获取模板元素
* 用于测试{@link ReadXml#getBy(String, ElementLocationType)}方法获取模板元素
*/
@Test
public void getByTest_Templet() {
System.out.println(r.getBy("XX控件11", PosMode.XPATH));
System.out.println(r.getBy("窗体1", PosMode.CSS));
System.out.println(r.getBy("XX控件11", ElementLocationType.XPATH));
System.out.println(r.getBy("窗体1", ElementLocationType.CSS));
}
/**
* 用于测试{@link ReadXml#getBy(String, PosMode)}方法获取顶层元素
* 用于测试{@link ReadXml#getBy(String, ElementLocationType)}方法获取顶层元素
*/
@Test
public void getByTest_RootElement() {
System.out.println(r.getBy("XX控件1", PosMode.XPATH));
System.out.println(r.getBy("XX控件1", ElementLocationType.XPATH));
}
/**
* 用于测试{@link ReadXml#getValue(String, PosMode)}方法获取普通元素
* 用于测试{@link ReadXml#getValue(String, ElementLocationType)}方法获取普通元素
*/
@Test
public void getElementValueTest_Element() {
System.out.println(r.getValue("XX控件7", PosMode.XPATH));
System.out.println(r.getValue("XX控件7", ElementLocationType.XPATH));
}
/**
* 用于测试{@link ReadXml#getValue(String, PosMode)}方法获取窗体元素
* 用于测试{@link ReadXml#getValue(String, ElementLocationType)}方法获取窗体元素
*/
@Test
public void getElementValueTest_Iframe() {
System.out.println(r.getValue("窗体1.1", PosMode.XPATH));
System.out.println(r.getValue("窗体1.1", ElementLocationType.XPATH));
}
/**
* 用于测试{@link ReadXml#getValue(String, PosMode)}方法获取模板元素
* 用于测试{@link ReadXml#getValue(String, ElementLocationType)}方法获取模板元素
*/
@Test
public void getElementValueTest_Templet() {
System.out.println(r.getValue("XX控件11", PosMode.XPATH));
System.out.println(r.getValue("窗体1", PosMode.CSS));
System.out.println(r.getValue("XX控件11", ElementLocationType.XPATH));
System.out.println(r.getValue("窗体1", ElementLocationType.CSS));
}
/**
* 用于测试{@link ReadXml#getValue(String, PosMode)}方法获取顶层元素
* 用于测试{@link ReadXml#getValue(String, ElementLocationType)}方法获取顶层元素
*/
@Test
public void getElementValueTest_RootElement() {
System.out.println(r.getValue("XX控件1", PosMode.XPATH));
System.out.println(r.getValue("XX控件1", ElementLocationType.XPATH));
}
/**
* 用于测试{@link ReadXml#getIframeName(String, PosMode)}方法获取普通元素
* 用于测试{@link ReadXml#getIframeName(String, ElementLocationType)}方法获取普通元素
*/
@Test
public void getIframeNameTest_Element() {
@ -111,7 +111,7 @@ public class TestReadXml {
}
/**
* 用于测试{@link ReadXml#getIframeName(String, PosMode)}方法获取窗体元素
* 用于测试{@link ReadXml#getIframeName(String, ElementLocationType)}方法获取窗体元素
*/
@Test
public void getIframeNameTest_Iframe() {
@ -119,7 +119,7 @@ public class TestReadXml {
}
/**
* 用于测试{@link ReadXml#getIframeName(String, PosMode)}方法获取模板元素
* 用于测试{@link ReadXml#getIframeName(String, ElementLocationType)}方法获取模板元素
*/
@Test
public void getIframeNameTest_Templet() {