2

In our project we have multiple selenium tests run with cucumber which are testing specific components. One of these components are two identifiers, which we call country identifier and site identifier. These have the following HTML:

<div class="identifiers">   
    <div class="country-identifier">
        <span class="ident-label">
            Germany
        </span>
    </div>
    <div class="site-identifier">
        <span class="ident-label">
            Gaming
        </span>
    </div>
</div>

Now our tests have two models, one for each identifier:

@PageObject(css = "div.country-identifier")
@Named("CountryIdentifier")
@ScenarioScoped
public class CountryIdentifier {

    @Inject
    @CurrentScope
    private WebElement scope;

    @FindBy(className = "ident-label")
    @CacheLookup
    private WebElement label;

}

And:

@PageObject(css = "div.site-identifier")
@Named("SiteIdentifier")
@ScenarioScoped
public class SiteIdentifier {

    @Inject
    @CurrentScope
    private WebElement scope;

    @FindBy(className = "ident-label")
    @CacheLookup
    private WebElement label;

}

Now the problem is when I want to access the label of the site identifier the WebElement label is having the value Germany and not Gaming. This is because the css selector to get the value is apparently only applying the class name ident-label without taking into account the container class. I would expect the selector generated to find the label is combining the css defined for the page object with the selector in the @FindBy annotation. Is there a way to tell the web driver to find the element by class name only in the scope of the container specified in the css selector of the @PageObject annotation? Or do I need the full css selector in the FindBy annotation like:

@FindBy(css = "div.site-identifier .ident-label")

And

@FindBy(css = "div.country-identifier .ident-label")
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
Christoph
  • 63
  • 6

1 Answers1

1

Seems you were almost there. You can use the following locators to identify the respective elements:

  • Germany:

      @FindBy(css = "div.country-identifier span.ident-label")
    
  • Gaming:

      @FindBy(css = "div.site-identifier span.ident-label")
    

Update

As per your comment update as you asked about it is possible to only specify ".ident-label" and make the driver search only inside the container specified by the css of page object annotation, the answer is No. That's because the class ident-label is present under both the <div> tags as follows:

  • Germany:

      <span class="ident-label">
          Germany
      </span>
    
  • Gaming:

      <span class="ident-label">
           Gaming
      </span>
    

So, WebDriver instance can't distinguish them and will always pick up the first match as per the prevailing HTML DOM.


Solution

There can be two solution as follows:

  • The easiest of all take help of the parent <div> tag which have different class attribute for each of it's child tag.
  • Else use index.

The first approach is the best approach and followed mostly.

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Ok, this is what I can do to make it work. But I would expect the behavior to be that when I call the locator on the SiteIdentifier model it only looks for the specific class name inside the container div.site-identifier, which I specified in the annotation. So assuming there are a lot of elements inside the container and I change the class name of the container, I need to update all the locators of every element. – Christoph Jul 12 '18 at 11:19
  • He already had the css (note the bottom of his question), he was wondering instead whether the css of the element would be joined to the css of the page object. The answer of which is no, he needs to use the full css. – KyleFairns Jul 12 '18 at 11:19
  • @Christoph if I have understood properly your question is would `div.site-identifier .ident-label` suffice instead of `div.site-identifier span.ident-label`? Is it? – undetected Selenium Jul 12 '18 at 11:27
  • @DebanjanB No, I wanted to know whether it is possible to only specify ".ident-label" and make the driver search only inside the container specified by the css of page object annotation. – Christoph Jul 12 '18 at 11:34
  • @Christoph Check out my answer update and let me know if any further questions. – undetected Selenium Jul 12 '18 at 12:02
  • 1
    @KyleFairns Does my updated answer caters to the question completely now? – undetected Selenium Jul 12 '18 at 12:02
  • 1
    @DebanjanB It does – KyleFairns Jul 12 '18 at 12:53
  • @DebanjanB Ok, so I get from your answer that there is no way to get the behaviour that I would expect the page object model to work like. Still I think this is not optimal because of the problems I mentioned when changing the css of the component you have to change every selector from the member elements. – Christoph Jul 13 '18 at 08:08
  • @Christoph You are right in your conclusion. A few words, 1) Always try to construct a unique locator _css_ or _xpath_. 2) In the long run what matters most is the optimization of the selectors you use. 3) Emphasize on the _css_ that would enhance the performance aspects of your _Test_ and _Test Execution_. – undetected Selenium Jul 13 '18 at 08:57