Monday, 13 August 2018

What to do to make sure HTML Table is loaded completely if implicit and explicit wait are not working.

These days I was working on a project, to implement the delete function of a listing. Such as below:
Actually,  every time deleted the item and also clicked the next page, the table will reload again. every time the table load, the page will send the request to the server for the data. The difficulty is that the XPath of HTML Table is same and I can not use Wait to check if the table is loaded. Also, Thread. Sleep is not a good choice for test automation because it will make the testing slow down.

After I check the network of Chrome and I fond that once the table loaded, the response code is 200 and the request URL contains "getMultipleServiceListing", So I use another way to guarantee a load of table---Lightbody: BrowserMobProxy.

System.setProperty( "webdriver.chrome.driver", ConfigReader.getChromePath() );//****************************proxy = new BrowserMobProxyServer();proxy.start();// get the Selenium proxy objectseleniumProxy = ClientUtil.createSeleniumProxy( proxy );// configure it as a desired capabilitycapabilities = new DesiredCapabilities();capabilities.setCapability( CapabilityType.PROXY, seleniumProxy );// start the browser updriver = new ChromeDriver( capabilities );// enable more detailed HAR capture, if desired (see CaptureType for the complete list)proxy.enableHarCaptureTypes( CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT );


//initial Harpublic static void MonitorResponseStart() throws InterruptedException {    //Initialize Har    proxy.newHar( BrowserFactory.driver.getCurrentUrl() );    har = proxy.getHar();    //Must use the sleep to wait for Har to initialize, or there may be error.    Thread.sleep( 500 );}
//Check request url and response statusprivate static boolean CheckStatus(Har har,String subUrl,int statuCode) {    //get entriesList    List<HarEntry> entriesList = har.getLog().getEntries();    //loop to check    for (HarEntry harEntry : entriesList) {        if ((harEntry.getRequest().getUrl().contains( subUrl ))                &&                (harEntry.getResponse().getStatus() == statuCode)) {            BaseClass.testLog.log( Status.INFO, "Table reloaded done ! " );            return true;        }    }    return false;}
//It is used to make sure that the table are loaded completelypublic static void MMonitorResponseEnd(String subUrl,int statuCode) throws IOException, InterruptedException {
    //if check status fail, wait and keep checking.    while (!CheckStatus( har,subUrl,statuCode)) {        Thread.sleep( 200 );    }    //write har to file, this step can be delete, just used for debugging....    har.writeTo( new File( "har.json" ) );}

Tuesday, 7 August 2018

Selenium Webdriver wait for JavaScript JQuery and Angular



Hi all, during the last two weeks I was dealing with the best solution to wait for both JQueryAngular and JavaScript (JS) in my Selenium (Java) test codes and finally, I found a significantly stable solution without silly sleep() statements to share with you. In this period, I searched maybe more than 20 articles and sites to find the best and unique solutions and in this article, I combined all solutions in only one method. This is “WaitJQueryAngular()“. When you need to wait for an asynchronous wait, you can use below methods as your project type.
I know that you wonder to know what it does? First, it waits JQuery is Ready? and then waits Angular is Ready? and if JQuery or Angular is ready? Then it checks JS is ready? If all of them are ready then the code will continue to run next statements. Also, I added a control that checks JQuery and Angular is defined or not. It is important that if the any of them is not defined in the page, code skips asynchronous wait statements. If this control does not exist, we will get JS error.
You can just add below methods in your code and use “WaitJQueryAngular()” for an asynchronous wait in your test automation codes.
  • Add below JSWaiter utility class into your project.
  • Then, send WebDriver object to JSWaiter Class in a convenient place in your project by adding this line:“JSWaiter.setDriver(driver);”
  • Finally, you can use any of the methods below in your test code:
    • JSWaiter.waitJQueryAngular(); –> Both waits JQuery, Angular, JS
    • waitUntilAngularReady(); –> It only waits Angular and JS
    • waitUntilJQueryReady(); –> It only waits JQuery and JS
NoteI added waitUntilJSReady(); call both in waitUntilJQueryReady() and waitUntilAngularReady() methods. In this way, if your test site only comprises of Angular or JQuery, you can just use the relevant method to wait asynchronous operations.
Note: You should combine this asynchronous wait solution with the synchronous explicit wait statements to get highest stability in your tests. If you face with a problem, please let me know.
JQuery, Angular, and JavaScript Waiter
JSWaiter
public class JSWaiter {
    private static WebDriver jsWaitDriver;
    private static WebDriverWait jsWait;
    private static JavascriptExecutor jsExec;
    //Get the driver
    public static void setDriver (WebDriver driver) {
        jsWaitDriver = driver;
        jsWait = new WebDriverWait(jsWaitDriver, 10);
        jsExec = (JavascriptExecutor) jsWaitDriver;
    }
    //Wait for JQuery Load
    public static void waitForJQueryLoad() {
        //Wait for jQuery to load
        ExpectedCondition<Boolean> jQueryLoad = driver -> ((Long) ((JavascriptExecutor) jsWaitDriver)
                .executeScript("return jQuery.active") == 0);
        //Get JQuery is Ready
        boolean jqueryReady = (Boolean) jsExec.executeScript("return jQuery.active==0");
        //Wait JQuery until it is Ready!
        if(!jqueryReady) {
            System.out.println("JQuery is NOT Ready!");
            //Wait for jQuery to load
            jsWait.until(jQueryLoad);
        } else {
            System.out.println("JQuery is Ready!");
        }
    }

