JA Nek
JA Nek

Reputation: 11

Selenium Webdriver findelement i sendKeys() isn't behaving as expected

I am trying to identify elements in Firefox using below xpath and name values in selenium webdriver but it is not working. This is link to the web page which I want to automate. All of the input fields on this page look weird to me and I don't understand how to fill them.

driver.findElement(By.name("sender-postCode")).sendKeys("02791");
driver.findElement(By.xpath(".//*[@id='stepOneForm']/div[2]/div[4]/div[1]/div[1]/div[1]/input")).sendKeys("02791");

This is my code:

package SalesBar;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.firefox.internal.ProfilesIni;
public class Salesbar {
public static void main(String[] args) throws Exception {
    // TODO Auto-generated method stub
    System.setProperty("webdriver.gecko.driver", "C:/Users/User/Documents/SeleniumWebDriver/geckodriver.exe");
    ProfilesIni profil = new ProfilesIni();
    FirefoxProfile myprofile = profil.getProfile("default");

    WebDriver driver;
    driver = new FirefoxDriver(myprofile);

    driver.get("https://wwwuat.dpdpickup.pl/Wycen-i-nadaj-Online");
    driver.findElement(By.xpath(".//*[@id='contentWrapper']/div/div/div[2]/div[1]/a")).click();
    Thread.sleep(3000);
    driver.findElement(By.xpath(".//*[@id='stepOneForm']/div[2]/div[3]/span[2]/label/span")).click();
    Thread.sleep(3000);
    driver.findElement(By.name("parcels-1-weight")).sendKeys("5");
    }

Please let me know if there is a standard way in WebDriver to find and fill these fields.

Upvotes: 1

Views: 605

Answers (1)

MikeJRamsey56
MikeJRamsey56

Reputation: 2829

An issue with all test automation tools is that the page may not have finished loading the DOM when the automation tool executes. There are various levels of sophistication that can be employed to get this to be 100% reliable. The first line of defense is to use ExpectedConditions. So for your first example,

WebDriver webDrive = ... // You have to initialize to a browser instance and navigate to your web page
By bySenderPostCode = By.name("sender-postCode");
Wait<WebDriver> wait_element = new WebDriverWait(webDriver, 40); // Wait up to 40 seconds
WebElement senderPostalCodeElement = wait_element.until(ExpectedConditions.visibilityOfElementLocated(bySenderPostCode));
senderPostalCodeElement.sendKeys("02791");

Complex pages with lots of executing JavaScript can be a pain. I use routines that that I have written to wait for angularJs to complete executing, wait for a loading spinner to complete, and finally for page readyState to equal complete:

waitForAngularToLoad(webDriver, 40);
wait_element.until((WebDriver dr1) -> (webDriver.findElement(mySpinner).getAttribute("class").contains("ng-hide")));
waitForBrowserReadystateComplete(webDriver);

These have to be tweaked for the environment that you have to operate in. Waiting for jQuery to complete is different than waiting for AngularJs. But what I gave you should get you going. Let me know how it turns out.

EDIT

I realize that telling you about my routines that I use to wait but not sharing the code was pointless. The loading spinner depends entirely on the implementation. There is no one way that is guaranteed to work everywhere but I gave you the general form which is common for AngularJs implementations.

Here are the others:

public void waitForBrowserReadystateComplete(WebDriver webDriver) {
    for (int a=0; a<20; a++) {
        JavascriptExecutor javascriptExecutor = (JavascriptExecutor) webDriver;
        if (javascriptExecutor.executeScript("return document.readyState")
                .toString().equals("complete")) {
            break;
        }
        sleepResponsibly(500);
    }
}

public void sleepResponsibly(int timeMillisecond){
    try{
        Thread.sleep(timeMillisecond);
    } catch (InterruptedException ex) {
        Thread.currentThread().interrupt(); 
        throw new RuntimeException(ex);
    }
}

public boolean waitForAngularToLoad(WebDriver driver, int timeout) {
    driver.manage().timeouts().setScriptTimeout(timeout, TimeUnit.SECONDS);
    WebDriverWait wait = new WebDriverWait(driver, timeout, 500L);
    return wait.until(angularHasFinishedProcessing());
}


public static ExpectedCondition<Boolean> angularHasFinishedProcessing() {
    return new ExpectedCondition<Boolean>() {
        @Override
        public Boolean apply(WebDriver driver) {
            String hasAngularFinishedScript = "var callback = arguments[arguments.length - 1];\n" +
                    "var el = document.querySelector('html');\n" +
                    "if (!window.angular) {\n" +
                    "    callback('false')\n" +
                    "}\n" +
                    "if (angular.getTestability) {\n" +
                    "    angular.getTestability(el).whenStable(function(){callback('true')});\n" +
                    "} else {\n" +
                    "    if (!angular.element(el).injector()) {\n" +
                    "        callback('false')\n" +
                    "    }\n" +
                    "    var browser = angular.element(el).injector().get('$browser');\n" +
                    "    browser.notifyWhenNoOutstandingRequests(function(){callback('true')});\n" +
                    "}";

            JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
            String isProcessingFinished = javascriptExecutor.executeAsyncScript(hasAngularFinishedScript).toString();

            return Boolean.valueOf(isProcessingFinished);
        }
    };
}

Remember, the angular ones only work if your System Under Test is built using AngularJs.

EDIT 2 Finding elements

I use the google chrome browser to "find" elements. Open your web page under chrome. Right-click on the displayed element. Select Inspect -> Copy -> Copy Selector | Copy Xpath. You can do this under Firefox as well. Chrome is just force of habit.

EDIT3

jQuery

public boolean waitForJquery(WebDriver driver, int timeout) {
    return waitFor(driver, "return jQuery.active;", "0", timeout);
}

public boolean waitFor(WebDriver driver, final String javascriptString, final String targetString, int timeout) {
  WebDriverWait wait = new WebDriverWait(driver, timeout, 500L);

  /*
   * If you are curious about what follows see:
\  *    http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/ExpectedCondition.html
   * 
   * We are creating an anonymous class that inherits from ExpectedCondition and then implements interface
   * method apply(...)
   */
   ExpectedCondition<Boolean> isLoaded = new ExpectedCondition<Boolean>() {

      public Boolean apply(WebDriver driver) {
        String jsReturnedValue = "";

        try {
            jsReturnedValue = String.valueOf(((JavascriptExecutor)driver).executeScript(javascriptString));
            return (jsReturnedValue.equals(targetString));
        } catch (Exception e) {
          log.info("Looking for: " + javascriptString + ", e.message: " + e.getMessage());
          return true;  // If Javascript not found then don't wait for it
        }
      }
    }; // Terminates statement started by ExpectedCondition<Boolean> isLoaded = ...

  return wait.until(isLoaded);
}

And just to round it out, Ajax

public boolean waitForPrototypeAjax(WebDriver driver, int timeout) {
    return waitFor(driver, "return Ajax.activeRequestCount;", "0", timeout);
}    

Upvotes: 1

Related Questions