我想编写自己的定位器来访问元素。 WebDriver的API提供了八个定位器,允许通过id,name属性,标签名称,完整或部分链接文本,XPath,类名和css选择器来检索元素。但是现在这些默认定位器对我来说还不够,因为我必须通过新属性访问元素。让我举一个例子,这样你就可以理解我真正想要的东西了。
实施例: 选择您的用户名:
现在我想编写一个代码,以便我可以使用myLocator定位器访问用户名按钮,如:
*driver.findElement(By.myLocator("username")).*
如果有人能给我们一些好主意,我怎么能重写BY类来添加我自己的定位器,这将是非常有用的。
提前感谢您的帮助。
答案 0 :(得分:4)
使用c#
using OpenQA.Selenium;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class ImageBy : By
{
public ImageBy(string imageByString)
{
FindElementMethod = (ISearchContext context) =>
{
IWebElement mockElement = context.FindElement(By.XPath("//img[@src='" + imageByString + "']"));
return mockElement;
};
FindElementsMethod = (ISearchContext context) =>
{
ReadOnlyCollection<IWebElement> mockElements = context.FindElements(By.XPath("//img[@src='" + imageByString + "']"));
return mockElements;
};
}
}
,用法如下
[FindsBy(How = How.Custom, Using = @"/path/to/img", CustomFinderType = typeof(ImageBy) )]
private IWebElement MenuStartButton = null;
使用Java
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
public class ByImageSrc extends By
{
private final String imageByString;
public ByImageSrc(String imageByString)
{
this.imageByString = imageByString;
}
@Override
public List<WebElement> findElements(SearchContext context)
{
List<WebElement> mockElements = context.findElements(By.xpath("//img[@src='" + imageByString + "']"));
return mockElements;
}
}
用法:
WebElement element = driver.findElement(new ByImageSrc("/path/to/image"));
答案 1 :(得分:1)
您需要对By
类进行子类化,并为findElement
和findElements
方法提供实现,因为这是实际元素查找的“肉”。
然后,您应该能够使用普通的driver.FindElement
。
答案 2 :(得分:0)
我知道这并没有真正回答你的问题,但为什么不只是使用Xpath? 看起来构建新的定位器而不是仅仅抓取DOM会有很多额外的工作。
例如:driver.findElement(By.Xpath("//div[@username='YourUsername']")
我可以提供一个更好的示例,其中包含有关您正在使用的属性和页面的更多详细信息。
答案 3 :(得分:0)
很像Michiel的回答,我觉得你可以用Selenium提供的东西达到你想要的效果。如果由于开发人员更改id和元素名称而需要避免维护开销,则可以创建一个单独的文件来跟踪需要定位的元素。
//EG. (not Java I know :))
string usernameXPath = "//div[@username='YourUsername']";
然后,如果有变化,你可以保持这个。您甚至可以更进一步为每个“其他类型”的元素实现一个类,只需在构造函数中放置一个XPath。 XPath非常灵活,因为它提供了诸如' contains '和' parent :: div'之类的功能。也许请查看W3schools page以获取更多XPath读数。
编辑:另外值得注意的是C#绑定最新版本说明如下:
.Net:介绍将CustomFinderType属性更新到 .NET FindsByAttribute。这允许使用自定义By子类 PageFactory。自定义查找器必须是By和的子类 它必须公开一个带有字符串参数的公共构造函数。
Hopefull这也适用于你的下一个Java版本:)
答案 4 :(得分:0)
您可以这样做:
private final String myLocator = "//*[contains(@id,'username') and contains (@type,'text') and contains (text(),'exactly what I want')]";
因此,您可以根据需要编写定位器,具体取决于您要映射的属性,单击或选择不需要5行。
此外,您可以在该定位器中使用通配符,只需将要用作“%s”的参数替换为参数,如下所示:
private final String myLocator = "//*[contains(@id,'%s') and contains (@type,'text') and contains (text(),'exactly what I want')]";
然后创建一个动态元素:
private WebElement usernameSelectElement(String text) {
return driver.findElement(By.xpath(String.format(myLocator, text)));
}
用法如下:
public void clickMyElement(text){
usernameSelectElement(text).click();
}
对于你所拥有的例子,我认为它过于复杂了。