    //Wait for Angular Load
    public static void waitForAngularLoad() {
        WebDriverWait wait = new WebDriverWait(jsWaitDriver,15);
        JavascriptExecutor jsExec = (JavascriptExecutor) jsWaitDriver;
        String angularReadyScript = "return angular.element(document).injector().get('$http').pendingRequests.length === 0";
        //Wait for ANGULAR to load
        ExpectedCondition<Boolean> angularLoad = driver -> Boolean.valueOf(((JavascriptExecutor) driver)
                .executeScript(angularReadyScript).toString());
        //Get Angular is Ready
        boolean angularReady = Boolean.valueOf(jsExec.executeScript(angularReadyScript).toString());
        //Wait ANGULAR until it is Ready!
        if(!angularReady) {
            System.out.println("ANGULAR is NOT Ready!");
            //Wait for Angular to load
            wait.until(angularLoad);
        } else {
            System.out.println("ANGULAR is Ready!");
        }
    }
    //Wait Until JS Ready
    public static void waitUntilJSReady() {
        WebDriverWait wait = new WebDriverWait(jsWaitDriver,15);
        JavascriptExecutor jsExec = (JavascriptExecutor) jsWaitDriver;
        //Wait for Javascript to load
        ExpectedCondition<Boolean> jsLoad = driver -> ((JavascriptExecutor) jsWaitDriver)
                .executeScript("return document.readyState").toString().equals("complete");
        //Get JS is Ready
        boolean jsReady =  (Boolean) jsExec.executeScript("return document.readyState").toString().equals("complete");
        //Wait Javascript until it is Ready!
        if(!jsReady) {
            System.out.println("JS in NOT Ready!");
            //Wait for Javascript to load
            wait.until(jsLoad);
        } else {
            System.out.println("JS is Ready!");
        }
    }
    //Wait Until JQuery and JS Ready
    public static void waitUntilJQueryReady() {
        JavascriptExecutor jsExec = (JavascriptExecutor) jsWaitDriver;
        //First check that JQuery is defined on the page. If it is, then wait AJAX
        Boolean jQueryDefined = (Boolean) jsExec.executeScript("return typeof jQuery != 'undefined'");
        if (jQueryDefined == true) {
            //Pre Wait for stability (Optional)
            sleep(20);
            //Wait JQuery Load
            waitForJQueryLoad();
            //Wait JS Load
            waitUntilJSReady();
            //Post Wait for stability (Optional)
            sleep(20);
        }  else {
            System.out.println("jQuery is not defined on this site!");
        }
    }
    //Wait Until Angular and JS Ready
    public static void waitUntilAngularReady() {
        JavascriptExecutor jsExec = (JavascriptExecutor) jsWaitDriver;
        //First check that ANGULAR is defined on the page. If it is, then wait ANGULAR
        Boolean angularUnDefined = (Boolean) jsExec.executeScript("return window.angular === undefined");
        if (!angularUnDefined) {
            Boolean angularInjectorUnDefined = (Boolean) jsExec.executeScript("return angular.element(document).injector() === undefined");
            if(!angularInjectorUnDefined) {
                //Pre Wait for stability (Optional)
                sleep(20);
                //Wait Angular Load
                waitForAngularLoad();
                //Wait JS Load
                waitUntilJSReady();
                //Post Wait for stability (Optional)
                sleep(20);
            } else {
                System.out.println("Angular injector is not defined on this site!");
            }
        }  else {
            System.out.println("Angular is not defined on this site!");
        }
    }
    //Wait Until JQuery Angular and JS is ready
    public static void waitJQueryAngular() {
        waitUntilJQueryReady();
        waitUntilAngularReady();
    }
    public static void sleep (Integer seconds) {
        long secondsLong = (long) seconds;
        try {
            Thread.sleep(secondsLong);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Notes:
– For java.net.SocketTimeoutException you can add below line before get() method. It will also wait for Page Load.

driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);

Thanks. Morgan

What to do to make sure HTML Table is loaded completely if implicit and explicit wait are not working.

These days I was working on a project, to implement the delete function of a listing. Such as below: Actually,  every time deleted the it...