FindBy strategies for Selenium explained

The @FindBy annotation is used in Page Objects in Selenium tests to specify the object location strategy for a WebElement or a list of WebElements. Using the PageFactory, these WebElements are usually initialized when a Page Object is created. In this post, I will demonstrate various ways in which you can use @FindBy annotations to efficiently locate (groups of) WebElements.

The @FindBy annotation is used to locate one or more WebElements using a single criterion. For example, to identify all elements that have the same class attribute, we could use the following identification:

@FindBy(how = How.CLASS_NAME, using = "classname")
private List<WebElement> singlecriterion;

If we are sure there is only a single element that is identified by our location strategy, for example when we use the element ID, we can also directly assign the result to a WebElement variable:

@FindBy(how = How.ID, using = "elementid")
private WebElement element;

To instantiate the elements, we call the initElements method of the PageFactory class:

PageFactory.initElements(driver, this);

@FindBys and @FindAll
In some cases we want (or need) to use more than a single criterion to identify one or more objects, for instance when page elements do not have a unique ID. In this case, there are two possible annotations that can be used:

  • The @FindBys annotation is used in case elements need to match all of the given criteria
  • The @FindAll annotation is used in case elements need to match at least one of the given criteria

Let’s take a look at an example that illustrates the difference between the two.

The Parabank homepage contains two textboxes, one for the username and one for the password. Both elements have a name attribute that we are going to use to identify them within a Page Object.

Using @FindBys:

	@FindBy(how = How.NAME, using = "username"),
	@FindBy(how = How.NAME, using = "password")
private List<WebElement> bothcriteria;

The bothcriteria list should contain 0 elements, as there is no element that has both a name attribute with the value username and a name attribute with the value password.

Using @FindAll:

	@FindBy(how = How.NAME, using = "username"),
	@FindBy(how = How.NAME, using = "password")
private List<WebElement> eithercriterion;

The eithercriterion list should contain 2 elements, as there is one element that has a name attribute with the value username and also one that has a name attribute with the value password.

For validation purposes, if we print the number of results found by all of the above strategies using

System.out.println("Using @FindBy, we found " + singlecriterion.size() + " element(s)");
System.out.println("Using @FindBys, we found " + bothcriteria.size() + " element(s)");
System.out.println("Using @FindAll, we found " + eithercriterion.size() + " element(s)");

we see this:
Results for different FindBy strategiesIt clearly works exactly as expected!

A more verbose FindBy
Finally, if you have a lot of elements within your Page Object, you can also use a more verbose way of specifying your @FindBy strategy. For example

@FindBy(className = "classname")

gives the exact same results as

@FindBy(how = How.CLASS_NAME, using = "classname")

