1

The requirement is to get locator(By) of current web element.

For my project, I'm implimenting custom elements. So for a an HTML select element, there would be a class SelectElement and for an HTML option element, there would be class OptionElement.

To implement custom elements, I am using CustomWebElement class from this repository: https://github.com/JulHorn/java_selenium_custom_elements

I would like to retrieve selectElementInstance.getOptions() which should kind of return List<OptionElement>and not List<WebElement>.

So here is what I'm trying to do:

1) I am getting List<WebElement> using findElements(...) method.

2) In this list, I am iterating the element one by one.

3) Whichever WebElement i get, i want to retrieve instance of By for this element.

4) With By instance in hand and WebDriver instance already present, I can create custom element by using the constructor super(WebDriver driver, By by).

Below i have gave my code sample:

List<WebElement> myList = driver.findElement(By.xpath("//select[@id ='abcd']/*"));
ListIterator<WebElement> simpleChildIterator = myList.listIterator();
List<OptionElement> options = new ArrayList<OptionElement>();
while(simpleChildIterator.hasNext())
{
    By l = simpleChildIterator.next().getBy();//I want locator for same element
    //Here I can now create Instance of OptionElement to add to List<OptionElement>
    OptionElement o = new OptionElement(driver, l);
    options.add(o);
}

Please note that when I use OptionElement extends CustomWebElement implementation in Page Object in lines with PageFactory, the following works absolutely fine for me.

@findBy(xpath = "//select[@id ='abcd']/*")
List<OptionElement> options;

But this works because of PageFactory's magic that gets involved through its initElements() call.

I want the same to work without PageFactory's involvement when I am willing to define a new method List<OptionElement> getOptions() on my SelectElementclass.

I hope the question is clear now that I have made several edits.

Thanks to @Muzzamil for suggesting WebDriver should be singleton. I have removed that from my question. Also thanks to @Pranav to exemplify my issue with select and option elements. It is a better example to explain.

Madhav Saraf
  • 100
  • 1
  • 9
  • 1
    what is exactly use case? – Muzzamil Jan 09 '20 at 10:24
  • According to https://selenium.dev/selenium/docs/api/java/org/openqa/selenium/WebElement.html WebElement has no such method, since elements are not bound to some specific driver. But what you could probably do is to somehow create some class, which implements default WebElement. – Andriy Zhuk Jan 09 '20 at 10:29
  • 3
    Does this answer your question? [Get the By locator of an already found WebElement](https://stackoverflow.com/questions/31676964/get-the-by-locator-of-an-already-found-webelement) – Infern0 Jan 09 '20 at 10:47
  • @Muzzamil I want to getDriver and Locator of current element, if i manage to get this i have to create newInstance of child class using reflection API. – Madhav Saraf Jan 09 '20 at 10:47
  • @AndriyZhuk it will be better if you can share some snippet please? – Madhav Saraf Jan 09 '20 at 10:52
  • @MadhavSaraf As Infern0 mentioned, selenium library don't provide any such function to get 'by' and 'webdriver' from 'webElement'. Although I have custom solution to get 'By' from 'webElement' but similiar my solution also mentioned in this post : https://stackoverflow.com/questions/31676964/get-the-by-locator-of-an-already-found-webelement?noredirect=1&lq=1 . I still can share if you want? – Muzzamil Jan 09 '20 at 11:33
  • 1
    Still I will ask why you need driver instance from webElement? As per my point of view, There is no need of get driver instance as generally we keep single driver instance. Additionally you can use Singleton design pattern for get single driver instance so you can use common driver instance, as it will be single instance every time and no need to get it from webElement. – Muzzamil Jan 09 '20 at 11:38
  • @Muzzamil Here is a use use case: We have select as a element and If we want to get list of options in this select element, that is not achivable with the List. i.e we need list of options rather than list of webelements – Pranav Bhagwat Jan 09 '20 at 11:47
  • @PranavBhagwat Basically you want to select an option from list. And you have parent node as select tag and child nodes as an options tag? – Muzzamil Jan 09 '20 at 12:51
  • @Muzzamil i have edited my question, now i hope you will understand it better, moreover we are implementing custom web element. – Madhav Saraf Jan 09 '20 at 12:57

2 Answers2

4

So basically you need By element from webElement. You can try this:

private By getByFromElement(WebElement element) {

    By by = null;
    String[] selectorWithValue= (element.toString().split("->")[1].replaceFirst("(?s)(.*)\\]", "$1" + "")).split(":");

    String selector = selectorWithValue[0].trim();
    String value = selectorWithValue[1].trim();

    switch (selector) {
        case "id":
            by = By.id(value);
            break;
        case "className":
            by = By.className(value);
            break;
        case "tagName":
            by = By.tagName(value);
            break;
        case "xpath":
            by = By.xpath(value);
            break;
        case "cssSelector":
            by = By.cssSelector(value);
            break;
        case "linkText":
            by = By.linkText(value);
            break;
        case "name":
            by = By.name(value);
            break;
        case "partialLinkText":
            by = By.partialLinkText(value);
            break;
        default:
            throw new IllegalStateException("locator : " + selector + " not found!!!");
    }
    return by;
}
Muzzamil
  • 2,823
  • 2
  • 11
  • 23
  • You can accept it as answer if it serve your purpose. It can help people with similar problem in future. – Muzzamil Jan 09 '20 at 14:08
0

Ok, so here is VERY dirty solution - please DO NOT use this in production but just as an idea for your specific question: So, first you can create class for the web driver:

public class WebDr {

    private ChromeDriver driver;

    public WebDr(ChromeDriver driver) {
        this.driver = driver;
    }

    public void get(final String url) {
        this.driver.get(url);
    }

    public WebEl getElem(By by) {
        return new WebEl(driver.findElement(by), this.driver);
    }
}

Also, here is class for WebElement:

public class WebEl {

    private WebElement elem;
    private WebDriver driver;

    public WebEl(WebElement elem, WebDriver driver) {
        this.elem = elem;
        this.driver = driver;
    }

    public WebDriver getDriver() {
        return this.driver;
    }
}

Finally in your code you can do similar to:

public class MainCl {

    public static void main(String[] args) throws Exception {
        System.setProperty("webdriver.chrome.driver", "C:\\***\\chromedriver.exe");
        WebDr driver = new WebDr(new ChromeDriver());

        driver.get("https://www.google.com/");


        Thread.sleep(5000);
        WebEl myElem = driver.getElem(By.name("q"));
        System.out.println(myElem.getDriver());

    }
}

And, of course, the same can be done for list of WebEl.

Andriy Zhuk
  • 133
  • 6