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(recognitionElements(name).get(0));
+ iframeNameList.add(name);
+ }
+ });
+ }
+
/**
* 该方法可用于切换弹出的窗口(新标签或新窗口),并返回新窗口的WebDriver对象,若无新窗口,则返回当前的窗口的WebDriver对象。
* 注意,该方法只能切换弹出一个窗口的情况,若有多个窗口,通过该方法无法准确定位,可参考方法{@link #switchWindow(String)}。
@@ -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();
}
- /**
- *
- * 用于根据传入的控件名称或定位方式,对控件在页面上定位,返回其WebElement对象。形参可以传入在xml文件中元素的名称,
- * 亦可以传入页面元素的定位方式,但目前识别只支持xpath和css两种方式。
- * 该方法获取的是单个元素,但本质是调用了{@link #judgeElementModes(String)}方法,只是将其容器中第一个元素进行返回。
- * 可用于普通元素事件获取页面元素中使用
- *
- *
- * 元素识别判断方式按照以下步骤进行:
- * 1.先对xml文件进行扫描,若存在该元素对应的标签,则读取xml文件的定位方式,并识别有效的定位方式一一匹配,直到正确为止;
- * 2.若在xml文件中查找不到该元素,则按照xpath和css的规则进行匹配,直到判断出该元素的定位方式位置;
- * 3.若仍找不到元素,则抛出UnrecognizableLocationModeException
- *
- *
- * @param text 元素名称或元素的定位方式
- * @return 返回页面元素WebElement对象
- * @throws TimeoutException 元素在指定时间内未查找到时,抛出的异常
- * @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
- */
- protected WebElement judgeElementMode(String name) {
- return judgeElementModes(name).get(0);
- }
-
/**
*
* 用于根据传入的控件名称或定位方式,对控件在页面上定位,返回其WebElement对象。形参可以传入在xml文件中元素的名称,
@@ -365,191 +316,123 @@ public class Element {
* @throws TimeoutException 元素在指定时间内未查找到时,抛出的异常
* @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
*/
- protected List judgeElementModes(String name) {
- // 获取当前的等待时间,若有对单个控件设置等待时间时,此处可以将等待时间设置回原来的时间
- long time = getWaitTime();
- // 判断是否有设置对单个控件增加等待时间,若存在该控件,则将等待时间设置为该控件设置的等待时间
- if (controlWaitTime.containsKey(name)) {
- setWaitTime(controlWaitTime.get(name));
+ List recognitionElements(String name) {
+ //判断元素是否存在于xml文件中,根据返回的状态,来判断调用的方法
+ if (xml.isElement(name)) {
+ return findXmlElement(name);
+ } else {
+ return findCommonElement(name, judgeElementLocationMode(name));
}
-
- // 存储最终识别得到元素
- List 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 + "”对应元素的定位方式");
- } else {
- // 页面查找元素,并存储该元素
- elements = driver.findElements(xml.getBy(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:
- 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;
- }
+ private List findCommonElement(String name, By by) {
+ if (isFindWebElement(controlWaitTime.containsKey(name) ? controlWaitTime.get(name) : waitTime, by)) {
+ return driver.findElements(by);
+ }
+
+ // 若循环结束后仍未能找到该元素,则返回一个空串
+ throw new TimeoutException("元素“" + name + "”无法查找,请核对定位方式:" + by.toString());
+ }
- // 若在页面上找到该元素,则将该元素的定位方式存储
- return mode;
+ /**
+ * 根据传入的元素名称,到指定的xml文件中查找相应的有效的定位方式,并在页面中查找,返回查找到的元素对象
+ * @param name 需要查找的元素名称
+ * @return 页面中查找到的元素
+ * @throws TimeoutException 当元素不能找到时抛出的异常
+ */
+ private List 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));
+ }
}
// 若循环结束后仍未能找到该元素,则返回一个空串
- return null;
-
+ throw new TimeoutException("元素“" + name + "”无法查找,请核对xml文件:" + xml.getXmlFile().getName() + "\n文件路径:" + xml.getXmlFile().getAbsolutePath());
}
/**
- * 用于自动定位元素所在窗体
- * @param iframeName 元素所在窗体名称
+ * 用于判断传入参数的定位方式,只识别xpath与css两种定位方式。需要注意的是,该方法主要用于
+ * 识别xptah,若元素的定位方式不是xpath定位,则根据css方式来返回
+ * @param text 元素定位方式
+ * @return 相应的By对象
*/
- protected void autoSwitchIframe(String iframeName) {
- //判断传入的窗体名称是否为空,若为空,说明元素在主窗体上
- if (iframeName.isEmpty()) {
- //判断当前定位是否在主窗体上(iframeNames无元素时),若不在主窗体上,则切换到主窗体,若在,则直接结束
- if (iframeNames.size() != 0) {
- //将窗体切换到顶层
- switchRootFrame();
- return;
- } else {
- return;
- }
- }
-
- //判断当前元素所在的窗体是否与已切换的窗体列表中最后一个元素(当前窗体)的内容相同,相同则直接返回(无需操作)
- //获取最后一层窗体的名称,若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);
- }
- }
-
- /**
- * 该方法用于在xml文件查找不到对应的元素时,则再对传入的参数进行xpath和css的比较,
- * 以确认是否为直接传值,若不为xpath和css中的一种,则抛出UnrecognizableLocationModeException
- *
- * @param driver WebDriver对象
- * @param text 定位方式
- * @return 定位方式的类型
- */
- 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;
- } else {
- return null;
- }
- } catch (TimeoutException exception) {
- // 将错误信息写入到记录工具的备注中
- RecordTool.recordMark("元素查找超时或不存在,请检查“" + text + "”定位方式");
- throw new TimeoutException("元素查找超时或不存在,请检查“" + text + "”定位方式");
+
+ // 如果抛出元素名称查找不到的的异常,则对应匹配xpath和css两种定位方式
+ // 匹配xpath定位,判定方法,判断text的第一个字符是否是“/”
+ if (text.indexOf(judgeXpath) == 0) {
+ // 查找该定位方式在有限的时间内是否内被查到
+ return By.xpath(text);
+ } else {
+ return By.cssSelector(text);
}
}
+ /**
+ * 用于获取元素在xml文件中所有的父窗体,并以集合的形式返回,存储的顺序为父窗体在前,子窗体在后,若当前元素没有窗体,
+ * 则集合的长度为0
+ * @param name 元素在xml文件中的名称
+ * @return 元素在xml文件中所有的父窗体集合
+ */
+ private List getParentFrameName(String name) {
+ //存储获取到的父层窗体名称
+ List nameList = new ArrayList();
+
+ //获取元素所在窗体的名称
+ String iframeName = xml.getIframeName(name);
+ //循环,判断窗体是否存在(方法返回不为空),若存在,则再将父窗体进行存储
+ while(!iframeName.isEmpty()) {
+ //存储窗体
+ nameList.add(iframeName);
+ //再以当前窗体的名称再次获取该窗体的父窗体
+ iframeName = xml.getIframeName(iframeName);
+ }
+
+ //将nameList的内容倒序,保证父窗体在子窗体之前
+ Collections.reverse(nameList);
+
+ return nameList;
+ }
+
/**
* 用于将页面控件元素高亮显示
* @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;
+ }
}
}
diff --git a/src/test/java/pres/auxiliary/selenium/xml/io/TestReadXml.java b/src/test/java/pres/auxiliary/selenium/xml/io/TestReadXml.java
index 2a4eb96..dd128a2 100644
--- a/src/test/java/pres/auxiliary/selenium/xml/io/TestReadXml.java
+++ b/src/test/java/pres/auxiliary/selenium/xml/io/TestReadXml.java
@@ -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() {