47 thoughts on “FindBy strategies for Selenium explained

  1. Nice job Bas, as always…very useful tutorial and great topic…this is a really efficient way to work with page elements…saves a lot of keystrokes and makes the code much easier to read.

  2. Hi Sunny,

    a NoSuchElementException is still thrown if you use for example

    @FindBy(how = How.CLASS_NAME, using = “classname”)
    private WebElement element;

    and your element does not exist on the page.

    If you use

    @FindBy(how = How.CLASS_NAME, using = “classname”)
    private List elementlist;

    you will always have a list of WebElements you need to loop through. If you specify your How’s incorrectly you might end up with an empty List, which might also result in NoSuchElementExceptions or NullPointerExceptions depending on your implementation.

    So by no means is using @FindBy a way to prevent NoSuchElementExceptions from occurring.

  3. Hi Bas,

    I am using Selenium C# code to create my test scripts.

    At once place I need to add mileage in required input filed. Through selenium code I enter the mileage and click on Next link.

    When my Firefox browser is opened it works fine it takes mileage input and click on next link and it slides to next screen.

    But when my Firefox browser is minimized it does not work, it takes input even though while clicking on Next it gives error to enter mileage.

    wait.Until(ExpectedConditions.ElementToBeClickable(By.Id(“mileageInput”))).SendKeys(“99”); Log.Info(“Mileage input end” + _driver.FindElement(By.Id(“mileageInput”)).Text);

    Also note that in log file input data is displayed correctly though while clicking next it gives error.

      • Thanks Bas!

        I appreciate your efforts to help people like us!

        Using my test script, I am creating bulk data by providing bulk input through .csv.

        So while my test script is executing I am doing another work and wanted it to be executed. If I did not minimize the browser just work with any other application then also it is not working. Script runs only in the case the browser is focused.

        Let me know in future you come across any solution for this.

        • Hi Manasi,

          I get your problem. Are there no ways to work around this? For example:

          * by using a different workstation to run your data entry script / test on?
          * by bypassing the UI altogether and entering the data using an API or a database insert?

          • Hi Bas,

            Here, I am with a new issue.

            I have a test script written in Selenium C# and working properly in FireFox.

            Now I am trying to execute the script in chrome. But when I pass 17 characters of input through sendKeys() method but in input field only few characters are input others are missing.

            It would be great if you can help me in this.

            Facing the same issue mentioned in

            And tried the solutions mentioned in this like sending single key one by one but didn’t work.

            Please suggest.

          • Hi Manasi,

            did you try to change your keyboard language too like it is suggested in the link you provided?

            If that didn’t help either I’m afraid I don’t know a solution to your issue either..

  4. Hi Bas,
    I tried to use:
    [FindsBy(How = How.XPath, Using = “//*[@id=’sidebar’]/div[2]/div/div/div”)]
    public List allElements;

    I am getting following ERROR:
    ‘system.argumentexception: object of type ‘castle.Proxies.IwrapsElementProxy_1’ cannot be converted to type ‘System.Collections.Generic.List 1 [OpenQA.Selenim.IWebElemen]’

    Any help is much appreciated.


    • Could you send me the code for the class where this is occurring, to bas AT ? I don’t think this is a really difficult one (just a matter of using the wrong object type in your code) but I can’t say without taking a look at the class as a whole. Please also specify in the mail if there are any other NuGet packages I need apart from Selenium and Castle DynamicProxy (which I think you’re using here).

  5. I created the selenium test project using microsoft test framework with c#.
    In PageFactory pattern how we can manage the element not found exception as one of my page is loaded with static content and some filed populated with web api call, so problem is until that filed populated my test case throwing the error element not visible or element not found exception

    Kindly provide the C# example with pagefactory pattern

    • Hi Swapnil,

      when you use the PageFactory pattern the element is retrieved from the DOM (using FindElement()) every time you reference it. The problem is that it isn’t there when you reference it, because your page content is dynamic. This is one of the problems I have with PageFactory too, and it’s also the reason I do not use it. Instead, what I have done is implementing a wrapper method that waits for a specific time interval every time an object is referenced, before throwing an error. See this post for an example.

      I’m aware that this isn’t a direct answer to your question but it is the best I can do at the moment.

  6. Pingback: Comparing @FindBy and Map repository approaches | rafazzevedo

  7. Hi Bas,

    what are the advantages if say ill just assign all elements using WebElement directly over using @FindBy annotation?

    currently i am not using @FindBy annotation and Pagefactory. What im implementing is assigning all elements using WebElement then accessing all my page methods in test class by instantiating my page object class.

    im just confused if ill proceed with rewriting my script to adopt page factory design.

    • Hey Ken,

      as usual: it depends. One feature of the PageFactory is that every time an object created using the PageFactory (with @FindBy) is referenced in your code, it is searched again automatically by the driver object. This is a good thing when you’re using an AJAX-heavy page with a lot of front-end processing going on. If you’d use your approach for such a web page, then the risk of the object not being there when you reference it (resulting in either a NoSuchElementException or more likely a StaleElementReferenceException) will increase.

      If, on the other hand, you’re pretty sure that your object will be there at the time of reference (of course you still need to provide some error handling), then there’s no real advantage of using the PageFactory.

      Personally I’m not too big a fan of the PageFactory pattern either, if only because it doesn’t support dynamic ID’s (for example XPath expressions that contain a variable whose value is to be determined at runtime).

      • Thanks for the response.

        in connection with the topic, i wanna know how to use @FindBys/All in selecting items in the dropdown. my implementation is ill create a random number based on the length of items in the dropdown. the random number will be the selection for which the item selected. will it be possible in using this annotation?

        same with selecting a date from a jquery datepicker. can it be possible with this annotation?

        • I don’t think that’s a very good idea. Why would you want to build (pseudo-)randomness like that into your tests? Automated checks are all about predictability, having randomness in them will very likely only lead to flaky tests and test code that is harder to maintain..

          • it is just for selecting items in the dropdown. i dont want to select the same item all throughout my tests. somehow when i make it random i can select other items w/o creating a test for each. its a lazy approach though. 🙂

            any suggestion how will i go about the scenario? Thanks

  8. Hi Bas,

    Can Something like:

    List element = driver.findEleemnt(“an id “)).findElements(By.tagName(“tr”)) is possible using these find annotation. If yes kindly give any small code example.

    • Hi Keshav,

      that’s not going to work probably. The first driver.findElement() returns only a single element (at most), what’s the point of the second findElements() in that case? You already have a specific element. It might be useful the other way around (first select a number of elements that have the
      tag, then select from that subset the one with id ‘an id’). I think you’re better off writing an appropriate CSS or XPath selector in that case, because it will only search the DOM once.

  9. Hi Bas,

    I am not getting use of


    While we have direct

    in POM

    and When we use @FindAll And @FindBys annotaion In POM

  10. Pingback: Understanding FindsBy in Selenium | Selenium Bytes

  11. Hi Bas,

    we have big test project for our web app. It has dozens on classes separated in packagase – test classes, parameters, page classes, constants.

    Naturally the project contains thousands of webelements. What we do now is that at the beginning of each page class we define all objectst on that page using @FindBy and then the methods for defined objects (fill form etc.).

    Problem is that we have a lot of elements on each page and it makes our classes too long and not so easy to read.

    We have also the problem that we can not use variables in selectors using @FindBy (as you mentioned before) and it would be really helpful sometimes.

    We are thinking to put our selectors to string constants and put variables in them using String.format(). Then we define object in method where we use it:
    WebElement filterButton = driver.findElement(By.xpath(String.format(XPATH_FILTER_BUTTON, columnName)));;

    What do you think about tis approach? Do you have any suggestion for web elements definition in big projects?

    • The String.format option sounds good, I used to do this with simple string concatenation but this is even better.

      And if your classes are getting too big then you simply need to refactor them and split them up in smaller classes (one for each form, for example). Or you could take a look at the Screenplay pattern as an alternative to the Page Object pattern, but that would probably require a lot of rework..

      Hope that helps! If not, do let me know.

  12. Hi there!

    Is there any way to find elements based on a parent element using the FindBy annotations? I’m using C# btw.

    Great post!

      • consider i have defined 2 elements using @Findby as below :

        private WebElement txt_username;

        private WebElement txt_password;

        and due to incorrect xpath both the findby fails. (noSuchElementFound)
        MyQuestion is , How to catch exception and display which element failed ?

        (hope im clear this time 🙂 )

        • Yeah I see what you’re trying to do now. I can’t think of an elegant way to do this using the PageFactory. I don’t even particularly like the PageFactory, if only because it doesn’t support dynamic locators (with variables in them). One alternative is to use wrapper methods around the Selenium API calls (hey look, here’s a blog post on that) and write some decent debugging / failure info to your output of choice. In that way, you know exactly what element couldn’t be found AND you can deal with dynamic locators.

  13. hi Bas,

    I am using @FindBy annotation in my code in the below form.

    WebElement auditbutton;

    the xpath is correct and i am clicking on the webelement taht i have defined.But i am getting null pointer exception.
    Is it that @FindBy annotation runs with some particular version of testng.
    Please help me on this.

    Thanks in advance

Leave a Reply

Your email address will not be published. Required fields are marked *