Kumar Gaurav
Kumar Gaurav

Reputation: 769

Extending selenium2library WebElement in RobotFramework

I am new to RobotFramework (actually evaluating it for a new test automation project).

In the past, I always created my own little framework using Java and page objects however this time I am wondering whether I can use an existing framework. I am evaluating Spock and Robot Framework.

My requirement is to test web application, windows objects and mobile apps so Robot definitely has an edge over Spock. Also I would prefer Python over Groovy any day.

I usually extend WebElement in my framework with following code. I am wondering whether it would be possible to do such things in Robot Framework.

//importing webdriver and other selenium libraries
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.internal.Coordinates;
import org.openqa.selenium.internal.Locatable;
import org.openqa.selenium.internal.WrapsElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;

//interface that will be implemented by my custom web element
interface MyElement extends WebElement, WrapsElement, Locatable {

}

//my custom web element class
public class MyWebElement implements MyElement {

    private WebElement element;

    //private constructor for my web element class
    private MyWebElement(WebElement element) {
        this.element = element;
    }

    //public factory method for my web element class
    public static MyWebElement getInstance(By by) {
        WebElement element = MyWebDriver.getInstance().findElement(by);
        MyWebElement myWebElement = new MyWebElement(element);
        return myWebElement;
    }

    //overriding WebElement method click
    @Override
    public void click() {
        waitUntilClickable();
        element.click();
    }

    //adding method waitUntilClickable to my web element
    public MyWebElement waitUntilClickable() {
        return waitUntilClickable(MyWebDriver.getTimeoutElementInMilliseconds(),
                MyWebDriver.getPollingElementInMilliseconds());
    }

    //adding helper method to implement waitUntilClickable
    public MyWebElement waitUntilClickable(long timeOutInMilliseconds,
            long pollingIntervalInMilliseconds) {
        Wait<WebDriver> wait = new FluentWait<WebDriver>(MyWebDriver.getInstance())
                .withTimeout(timeOutInMilliseconds, TimeUnit.MILLISECONDS)
                .pollingEvery(pollingIntervalInMilliseconds, TimeUnit.MILLISECONDS);
        wait.until(ExpectedConditions.elementToBeClickable(element));
        return this;
    }
   //other additional and overriding methods
   //.........................
   //.........................

Robot Framework looks good so far, I like python too.. however I don't know whether I would be able to extend the libraries like selenium2library to have my own custom methods, like I used to do in java in above examples.

Upvotes: 0

Views: 1229

Answers (2)

Bryan Oakley
Bryan Oakley

Reputation: 386362

You can, but I'm not sure what value that provides with respect to robot framework. For an example of how to subclass the library and/or get access to the actual webdriver object, see the answers to this question: Pass existing Webdriver object to custom Python library for Robot Framework

However, the whole point of using robot is that you are not calling webdriver functions directly. You can certainly override the methods (known as "monkeypatching" in python) and the keywords will use your patched functions, but that's not really necessary. When you use robot, you shouldn't be interacting directly with web elements.

With robot framework you should be writing tests that are more abstract. For example:

*** Test Cases ***
| Login with valid credentials
| | Go to page | LoginPage
| | Enter the username | [email protected]
| | Enter the password | letmein!
| | Click the login button
| | The current page should be | DashboardPage

Notice how the test doesn't use web elements at all. It uses high level keywords that eliminate the need to interact directly with web elements, add waits, etc. The test writer is completely isolated from the actual implementation of the page so they can focus on the logic of the test itself.

Of course, robot doesn't provide such keywords since it is a generic framework. It provides generic keywords ("go to page", "click button", etc), but that's not where the true power of robot framework comes in. The real power comes from custom page-specific libraries.

In your example you showed overriding the click method so that you could add an explicit wait. Instead of overriding the method, with robot you can build the waiting into the keyword itself wherever it makes sense.

For example, the implementation of the "Click the login button" might look something like this:

def click_login_button(self):
    with self._wait_for_page_refresh():
        WebDriverWait(self.browser, 10).until(
            lambda *args: button_element.element_to_be_clickable((By.ID, locator.login_button))
        )
        self.browser.find_element_by_id(locator.login_button).click()

In this example, we've taken care of waiting for the element to be clickable, we click on it, and then we wait for the page to be refreshed before returning. Notice how, within the keyword itself you have the full power of python and selenium at your disposal even though none of that is visible at the test case level.


Note: these examples are roughly based on a library I wrote that implements the page object pattern with robot. For more information on that library see this blog post: Robot Framework Page objects

Upvotes: 3

A. Kootstra
A. Kootstra

Reputation: 6981

Writing extensions in Python and Java are possible. However, I think that using the already available keywords and creating your testing logic by crafting custom keywords using existig functionality is how most of us create our test cases.

Upvotes: 0

Related Questions