修改元素存储机制,添加元素指定类型的定位方式

This commit is contained in:
彭宇琦 2020-04-25 22:33:08 +08:00
parent 6cb4ae5322
commit bb6797d4f7
14 changed files with 496 additions and 247 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.ElementLocationType;
import pres.auxiliary.selenium.xml.ByType;
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("项目选项", ElementLocationType.XPATH));
l = d.findElements(r.getBy("项目选项", ByType.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("导出数据表单", ElementLocationType.XPATH)).submit();
d.findElement(r.getBy("导出数据表单", ByType.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.ElementLocationType;
import pres.auxiliary.selenium.xml.ByType;
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 {
ElementLocationType mode = readXml(name);
ByType 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) {
ElementLocationType mode = readValue(driver, name);
ByType mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
@ -197,9 +197,9 @@ public abstract class AbstractEvent {
//若有返回定位方式则根据定位方式类型获取其元素
switch (mode) {
case XPATH:
return ElementLocationType.XPATH.getValue() + "=" + name;
return ByType.XPATH.getValue() + "=" + name;
case CSS:
return ElementLocationType.CSS.getValue() + "=" + name;
return ByType.CSS.getValue() + "=" + name;
default:
return "";
}
@ -428,7 +428,7 @@ public abstract class AbstractEvent {
// 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置
// 3.若仍找不到元素则抛出UnrecognizableLocationModeException
try {
ElementLocationType mode = readXml(name);
ByType 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) {
ElementLocationType mode = readValue(driver, name);
ByType mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
@ -473,9 +473,9 @@ public abstract class AbstractEvent {
* @param name 控件名称
* @return 查找到的定位方式名称
*/
protected ElementLocationType readXml(String name) {
protected ByType readXml(String name) {
// 循环逐个在页面上配对有效的标签对应的定位方式
for (ElementLocationType mode : xml.getElementMode(name)) {
for (ByType mode : xml.getElementMode(name)) {
// 在页面上查找元素定位方式
try {
//自动定位元素所在的窗体
@ -545,7 +545,7 @@ public abstract class AbstractEvent {
* @param text 定位方式
* @return 定位方式的类型
*/
protected ElementLocationType readValue(WebDriver driver, String text) {
protected ByType 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 ElementLocationType.XPATH;
return ByType.XPATH;
// 将等待时间设置回原来的
} else if (text.indexOf(judgeCss) == 0) {
// 匹配css判断方法判断text的前四个字符是否是html
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(text)));
return ElementLocationType.CSS;
return ByType.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.ElementLocationType;
import pres.auxiliary.selenium.xml.ByType;
/**
* <p><b>文件名</b>JsEvent.java</p>
@ -158,10 +158,10 @@ public class JsEvent extends AbstractEvent {
String[] element = getElementPosition(text).split("=");
// 判断定位方式若定位方式为css则按照querySelector()方式进行选择其他的方式均按照xpath来获取
if (ElementLocationType.XPATH.getValue().equalsIgnoreCase(element[0])) {
if (ByType.XPATH.getValue().equalsIgnoreCase(element[0])) {
script = "document.evaluate('" + element[1]
+ "', document, null, XPathResult.ANY_TYPE, null).iterateNext()";
} else if (ElementLocationType.CSS.getValue().equalsIgnoreCase(element[0])) {
} else if (ByType.CSS.getValue().equalsIgnoreCase(element[0])) {
script = "document.querySelector(" + element[1] + ")";
} else {
script = "document.evaluate('//*[@" + element[0] + "=\"" + element[1]

View File

@ -2,7 +2,7 @@ package pres.auxiliary.selenium.xml;
/**
* <p>
* <b>文件名</b>PosMode.java
* <b>文件名</b>ByType.java
* </p>
* <p>
* <b>用途</b>用于枚举出能被识别的元素定位方式
@ -19,7 +19,7 @@ package pres.auxiliary.selenium.xml;
* @since JDK 12
*
*/
public enum ElementLocationType {
public enum ByType {
/** 通过xpath方式进行定位 */
XPATH("xpath"),
/** 通过css方式进行定位 */
@ -33,14 +33,19 @@ public enum ElementLocationType {
/** 通过name方式进行定位 */
NAME("name"),
/** 通过tagName方式进行定位 */
TAGNAME("tagname");
TAGNAME("tagname"),
/**
* 通过jQuert的方式进行定位
*/
// JQ("jquert"),
;
/**
* 定义枚举值
*/
private String value;
private ElementLocationType(String value) {
private ByType(String value) {
this.value = value;
}

View File

@ -105,9 +105,9 @@ public class ReadXml {
* @param name 元素名称
* @return 当前元素有效的定位名称多个标签名称以空格隔开
*/
public List<ElementLocationType> getElementMode(String name) {
public List<ByType> getElementMode(String name) {
// 用于存储元素定位方式的标签名称
List<ElementLocationType> modes = new ArrayList<>();
List<ByType> modes = new ArrayList<>();
try {
@SuppressWarnings("unchecked")
@ -134,13 +134,13 @@ public class ReadXml {
* 根据元素名称在指定的xml文件中查找到相应的元素返回其元素的信息{@link By}类返回
*
* @param name 元素名称
* @param mode 定位方式枚举类对象参见{@link ElementLocationType}
* @param mode 定位方式枚举类对象参见{@link ByType}
* @return 元素对应的{@link By}类对象
*
* @throws UndefinedElementException 未找到相应的模板元素时抛出的异常
* @throws NoSuchSignValueException 模板中存在为定义值的标志时抛出的异常
*/
public By getBy(String name, ElementLocationType mode) {
public By getBy(String name, ByType mode) {
// 存储从xml文件中读取到的元素定位
String elementPos = getValue(name, mode);
@ -173,13 +173,13 @@ public class ReadXml {
* 用于根据元素名称及定位方式来返回其定位方式的值
*
* @param name 元素名称
* @param mode 定位方式枚举类对象参见{@link ElementLocationType}
* @param mode 定位方式枚举类对象参见{@link ByType}
* @return xml文件中的相应元素的定位值
*
* @throws UndefinedElementException 未找到相应的模板元素时抛出的异常
* @throws NoSuchSignValueException 模板中存在为定义值的标志时抛出的异常
*/
public String getValue(String name, ElementLocationType mode) {
public String getValue(String name, ByType mode) {
// 用于拼接读取XML中元素的xpath为了兼容iframe标签故此处使用*符号来查找元素
String xmlXpath = "//*[@name='" + name + "']/" + mode.getValue();
// 获取元素节点并将其转为Element对象以便于获取该元素的属性值
@ -241,7 +241,7 @@ public class ReadXml {
* @throws NoSuchSignValueException 模板中存在为定义值的标志时抛出的异常
*/
@SuppressWarnings("unchecked")
private String getTempletPath(Element element, String name, ElementLocationType mode) {
private String getTempletPath(Element element, String name, ByType mode) {
// 通过元素的temp_id定位到模板的id上
Element templetElement = (Element) dom.selectSingleNode(
"//templet/" + mode.getValue() + "[@id='" + element.attribute("temp_id").getValue() + "']");
@ -281,22 +281,22 @@ public class ReadXml {
* @param modeName 定位标签名称
* @return ElementLocationType枚举
*/
private static ElementLocationType getMode(String modeName) {
private static ByType getMode(String modeName) {
switch (modeName) {
case "xpath":
return ElementLocationType.XPATH;
return ByType.XPATH;
case "css":
return ElementLocationType.CSS;
return ByType.CSS;
case "classname":
return ElementLocationType.CLASSNAME;
return ByType.CLASSNAME;
case "id":
return ElementLocationType.ID;
return ByType.ID;
case "linktext":
return ElementLocationType.LINKTEXT;
return ByType.LINKTEXT;
case "name":
return ElementLocationType.NAME;
return ByType.NAME;
case "tagname":
return ElementLocationType.TAGNAME;
return ByType.TAGNAME;
default:
throw new IllegalArgumentException("Unexpected value: " + modeName);

View File

@ -21,7 +21,7 @@ import com.alibaba.fastjson.JSONObject;
* @since JDK 12
*
*/
public abstract class Brower {
public abstract class AbstractBrower {
/**
* 用于接收浏览器启动所需的文件路径
*/
@ -50,7 +50,7 @@ public abstract class Brower {
*
* @param driberFile 驱动文件对象
*/
public Brower(File driverFile) {
public AbstractBrower(File driverFile) {
this.driverFile = driverFile;
// 存储页面信息
@ -64,7 +64,7 @@ public abstract class Brower {
* @param url 待测站点
* @param pageName 待测站点名称用于切换页面
*/
public Brower(File driverFile, String url, String pageName) {
public AbstractBrower(File driverFile, String url, String pageName) {
this(driverFile);
nowPage = new Page(url, pageName);
}
@ -75,7 +75,7 @@ public abstract class Brower {
* @param driverFile 驱动文件对象
* @param page {@link Page}类对象
*/
public Brower(File driverFile, Page page) {
public AbstractBrower(File driverFile, Page page) {
this(driverFile);
nowPage = page;
}
@ -322,6 +322,8 @@ public abstract class Brower {
}
}
}
/**
* 用于切换到当前页面

View File

@ -40,7 +40,7 @@ import com.alibaba.fastjson.JSONArray;
* @since JDK 1.8
*
*/
public class ChromeBrower extends Brower {
public class ChromeBrower extends AbstractBrower {
/**
* 用于存储需要对浏览器进行配置的参数
*/

View File

@ -137,7 +137,7 @@ public class Page {
/**
* 用于通过浏览器加载页面并根据页面断言返回页面是否加载成功若未设置断言则无论
* 页面是否成功加载均返回true
* @param driver WebDriver对象通过可通过{@link Brower}类及其子类来生成
* @param driver WebDriver对象通过可通过{@link AbstractBrower}类及其子类来生成
* @return 根据页面断言返回页面是否加载成功
*/
public boolean loadPage(WebDriver driver) {

View File

@ -2,14 +2,11 @@ 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.junit.rules.ExpectedException;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.TimeoutException;
@ -19,23 +16,31 @@ import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import pres.auxiliary.selenium.event.NoSuchWindownException;
import pres.auxiliary.selenium.event.UnrecognizableLocationModeException;
import pres.auxiliary.selenium.xml.ElementLocationType;
import pres.auxiliary.selenium.xml.ByType;
import pres.auxiliary.selenium.xml.ReadXml;
public class Element {
/**
* <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 AbstractElement {
/**
* 用于存储浏览器的WebDriver对象设为静态保证所有的子类只使用一个WebDriver对象以避免造成WebDriver不正确导致的Bug
*/
private WebDriver driver;
WebDriver driver;
/**
* 用于指向存储控件定位方式的xml文件
*/
private ReadXml xml = new ReadXml();
/**
* 全局控件等待时间
*/
private long waitTime = 3;
ReadXml xml = new ReadXml();
/**
* 存储单个控件的等待时间
*/
@ -49,36 +54,50 @@ public class Element {
*/
private ArrayList<String> iframeNameList = new ArrayList<>();
/**
* 用于存储元素通用的等待时间
*/
private long waitTime = 5;
/**
* 控制是否自动切换窗体由于通过Event类调用时会构造另一个事件类但每个类都应共享一个开关故需要加上static
*/
boolean switchIframe = true;
boolean isAutoSwitchIframe = true;
/**
* 构造对象并存储浏览器的WebDriver对象
*
* @param driver 浏览器的WebDriver对象
*/
public Element(WebDriver driver) {
public AbstractElement(WebDriver driver) {
this.driver = driver;
browserHandles = this.driver.getWindowHandle();
}
/**
* 用于设置等待时间
* 用于对单个控件设置等待时间
*
* @param name 控件名称
* @param waitTime 等待时间
*/
public void setContorlWaitTime(String name, long waitTime) {
controlWaitTime.put(name, waitTime);
}
/**
* 用于设置控件的通用等待时间
* @param waitTime 控件通用的等待时间
*/
public void setWaitTime(long waitTime) {
// wait = new WebDriverWait(driver, waitTime, 200);
this.waitTime = waitTime;
}
/**
* 设置是否自动切换窗体
* @param switchIframe 是否自动切换窗体
*/
public void setSwitchIframe(boolean switchIframe) {
this.switchIframe = switchIframe;
public void setAutoSwitchIframe(boolean isAutoSwitchIframe) {
this.isAutoSwitchIframe = isAutoSwitchIframe;
}
/**
@ -103,17 +122,6 @@ public class Element {
}
}
/**
* 用于对单个控件设置等待时间
*
* @param name 控件名称
* @param waitTime 等待时间
*/
public void setContorlWaitTime(String name, long waitTime) {
controlWaitTime.put(name, waitTime);
}
/**
* 该方法用于将窗体切回顶层当本身是在最顶层时则该方法将使用无效
*/
@ -143,19 +151,64 @@ public class Element {
}
/**
* <p>
* 通过传入在xml文件中的控件名称到类中指向的xml文件中查找控件
* 名称对应的定位方式或直接传入xpath与css定位方式
* 根据定位方式对相应的窗体进行定位当传入的窗体为当前窗体的前层父层窗体时
* 通过该方法将调用切换父层的方法将窗体切换到父层上例如<br>
* 当前存在f1, f2, f3, f4四层窗体则调用方法<br>
* switchFrame("f2")<br>
* 此时窗体将回到f2层无需再从顶层开始向下切换<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 names 窗体的名称或xpath与css定位方式
* @param name 窗体的名称或xpath与css定位方式
*/
public void switchFrame(String...names) {
switchFrame(Arrays.asList(names));
public void switchFrame(String name) {
switchFrame(name, null);
}
/**
* 通过传入在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) {
List<ElementInformation> nameList = new ArrayList<ElementInformation>();
//判断传入的元素名称是否存在于xml文件中若存在则将该元素的父层名称存储至nameList
if (xml != null && xml.isElement(name) && isAutoSwitchIframe) {
nameList.addAll(getParentFrameName(name));
}
//将相应的元素存入nameList中
nameList.add(new ElementInformation(name, byType, controlWaitTime.containsKey(name) ? controlWaitTime.get(name) : waitTime));
//调用
switchFrame(nameList);
}
/**
@ -163,21 +216,26 @@ public class Element {
* 名称对应的定位方式或直接传入xpath与css定位方式
* 根据定位方式对相应的窗体进行定位当传入的窗体为当前窗体的前层父层窗体时
* 通过该方法将调用切换父层的方法将窗体切换到父层上例如<br>
* 当前存在f1, f2, f3, f4四层窗体则调用方法<br>
* List<String> nameList = new ArrayList<String>();<br>
* nameList.add("f2");<br>
* switchFrame(nameList)<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 nameList 存储窗体的名称或xpath与css定位方式的List集合
* @param elementInformationList 存储窗体的名称或xpath与css定位方式的List集合
*/
public void switchFrame(List<String> nameList) {
nameList.forEach(name -> {
private void switchFrame(List<ElementInformation> elementInformationList) {
elementInformationList.forEach(elementInformation -> {
//判断name指向的窗体是否在iframeNameList中若存在则向上切换父层直到切换到name指向的窗体若不存在则直接切换并添加窗体名称
if (iframeNameList.contains(name)) {
if (iframeNameList.contains(elementInformation.name)) {
//获取name窗体在iframeNameList中的位置
int index = iframeNameList.indexOf(name);
int index = iframeNameList.indexOf(elementInformation.name);
//获取需要向上切换窗体的次数公式为推断出来
int count = iframeNameList.size() - index - 1;
for (int i = 0; i < count; i++) {
@ -185,8 +243,8 @@ public class Element {
}
} else {
//切换窗体
driver.switchTo().frame(recognitionElements(name).get(0));
iframeNameList.add(name);
driver.switchTo().frame(recognitionElements(elementInformation).get(0));
iframeNameList.add(elementInformation.name);
}
});
}
@ -250,7 +308,7 @@ public class Element {
throw new NoSuchWindownException("未找到存在元素" + controlName + "所在的窗体");
}
/**
* 定位到弹框上并且点击确定按钮并返回弹框上的文本
*
@ -316,12 +374,12 @@ public class Element {
* @throws TimeoutException 元素在指定时间内未查找到时抛出的异常
* @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
*/
List<WebElement> recognitionElements(String name) {
List<WebElement> recognitionElements(ElementInformation element) {
//判断元素是否存在于xml文件中根据返回的状态来判断调用的方法
if (xml.isElement(name)) {
return findXmlElement(name);
if (xml.isElement(element.name)) {
return findXmlElement(element);
} else {
return findCommonElement(name, judgeElementLocationMode(name));
return findCommonElement(element);
}
}
@ -330,13 +388,18 @@ public class Element {
* @param name 元素内容
* @return
*/
private List<WebElement> findCommonElement(String name, By by) {
if (isFindWebElement(controlWaitTime.containsKey(name) ? controlWaitTime.get(name) : waitTime, by)) {
return driver.findElements(by);
private List<WebElement> findCommonElement(ElementInformation element) {
//若未对元素的定位方式进行存储则调用方法对元素的定位方式进行识别
if (element.byType == null) {
element.byType = judgeElementLocationMode(element.value);
}
if (isExistElement(element)) {
return driver.findElements(getBy(element.byType, element.value));
}
// 若循环结束后仍未能找到该元素则返回一个空串
throw new TimeoutException("元素“" + name + "”无法查找,请核对定位方式:" + by.toString());
throw new TimeoutException("元素“" + element.name + "”无法查找,请核对定位方式:" + element.byType.getValue() + "=" + element.value);
}
/**
@ -345,35 +408,84 @@ public class Element {
* @return 页面中查找到的元素
* @throws TimeoutException 当元素不能找到时抛出的异常
*/
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));
private List<WebElement> findXmlElement(ElementInformation element) {
//若元素的定位方式未被存储则调用方法对元素的定位方式进行获取
if (element.byType == null || element.value.isEmpty()) {
// 循环逐个在页面上配对有效的标签对应的定位方式
for (ByType mode : xml.getElementMode(element.name)) {
//存储当前查询到的元素信息
element.byType = mode;
element.value = xml.getValue(element.name, mode);
//若元素能被找到则结束循环
if (isExistElement(element)) {
break;
}
}
// 若循环结束后仍未能找到该元素则抛出异常
throw new TimeoutException("元素“" + element.name + "”无法查找请核对xml文件" + xml.getXmlFile().getName() + "\n文件路径" + xml.getXmlFile().getAbsolutePath());
}
// 若循环结束后仍未能找到该元素则返回一个空串
throw new TimeoutException("元素“" + name + "”无法查找请核对xml文件" + xml.getXmlFile().getName() + "\n文件路径" + xml.getXmlFile().getAbsolutePath());
return driver.findElements(getBy(element.byType, element.value));
}
/**
* 用于判断传入参数的定位方式只识别xpath与css两种定位方式需要注意的是该方法主要用于
* 识别xptah若元素的定位方式不是xpath定位则根据css方式来返回
* 用于判断传入参数的定位方式只识别xpath路径绝对的css路径两种定位方式
*
* @param text 元素定位方式
* @return 相应的By对象
* @return {@link ByType}枚举
*/
private By judgeElementLocationMode(String text) {
// 定义判断参数为xpath的字符
String judgeXpath = "/";
// 如果抛出元素名称查找不到的的异常则对应匹配xpath和css两种定位方式
private ByType judgeElementLocationMode(String text) {
// 如果抛出元素名称查找不到的的异常则对应匹配xpath和绝对css路径两种定位方式
// 匹配xpath定位判定方法判断text的第一个字符是否是/
if (text.indexOf(judgeXpath) == 0) {
if (text.indexOf("/") == 0) {
// 查找该定位方式在有限的时间内是否内被查到
return By.xpath(text);
return ByType.XPATH;
} else if (text.indexOf("html") == 0) {
return ByType.CSS;
} else {
return By.cssSelector(text);
throw new UnrecognizableLocationModeException("元素定位方式类型无法识别:" + text);
}
}
/**
* 根据页面的等待时间和元素定位方式在页面上查找相应的元素返回是否能查到元素
* @param time 控件等待时间
* @param by 元素定位方式
* @return 是否能查找到的元素
*/
boolean isExistElement(ElementInformation element) {
// new WebDriverWait(driver, time, 200).until(ExpectedConditions.elementToBeClickable(by));
By by = getBy(element.byType, element.value);
//当查找到元素时则返回true若查不到元素则会抛出异常故返回false
try {
new WebDriverWait(driver, element.waitTime, 200).until(ExpectedConditions.presenceOfElementLocated(by));
return true;
} catch (Exception e) {
return false;
}
}
By getBy(ByType byType, String value) {
//根据元素的定位方式对定位内容进行选择返回相应的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);
}
}
@ -383,16 +495,16 @@ public class Element {
* @param name 元素在xml文件中的名称
* @return 元素在xml文件中所有的父窗体集合
*/
private List<String> getParentFrameName(String name) {
List<ElementInformation> getParentFrameName(String name) {
//存储获取到的父层窗体名称
List<String> nameList = new ArrayList<String>();
List<ElementInformation> nameList = new ArrayList<ElementInformation>();
//获取元素所在窗体的名称
String iframeName = xml.getIframeName(name);
//循环判断窗体是否存在方法返回不为空若存在则再将父窗体进行存储
while(!iframeName.isEmpty()) {
//存储窗体
nameList.add(iframeName);
nameList.add(new ElementInformation(iframeName, controlWaitTime.containsKey(iframeName) ? controlWaitTime.get(iframeName) : waitTime));
//再以当前窗体的名称再次获取该窗体的父窗体
iframeName = xml.getIframeName(iframeName);
}
@ -420,19 +532,94 @@ public class Element {
}
/**
* 根据页面的等待时间和元素定位方式在页面上查找相应的元素返回是否能查到元素
* @param time 控件等待时间
* @param by 元素定位方式
* @return 是否能查找到的元素
* <p><b>文件名</b>AbstractElement.java</p>
* <p><b>用途</b>用于</p>
* <p><b>编码时间</b>2020年4月25日 下午5:43:59</p>
* <p><b>修改时间</b>2020年4月25日 下午5:43:59</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*/
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;
class ElementInformation {
/**
* 用于存储元素的名称
*/
private String name;
/**
* 用于存储元素的定位内容
*/
private String value = "";
/**
* 用于存储元素的定位方式
*/
private ByType byType;
/**
* 用于存储在页面上查找的等待时间
*/
private long waitTime;
/**
* 用于初始化元素的信息
* @param name 元素在xml文件的名称或xpath路径或绝对的css路径
* @param waitTime 元素控件的等待时间
*/
public ElementInformation(String name, long waitTime) {
this.name = name;
this.waitTime = waitTime;
//若未指定xml文件或xml文件中不存在name对应的元素则将name的值赋给value表示
if (xml == null || !xml.isElement(name)) {
value = name;
}
}
/**
* 用于初始化元素的信息
* @param name 元素在xml文件的名称或xpath路径或绝对的css路径
* @param waitTime 元素控件的等待时间
*/
public ElementInformation(String name, ByType byType, long waitTime) {
this.name = name;
this.byType = byType;
this.waitTime = waitTime;
//若未指定xml文件则将name的值赋给value
if (xml == null) {
value = name;
}
//xml文件中不存在name对应的元素则将name的值赋给value反之则在xml文件中查找对应的定位内容
if (!xml.isElement(name)) {
value = name;
} else {
value = xml.getValue(name, byType);
}
}
/**
* 用于返回元素的名称或定位方式
* @return 元素的名称
*/
public String getName() {
return name;
}
/**
* 用于返回元素的等待时间
* @return
*/
public long getWaitTime() {
return waitTime;
}
/**
* 用于返回定位元素的内容当未对元素进行查找时返回空串
* @return 定位元素的内容
*/
public String getValue() {
return value;
}
}
}

View File

@ -3,7 +3,7 @@ package pres.auxiliary.work.selenium.element;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class CommonElement extends Element {
public class CommonElement extends AbstractElement {
/**
* 构造对象并存储浏览器的WebDriver对象
*
@ -20,18 +20,13 @@ public class CommonElement extends Element {
* @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 若是则调用判断元素是否存在的方法对元素进行存在判断
//判断传入的元素是否在xml文件中若存在再判断是否自动切换窗体若需要则获取元素的所有父窗体并进行切换
if (xml.isElement(name)) {
//判断元素是否需要自动切换窗体
if (isAutoSwitchIframe) {
switchFrame(getParentFrameName(name));
}
}
return null;
}

View File

@ -0,0 +1,38 @@
package pres.auxiliary.work.selenium.element;
/**
* <p><b>文件名</b>UnrecognizableLocationModeException.java</p>
* <p><b>用途</b>在元素定位方式无法被识别的情况下抛出的异常</p>
* <p><b>编码时间</b>2019年9月24日下午3:19:43</p>
* <p><b>修改时间</b>2019年9月24日下午3:19:43</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*
*/
public class UnrecognizableLocationModeException extends RuntimeException {
private static final long serialVersionUID = 1L;
public UnrecognizableLocationModeException() {
super();
}
public UnrecognizableLocationModeException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public UnrecognizableLocationModeException(String message, Throwable cause) {
super(message, cause);
}
public UnrecognizableLocationModeException(String message) {
super(message);
}
public UnrecognizableLocationModeException(Throwable cause) {
super(cause);
}
}

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

View File

@ -1,78 +0,0 @@
package test.javase;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
public class Test111 {
public static void main(String[] args) throws Exception {
File f1 = new File("D:\\1.txt");
File f2 = new File("D:\\2.txt");
// System.out.println(f1.getName());
BufferedReader br1 = new BufferedReader(new FileReader(f1));
BufferedReader br2 = new BufferedReader(new FileReader(f2));
// BufferedReader br1 = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\1.txt"), "UTF-8"));
// BufferedReader br2 = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\2.txt"), "UTF-8"));
String text1 = "";
String text2 = "";
String s = "";
while((s = br1.readLine()) != null) {
text1 += s;
text1 += "\n";
}
s = "";
while((s = br2.readLine()) != null) {
text2 += s;
text2 += "\n";
}
// System.out.println(text1);
// System.out.println("-----------------");
// System.out.println(text2);
String[] texts1 = text1.split("\\n");
String[] texts2 = text2.split("\\n");
for (String t1 : texts1) {
for (String t2 : texts2) {
// String tt1 = new String(t1.getBytes("ISO-8859-1"),"UTF-8");
// String tt2 = new String(t2.getBytes("ISO-8859-1"), "UTF-8");
System.out.println(t1.length());
System.out.println(t2.length());
System.out.println("字符串“" + t1 + "”与字符串“" + t2 + "”的比较结果为:" + t1.equals(t2));
}
}
/*
System.out.println("t1:" + texts1.length);
System.out.println("t2:" + texts2.length);
for (String t1 : texts1) {
boolean b = true;
for (String t2 : texts2) {
if (t2.equals(t1)) {
b = false;
break;
}
b = true;
}
if(b) {
System.out.println(t1);
}
}*/
br1.close();
br2.close();
}
}

View File

@ -0,0 +1,100 @@
package test.javase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.Test;
public class TestList {
@Test
public void test() {
//TODO
SwitchFrame sf = new SwitchFrame();
}
class SwitchFrame {
private ArrayList<String> parentIframeList = new ArrayList<String>();
ArrayList<String> iframeNameList = new ArrayList<String>();
public SwitchFrame() {
parentIframeList.add("f1");
parentIframeList.add("f2");
parentIframeList.add("f3");
}
/**
* 该方法用于将窗体切回顶层当本身是在最顶层时则该方法将使用无效
*/
public void switchRootFrame() {
//清空iframeNameList中的内容
iframeNameList.clear();
}
/**
* 该方法用于将窗体切换到上一层父层若当前层只有一层则调用方法后切回顶层
* 若当前层为最顶层时则该方法将使用无效
*/
public void switchParentFrame() {
//若iframeNameList大于1层则向上切换窗体
if (iframeNameList.size() > 1) {
iframeNameList.remove(iframeNameList.size() - 1);
} else if (iframeNameList.size() == 1) {
//若iframeNameList等于1层则调用切换至顶层的方法
switchRootFrame();
} else {
//若iframeNameList小于1层则不做操作
return;
}
}
/**
* 通过传入在xml文件中的控件名称到类中指向的xml文件中查找控件
* 名称对应的定位方式或直接传入xpath与css定位方式
* 根据定位方式对相应的窗体进行定位当传入的窗体为当前窗体的前层父层窗体时
* 通过该方法将调用切换父层的方法将窗体切换到父层上例如<br>
* 当前存在f1, f2, f3, f4四层窗体则调用方法<br>
* switchFrame("f2")<br>
* 此时窗体将回到f2层无需再从顶层开始向下切换<br>
* 注意窗体的切换按照从前向后的顺序进行切换切换顺序不能相反
*
* @param names 窗体的名称或xpath与css定位方式
*/
public void switchFrame(String...names) {
switchFrame(Arrays.asList(names));
}
/**
* 通过传入在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 {
//切换窗体
iframeNameList.add(name);
}
});
}
}
}