菜单栏,由于安装不同的组件导致录制的xpath发生变化。
左侧树,由于左侧树由于业务会经常发生变动,导致录制xpath发生变化。
列表信息,通常一个列表里面包含N多数据,我们不可以挨个去录制。且列表一般都是可配置列的。
动态id,很多弹出页面,弹出框之类的页面大多都使用的是动态id
为解决此类问题,我们要学会活用selenium为我们提供的多种定位方式。 用以达到用例稳定运行的目标。
By.id定位是最高效也是首选的方法用于查找一个元素。UI 开发人员常犯的错误是,要么没有指定id,要么自动生成随机 id,这两种情况都应避免。及时是使用 class 也比使用自动生成随机 id要好的多。
HTML:
Java:
WebElement element = driver.findElement(By.id("coolestWidgetEvah"));
By xpath: 在没有id的场景中。 最常用的是xpath。无所不能的定位方式。 类似如下所示。
定位图片:
xpath=//img[@alt='image alt text goes here']
定位表格:
xpath=//table[@id='table1']//tr[4]/td[2]
xpath=(//table[@class='nice'])//th[text()='headertext']/
定位a标签
xpath=//a[contains(@href,'href goes here')]
xpath=//a[contains(@href,'#id1')]/@class
定位input
xpath=//input[@name='name2' and @value='yes']
Java:
WebElement element = driver.findElement(By.xpath(xpath));
By Link Text :查找链接文字匹配的链接元素。
HTML:
Java:
WebElement cheese = driver.findElement(By.linkText("cheese"));
By Partial Link Text:查找链接文字部分匹配的链接元素。
HTML:
Java:
WebElement cheese = driver.findElement(By.partialLinkText("cheese"));
在我们http://www.seleniumeasy.com/test/页面为例:
例如: 点击报表列表。
点击菜单:
我们通过直接录制点击报表的形式因为安装的控件原因会导致xpath等发生变化导致定位失败。
此时我们若使用类似如下方法, 将使用By.partialLinkText(reportmenu)的方式直接点击菜单名称。 会很大程度提升用例的稳定性。
public void clickMenu(String reportmenu) {
drivre.findElement(By.partialLinkText(reportmenu)).click();
}
By Tag Name 是一个特别好用的定位方式。 多用于都配合driver.findElements(By.tagName(name))使用。
例如:
下拉框:
列表:
树形菜单:
如上图所示:
当我们需要处理类似多种数据时。 比如我们需要遍历下拉列表。 遍历获取列表框中的数据。 点击树状菜单时。 此时通过 By Tag Name 是最好的选择方式。
如下代码,我们首先定位到下拉列表框。 然后通过By.tagName("div")),获取自称元素。
再通过element.findElements(By.tagName("div")) 的方式获取我们所需要的所有的列表数值。
后续我们通过传入的参数进行操作。 可以达到整个版本通用。
public static void selectByVisibleText(WebDriver driver, String visibleText) {
WebElement element = driver.findFirstElement(By.tagName("div"));
List elementList = element.findElements(By.tagName("div"));
logger.info("elementList.size():" + elementList.size());
for (WebElement webElement : elementList) {
String text = webElement.getText();
logger.info("text:" + text);
if (visibleText != null && text.contains(visibleText)) {
BasicAction.sleep(1);
webElement.click();
break;
}
}
}
当我们处理list列表的时候,只需要获取到table的元素。 然后通过By.tagName("tr")) 获取行元素
再通过By.tagName("td"))获取列元素。
通过行列的两层遍历便可得到整个列表的元素信息。
public static JSONArray getListInfo(WebElemnt table) {
JSONObject object = new JSONObject();
JSONArray array = new JSONArray();
List rows = table.findElements(By.tagName("tr"));
// logger.info("rows size: " + rows.size());
for (WebElement row : rows) {
if (row.getAttribute("class").contains("eview-table-tr")) {
List cols = row.findElements(By.tagName("td"));
if (cols.size() == 1) {
break;
} else {
for (WebElement col : cols) {
object.put(col.getAttribute("data-colid"), col.getText());
}
array.add(object);
}
}
}
return array;
}
如下所示,我们需要获取弹出框中的提示信息时。 当前页面弹出框 没有其他可定位的条件。 此时通过唯一的className定位是极好的。
public static String getMsgDialogText() {
WebDriver driver ;
String text = driver.findElement(By.className("eview-msg-content")).getText();
logger.info("MessageDialog Text:" + text);
return text;
}
定位类似标签页中有多个class的。 此时我们使用className定位不都准确。可以使用css的定位方式处理。
public static JSONObject getPortalNameJson(WebElement chartElement) {
JSONObject object = new JSONObject();
WebElement yElement = chartElement.findElement(By.cssSelector(".dual-list list-left.col-md-5"));
List divElements = yElement.findElements(By.className("list-group-item"));
Map deviceMap = new LinkedHashMap();
Map devicePointMap = new LinkedHashMap();
for (WebElement webElement : divElements) {
String title = null;
title = webElement.getText();
if (title.endsWith("...")) {
title = webElement.getAttribute("title");
title = "..." + title; //表示该设备名称未全部显示
}
String index = webElement.getAttribute("index");
String namePoint = webElement.getLocation().toString();
devicePointMap.put(title, namePoint);
deviceMap.put(index, title);
}
object.put(NAME_MAP, deviceMap);
object.put(NAME_POINT_MAP, devicePointMap);
logger.info("getPortalNameJson object: " + object);
return object;
}