如何在 Java 中为 Selenium webdriver 编写我自己的自定义定位器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14263483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 15:39:46  来源:igfitidea点击:

How to write my own customize locator for Selenium webdriver in java?

javaseleniumwebdriverselenium-webdriverbrowser-automation

提问by BlueSky

I want to write my own locator to access the elements. WebDriver's API offers currently eight locators allowing to retrieve elements by id, name attribute, tag name, complete or partial link text, XPath, class name, and css selector. However those default locators not enough for me now because I have to access the elements through a new attribute. Let me give an xample so that you can understand what I really want here.

我想编写自己的定位器来访问元素。WebDriver 的 API 目前提供八个定位器,允许通过 id、名称属性、标签名称、完整或部分链接文本、XPath、类名和 css 选择器检索元素。但是,这些默认定位器现在对我来说还不够,因为我必须通过新属性访问元素。让我举个例子,让你明白我在这里真正想要的是什么。

Example: Choose your username:

示例: 选择您的用户名:

Now I want to write a code so that I can access the username button using the myLocator locator like:

现在我想编写一个代码,以便我可以使用 myLocator 定位器访问用户名按钮,例如:

*driver.findElement(By.myLocator("username")).*

It would be very helpful if anybody can give us some good idea how could I rewrite the BY class to add my own locator.

如果有人能给我们一些好主意,我将如何重写 BY 类以添加我自己的定位器,这将非常有帮助。

Thank you in advance for your help.

预先感谢您的帮助。

采纳答案by Arran

You would need to subclass the Byclass and provide an implementation for findElementand findElementsmethods, since this is where the 'meat' of the actual element finding occurs.

您需要对类进行子By类化并提供findElementfindElements方法的实现,因为这是实际元素查找的“肉”发生的地方。

You should then be able to use it with the normal driver.FindElementthen.

然后,您应该可以正常使用它driver.FindElement

回答by Sridhar

using c#

使用 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;
        };
    }
}

and the usage would be as follows

用法如下

[FindsBy(How = How.Custom, Using = @"/path/to/img", CustomFinderType = typeof(ImageBy) )]
private IWebElement MenuStartButton = null;

Using Java

使用 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;
    }
}

usage :

用法 :

WebElement element = driver.findElement(new ByImageSrc("/path/to/image"));

回答by Vivian Nastasa

You can do something like this:

你可以这样做:

private final String myLocator = "//*[contains(@id,'username') and contains (@type,'text') and contains (text(),'exactly what I want')]";

So you can write up the locator however you wish, depending on the attributes that what you're mapping has, no need to have 5 rows for a click or select.

因此,您可以根据自己的意愿编写定位器,具体取决于您要映射的内容的属性,无需单击或选择 5 行。

Also, you can use a wildcard in that locator and just replace whatever you want to use as a parameter with "%s", like this:

此外,您可以在该定位器中使用通配符,只需将您想用作参数的任何内容替换为“%s”,如下所示:

private final String myLocator = "//*[contains(@id,'%s') and contains (@type,'text') and contains (text(),'exactly what I want')]";

Then have a dynamic element created from that like:

然后创建一个动态元素,例如:

private WebElement usernameSelectElement(String text) {
    return driver.findElement(By.xpath(String.format(myLocator, text)));
}

And the usage would be something like:

用法类似于:

public void clickMyElement(text){
usernameSelectElement(text).click();
}

For the example that you had, it's just overly complicated in my view.

对于您提供的示例,我认为它过于复杂。

回答by Michiel

I know this doesn't really answer your question, but why not just use Xpath? It seems like it would be a lot of extra work to build out a new locator instead of just crawling the DOM.

我知道这并不能真正回答您的问题,但为什么不直接使用 Xpath?构建一个新的定位器而不是仅仅爬取 DOM 似乎需要做很多额外的工作。

For example: driver.findElement(By.Xpath("//div[@username='YourUsername']")

例如: driver.findElement(By.Xpath("//div[@username='YourUsername']")

I could give a better example with some more detail about the attribute and page you're working with.

我可以提供一个更好的示例,其中包含有关您正在使用的属性和页面的更多详细信息。

回答by Nashibukasan

Much like Michiel answered I feel you can achieve what you want with what Selenium has already provided. If it is a maintenance overhead you are wanting to avoid due to developers altering ids and element names you can create a separate file that keeps track of the elements you need to locate.

就像 Michiel 回答的那样,我觉得你可以用 Selenium 已经提供的东西来实现你想要的。如果这是由于开发人员更改 id 和元素名称而想要避免的维护开销,您可以创建一个单独的文件来跟踪您需要定位的元素。

//EG. (not Java I know :))
string usernameXPath = "//div[@username='YourUsername']";

Then if there is a change you can maintain this. You could even go a step further and implement a class for each 'other type' of element and just put an XPath around it in the constructor. XPath is very flexible as it offers functions such as 'contains' and 'parent::div'. Maybe look at the W3schools pagefor some more XPath reading.

然后如果有变化,你可以保持这个。您甚至可以更进一步,为每个“其他类型”的元素实现一个类,然后在构造函数中围绕它放置一个 XPath。XPath 非常灵活,因为它提供了诸如 ' contains' 和 ' parent::div' 之类的功能。也许查看W3schools 页面以获取更多 XPath 阅读资料。

EDIT: Also worth noting is that the C# bindings latest release says the following:

编辑:另外值得注意的是,C# 绑定的最新版本说明如下:

.Net: Introduces the Updating the CustomFinderType property to the .NET FindsByAttribute. This allows use of custom By subclasses in the PageFactory. The custom finder must be a subclass of By, and it must expose a public constructor that takes a string argument.

.Net:将更新 CustomFinderType 属性引入 .NET FindsByAttribute。这允许在 PageFactory 中使用自定义 By 子类。自定义查找器必须是 By 的子类,并且必须公开一个接受字符串参数的公共构造函数。

Hopefull this is in the next Java release for you too :)

希望这也将在下一个 Java 版本中为您提供 :)