添加部分功能

This commit is contained in:
彭宇琦 2020-05-07 21:05:37 +08:00
parent cd6a5cfb58
commit 67bded1213
6 changed files with 350 additions and 215 deletions

View File

@ -13,7 +13,6 @@ import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.TimeoutException; import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
import pres.auxiliary.selenium.event.NoSuchWindownException; import pres.auxiliary.selenium.event.NoSuchWindownException;
import pres.auxiliary.selenium.xml.ByType; import pres.auxiliary.selenium.xml.ByType;
@ -228,14 +227,8 @@ public abstract class AbstractElement {
//调用切换窗体的方法 //调用切换窗体的方法
switchFrame(nameList); switchFrame(nameList);
//将相应的元素存入nameList中 driver.switchTo().frame(recognitionElement(name, byType).get(0));
if (byType != null) {
driver.switchTo().frame(recognitionElements(new ElementInformation(name, byType, getWaitTime(name))).get(0));
} else {
driver.switchTo().frame(recognitionElements(new ElementInformation(name, getWaitTime(name))).get(0));
}
//切换窗体 //切换窗体
iframeNameList.add(name); iframeNameList.add(name);
} }
@ -271,7 +264,7 @@ public abstract class AbstractElement {
} }
} else { } else {
//切换窗体 //切换窗体
driver.switchTo().frame(recognitionElements(new ElementInformation(frameName, getWaitTime(frameName))).get(0)); driver.switchTo().frame(recognitionElement(frameName, null).get(0));
iframeNameList.add(frameName); iframeNameList.add(frameName);
} }
}); });
@ -316,7 +309,7 @@ public abstract class AbstractElement {
driver.switchTo().window(newWinHandle); driver.switchTo().window(newWinHandle);
try { try {
//构造信息因为在构造过程中会判断元素是否存在 //构造信息因为在构造过程中会判断元素是否存在
new ElementInformation(controlName, getWaitTime(controlName)); recognitionElement(controlName, null);
return; return;
}catch (Exception e) { }catch (Exception e) {
continue; continue;
@ -329,7 +322,7 @@ public abstract class AbstractElement {
//切换窗口并查找元素是否在窗口上若存在则结束切换 //切换窗口并查找元素是否在窗口上若存在则结束切换
brower.switchWindow(page); brower.switchWindow(page);
try { try {
new ElementInformation(controlName, getWaitTime(controlName)); recognitionElement(controlName, null);
return; return;
}catch (Exception e) { }catch (Exception e) {
continue; continue;
@ -406,9 +399,41 @@ public abstract class AbstractElement {
* @throws TimeoutException 元素在指定时间内未查找到时抛出的异常 * @throws TimeoutException 元素在指定时间内未查找到时抛出的异常
* @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常 * @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
*/ */
/*
List<WebElement> recognitionElements(ElementInformation element) { List<WebElement> recognitionElements(ElementInformation element) {
return driver.findElements(element.getBy()); return driver.findElements(element.getBy());
} }
*/
List<WebElement> recognitionElement(String name, ByType byType) {
By by;
//若未指定xml文件或者在xml文件中无法查到相应的元素时则将name的值赋给value且根据value判断相应定位方式
if (isXmlElement(name)) {
by = recognitionCommonElement(name, byType);
} else {
//若指定了xml文件且传入的元素名称存在与xml文件中则判断元素相应的定位方式及定位内容
by = recognitionXmlElement(name, byType);
}
return driver.findElements(by);
}
private By recognitionCommonElement(String name, ByType byType) {
//判断传入的ByType对象是否为null
if (byType == null) {
return judgeCommonElementBy(name);
} else {
return getBy(name, byType);
}
}
private By recognitionXmlElement(String name, ByType byType) {
//判断传入的ByType对象是否为null
if (byType == null) {
return judgeXmlElementBy(name);
} else {
return xml.getBy(name, byType);
}
}
/** /**
* 用于返回控件的等待时间若设置单个控件的等待时间使用{@link #setContorlWaitTime(String, long)}方法设置 * 用于返回控件的等待时间若设置单个控件的等待时间使用{@link #setContorlWaitTime(String, long)}方法设置
@ -466,203 +491,103 @@ public abstract class AbstractElement {
} }
/** /**
* <p><b>文件名</b>AbstractElement.java</p> * 用于根据传入的参数识别非xml文件内的元素定位方式
* <p><b>用途</b>用于</p> * 该方法能快速识别xpath定位方式以及绝对css定位方式若不是以上两种定位方式
* <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
*/ */
class ElementInformation { By judgeCommonElementBy(String value) {
/** // 如果抛出元素名称查找不到的的异常则对应匹配xpath和绝对css路径两种定位方式
* 用于存储元素的名称 // 匹配xpath定位判定方法判断text的第一个字符是否是/
*/ //由于是识别普通元素非xml元素其value就是元素的名称name 故获取等待时间时可直接将value传入
private String name; if (value.indexOf("/") == 0) {
//在页面中查找元素若元素能找到则结束查找
/** By by = getBy(value, ByType.XPATH);
* 用于存储元素的定位内容 if (isExistElement(by, getWaitTime(value))) {
*/ return by;
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的值赋给value且根据value判断相应定位方式
if (xml == null || !xml.isElement(name)) {
value = name;
setCommonElementLocationMode();
} else {
//若指定了xml文件且传入的元素名称存在与xml文件中则判断元素相应的定位方式及定位内容
setXmlElementLocation();
} }
} } else if (value.indexOf("html") == 0) {
//在页面中查找元素若元素能找到则结束查找
/** By by = getBy(value, ByType.CSS);
* 用于初始化元素的信息 if (isExistElement(by, getWaitTime(value))) {
* @param name 元素在xml文件的名称或xpath路径或绝对的css路径 return by;
* @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;
} else {
//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;
}
/** //若元素无法识别则将所有的定位类型排除xpath类型与之进行对比直到在页面上找到元素为止
* 用于返回定位元素的内容当未对元素进行查找时返回空串 for(ByType type : ByType.values()) {
* @return 定位元素的内容 if (type == ByType.XPATH) {
*/ continue;
public String getValue() {
return value;
}
/**
* 用于根据传入的参数识别非xml文件内的元素定位方式
* 该方法能快速识别xpath定位方式以及绝对css定位方式若不是以上两种定位方式
* 则会遍历所有的定位方式此时会降低运行速度建议在不是以上两种定位方式的
* 情况下直接指定元素的定位方式以提高效率
*/
void setCommonElementLocationMode() {
// 如果抛出元素名称查找不到的的异常则对应匹配xpath和绝对css路径两种定位方式
// 匹配xpath定位判定方法判断text的第一个字符是否是/
if (value.indexOf("/") == 0) {
// 查找该定位方式在有限的时间内是否内被查到
byType = ByType.XPATH;
//在页面中查找元素若元素能找到则结束查找
if (isExistElement()) {
return;
}
} else if (value.indexOf("html") == 0) {
byType = ByType.CSS;
//在页面中查找元素若元素能找到则结束查找
if (isExistElement()) {
return;
}
} else {
//若元素无法识别则将所有的定位类型排除xpath类型与之进行对比直到在页面上找到元素为止
for(ByType type : ByType.values()) {
if (type == ByType.XPATH) {
continue;
}
byType = type;
//在页面中查找元素若元素能找到则结束查找
if (isExistElement()) {
return;
}
}
} }
//若所有的定位方式均无法查找到元素则抛出异常 By by = getBy(value, type);
throw new UnrecognizableLocationModeException("元素定位方式类型无法识别:" + value);
} //在页面中查找元素若元素能找到则结束查找
if (isExistElement(by, getWaitTime(value))) {
/** return by;
* 用于设置xml文件内的元素的定位方式及定位内容
*/
void setXmlElementLocation() {
// 循环逐个在页面上配对有效的标签对应的定位方式
for (ByType mode : xml.getElementMode(name)) {
//存储当前查询到的元素信息
byType = mode;
value = xml.getValue(name, mode);
//若元素能被找到则结束循环
if (isExistElement()) {
break;
}
// 若循环结束后仍未能找到该元素则抛出异常
throw new TimeoutException("元素“" + name + "”无法查找请核对xml文件" + xml.getXmlFile().getName() + "\n文件路径" + xml.getXmlFile().getAbsolutePath());
} }
} }
/** //若所有的定位方式均无法查找到元素则抛出异常
* 根据元素的参数返回元素的By对象 throw new TimeoutException("普通元素定位方式类型无法识别:" + value);
* @return 元素的By对象 }
*/
By getBy() { /**
//根据元素的定位方式对定位内容进行选择返回相应的By对象 * 用于设置xml文件内的元素的定位方式及定位内容
switch (byType) { */
case XPATH: By judgeXmlElementBy(String name) {
return By.xpath(value); By by;
case CLASSNAME: // 循环逐个在页面上配对有效的标签对应的定位方式
return By.className(value); for (ByType mode : xml.getElementMode(name)) {
case CSS: by = getBy(xml.getValue(name, mode), mode);
return By.cssSelector(value);
case ID: //若元素能被找到则返回相应的By对象若未找到则再次循环
return By.id(value); if (isExistElement(by, getWaitTime(name))) {
case LINKTEXT: return by;
return By.linkText(value); } else {
case NAME: continue;
return By.name(value);
case TAGNAME:
return By.tagName(value);
default:
throw new UnrecognizableLocationModeException("无法识别的定位类型:" + byType);
} }
} }
/** // 若循环结束后仍未能找到该元素则抛出异常
* 根据页面的等待时间和元素定位方式在页面上查找相应的元素返回是否能查到元素 throw new TimeoutException("xml文件内元素“" + name + "”无法查找请核对xml文件" + xml.getXmlFile().getName() + "\n文件路径" + xml.getXmlFile().getAbsolutePath());
* @param time 控件等待时间 }
* @param by 元素定位方式
* @return 是否能查找到的元素 /**
*/ * 根据元素的参数返回元素的By对象
boolean isExistElement() { * @return 元素的By对象
// new WebDriverWait(driver, time, 200).until(ExpectedConditions.elementToBeClickable(by)); */
// new WebDriverWait(driver, time, 200).until(ExpectedConditions.titleContains("")); By getBy(String value, ByType byType) {
//当查找到元素时则返回true若查不到元素则会抛出异常故返回false //根据元素的定位方式对定位内容进行选择返回相应的By对象
return new WebDriverWait(driver, waitTime, 200). switch (byType) {
until((driver) -> { case XPATH:
WebElement element = driver.findElement(getBy()); return By.xpath(value);
return element != null; 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);
boolean isXmlElement(String name) {
return (xml == null || !xml.isElement(name));
}
} }

View File

@ -1,7 +1,9 @@
package pres.auxiliary.work.selenium.element; package pres.auxiliary.work.selenium.element;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
import pres.auxiliary.selenium.xml.ByType; import pres.auxiliary.selenium.xml.ByType;
import pres.auxiliary.work.selenium.brower.AbstractBrower; import pres.auxiliary.work.selenium.brower.AbstractBrower;
@ -47,12 +49,7 @@ public class CommonElement extends AbstractElement {
* @return WebElement对象 * @return WebElement对象
*/ */
public WebElement getWebElement(String name) { public WebElement getWebElement(String name) {
//判断传入的元素是否在xml文件中若存在再判断是否自动切换窗体若需要则获取元素的所有父窗体并进行切换 return getWebElement(name, null);
if (xml != null && xml.isElement(name) && isAutoSwitchIframe) {
switchFrame(getParentFrameName(name));
}
return recognitionElements(new ElementInformation(name, getWaitTime(name))).get(0);
} }
/** /**
@ -67,6 +64,16 @@ public class CommonElement extends AbstractElement {
switchFrame(getParentFrameName(name)); switchFrame(getParentFrameName(name));
} }
return recognitionElements(new ElementInformation(name, byType, getWaitTime(name))).get(0); return recognitionElement(name, byType).get(0);
}
@Override
boolean isExistElement(By by, long waitTime) {
//当查找到元素时则返回true若查不到元素则会抛出异常故返回false
return new WebDriverWait(driver, waitTime, 200).
until((driver) -> {
WebElement element = driver.findElement(by);
return element != null;
});
} }
} }

View File

@ -4,11 +4,13 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.WebDriverWait;
import pres.auxiliary.selenium.xml.ByType;
import pres.auxiliary.work.selenium.brower.AbstractBrower; import pres.auxiliary.work.selenium.brower.AbstractBrower;
/** /**
@ -31,11 +33,38 @@ public class DataListElement extends AbstractElement {
*/ */
private HashMap<String, List<WebElement>> elementMap = new HashMap<>(16); private HashMap<String, List<WebElement>> elementMap = new HashMap<>(16);
/**
* 用于存储元素列累计的个数
*/
private HashMap<String, Integer> elementSizeMap = new HashMap<String, Integer>(16);
/**
* 用于存储是否开始累加列表元素的个数
*/
private boolean isStartAddSize = false;
/** /**
* 用于判断列表的第一行元素是否为标题元素 * 用于判断列表的第一行元素是否为标题元素
*/ */
private boolean isFristRowTitle = false; private boolean isFristRowTitle = false;
/**
* 存储获取到的元素列表中最多元素列的元素个数
*/
private int maxColumnSize = -1;
/**
* 存储获取到的元素列表中最多元素列的名称
*/
private String maxColumnName = "";
/**
* 存储获取到的元素列表中最少元素列的元素个数
*/
private int minColumnSize = Integer.MAX_VALUE;
/**
* 存储获取到的元素列表中最少元素列的名称
*/
private String minColumnName = "";
/** /**
* 通过浏览器对象{@link AbstractBrower}进行构造 * 通过浏览器对象{@link AbstractBrower}进行构造
* @param brower {@link AbstractBrower}对象 * @param brower {@link AbstractBrower}对象
@ -62,19 +91,170 @@ public class DataListElement extends AbstractElement {
} }
/** /**
* 用于根据xml文件中元素的名称返回对应的获取到的一组WebElement对象该方法亦可传入元素 * 用于设置是否开始计算元素个数
* 定位内容通过遍历所有的定位方式在页面上查找元素来获取元素的WebElement对象 * @param isStartAddSize 是否开始计算元素个数
* 建议传入的定位内容为xpath路径或绝对的css路径若非这两路径则在识别元素时会很慢降低
* 程序运行速度
*
* @param names 一组控件的名称或xpath与css定位方式
*/ */
public void add(String name) { public void setStartAddSize(boolean isStartAddSize) {
//判断当前列名是否存在不存在则先存储其类名 this.isStartAddSize = isStartAddSize;
if (!elementMap.containsKey(name)) { }
elementMap.put(name, new ArrayList<WebElement>());
/**
* 返回元素最多列的元素个数
* @return 元素最多列的元素个数
*/
public int getMaxColumnSize() {
return maxColumnSize;
}
/**
* 返回元素最多列的列名称
* @return 元素最多列的列名称
*/
public String getMaxColumnName() {
return maxColumnName;
}
/**
* 返回元素最少列的元素个数
* @return 元素最少列的元素个数
*/
public int getMinColumnSize() {
return minColumnSize;
}
/**
* 返回元素最少列的列名称
* @return 元素最少列的列名称
*/
public String getMinColumnName() {
return minColumnName;
}
/**
* 返回列表名称对应的元素个数若该列未被获取则返回-1
* @param name 被获取的列名称
* @return 列名对应列的元素个数
*/
public int getColumnSize(String name) {
if (elementMap.containsKey(name)) {
return elementMap.get(name).size();
} else {
return -1;
}
}
/**
* 用于根据传入的元素在xml文件中的名称或者元素的定位内容添加元素列由于该方法不指定元素的定位
* 方式若传入的参数不是xml元素且非xpath路径或绝对css路径时其识别效率较慢建议在该情况下
* 调用{@link #add(String, ByType)}方法指定元素定位方法
* @param name 元素在xml文件或者元素的定位内容
* @param isAddSize 是否对元素个数进行统计
* @see #add(String, ByType)
* @throws TimeoutException 元素在指定时间内无法找到时抛出的异常
*/
public void add(String name, boolean isAddSize) {
add(name, null, isAddSize);
}
/**
* 用于根据传入的元素在xml文件中的名称或者元素的定位内容以及元素的定位方式添加元素列
* @param name 元素在xml文件或者元素的定位内容
* @param byType 元素定位方式枚举对象{@link ByType}枚举
* @param isAddSize 是否对元素个数进行统计
* @see #add(String)
* @throws TimeoutException 元素在指定时间内无法找到时抛出的异常
*/
public void add(String name, ByType byType, boolean isAddSize) {
List<WebElement> elementList = new ArrayList<WebElement>();
//获取元素
elementList = recognitionElement(name, byType);
//添加元素
elementMap.put(name, elementList);
//判断当前获取到的元素是否大于当前存储的元素的最大值或小于当前存储的最小值若是则将最大值或最小值进行替换
int elementSize = elementList.size();
if (elementSize > maxColumnSize) {
maxColumnSize = elementSize;
maxColumnName = name;
} else if (elementSize < minColumnSize) {
minColumnSize = elementSize;
minColumnName = name;
} else {
} }
//判断元素是否需统计若元素需要统计则对元素列表的个数加上当前获取到的元素个数若不需要统计则移除该元素
if (isAddSize) {
if (elementSizeMap.containsKey(name)) {
elementSizeMap.put(name, 0);
}
if (isStartAddSize) {
elementSizeMap.put(name, elementSizeMap.get(name) + elementSize);
}
} else {
if (elementSizeMap.containsKey(name)) {
elementSizeMap.remove(name);
}
}
}
/**
* 用于清除或移除指定的列及列中的元素当参数传入false时则只清理列表中存储的元素不移除
* 整个列若传入true时则直接移除整个列若列名称对应的列未被获取则返回null
* @param name 已被获取的元素列名称
* @param isRemove 是否需要将该列移除
* @return 被移除列中存储的所有元素
*/
public List<WebElement> clearColumn(String name, boolean isRemove) {
//若元素不存在则直接返回null
if (elementMap.containsKey(name)) {
return null;
}
//用于存储被移除的元素
List<WebElement> elementList = elementMap.get(name);
//判断元素是否需要被完全移除
if (isRemove) {
//若元素需要被完全移除则直接移除元素
elementMap.remove(name);
//由于元素被移除若该列存在元素个数统计则同样将该元素移除
if (elementSizeMap.containsKey(name)) {
elementSizeMap.remove(name);
}
} else {
//若元素无需移除则将元素存储的列表内容清空
elementMap.get(name).clear();
}
return elementList;
}
private int findColumnLimitSize(boolean isMax) {
//根据传入的参数判断是获取最大值还是获取最小值根据不同的类型初始化不同的参数
int limit = isMax ? -1 : Integer.MAX_VALUE;
//TODO 获取极值
elementMap.forEach((key, value) -> {
});
return limit;
}
@Override
boolean isExistElement(By by, long waitTime) {
//TODO 修改等待方法改为获取到元素后才返回相应的状态
//当查找到元素时则返回true若查不到元素则会抛出异常故返回false
return new WebDriverWait(driver, waitTime, 200).
until((driver) -> {
List<WebElement> elementList = driver.findElements(by);
//若获取的标题首行为标题行时则判断为获取到大于1个元素时返回true否则则大于0个元素返回true
if (isFristRowTitle) {
return elementList.size() > 1;
} else {
return elementList.size() > 0;
}
});
} }
} }

View File

@ -2,6 +2,7 @@ package pres.auxiliary.work.selenium.element;
import java.io.File; import java.io.File;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -22,7 +23,7 @@ import pres.auxiliary.work.selenium.brower.ChromeBrower.ChromeOptionType;
* *
*/ */
public class CommonElementTest { public class CommonElementTest {
ChromeBrower cb = new ChromeBrower(new File("Resource/BrowersDriver/Chrom/78.0394.70/chromedriver.exe")); ChromeBrower cb = new ChromeBrower(new File("Resource/BrowersDriver/Chrom/80.0.3987.163/chromedriver.exe"));
CommonElement ce; CommonElement ce;
@BeforeClass @BeforeClass
@ -31,6 +32,11 @@ public class CommonElementTest {
ce = new CommonElement(cb); ce = new CommonElement(cb);
} }
@AfterClass
public void qiut() {
cb.getDriver().quit();
}
/** /**
* 用于测试非xml文件中的传参进行窗体切换与元素的获取 * 用于测试非xml文件中的传参进行窗体切换与元素的获取
*/ */

View File

@ -0,0 +1,17 @@
package test.javase;
import java.util.HashMap;
import org.testng.annotations.Test;
public class TestMap {
HashMap<String, String> map = new HashMap<String, String>(16);
/**
* 用于测试map移除不存在的元素
*/
@Test
public void removeTest() {
System.out.println(map.remove("hehe"));
}
}