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

Tuesday, 24 July 2018

Advanced SpecFlow: Using Hooks to Extend Test Execution Workflow.

What are Hooks?

Definition


The hooks (event bindings) can be used to perform additional automation logic on specific events, such as before executing a scenario. Hooks are global but can be restricted to run only for features or scenarios with a particular tag (see below). The execution order of hooks for the same event is undefined.

Create SpecFlow Hooks' File

1. Add the new item to project
Add New Item Project
2. Select the SpecFlow's hooks' template
specflow hooks files template
The following class will be automatically generated.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
namespace ExtendTestExecutionWorkflowUsingHooks
{
[Binding]
public sealed class Hooks
{
// For additional details on SpecFlow hooks see http://go.specflow.org/doc-hooks
[BeforeScenario]
public void BeforeScenario()
{
//TODO: implement logic that has to run before executing each scenario
}
[AfterScenario]
public void AfterScenario()
{
//TODO: implement logic that has to run after executing each scenario
}
}
}

Types of SpecFlow Hooks

SpecFlow comes with some predefined hooks that are executed after some events are fired during the tests’ execution. To make an analogy, think about TestInitialize and TestCleanup from MSTest framework.
The available hooks and their running order are:
[BeforeTestRun]
[BeforeFeature]
[BeforeScenario]
[BeforeScenarioBlock]
[BeforeStep]
[AfterStep]
[AfterScenarioBlock]
[AfterScenario]
[AfterFeature]
[AfterTestRun]
Attribute
Description
Is Static
MSTest Analoge
[BeforeTestRun]

[AfterTestRun]
Run before/after the entire test run
Yes
AssemblyInitialize and AssemblyCleanup
[BeforeFeature]

[AfterFeature]
Run before/after executing each feature
Yes
ClassInitialize and ClassCleanup
[BeforeScenario] or [Before]

[AfterScenario] or [After]
Run before/after executing each scenario
No
TestInitialize and TestCleanup
[BeforeScenarioBlock]

[AfterScenarioBlock]
Run before/after executing each scenario block (e.g. between the "givens" and the "whens")
No
-
[BeforeStep]

[AfterStep]
Run before/after executing each scenario step
No
-

SpecFlow Hooks in Tests

I will leverage on the test example from the first article from the series where we built a test for converting Kilowatt-Hours to Newton Meters. One of the drawbacks of the first implementation was that we needed to start the browser in the SpecFlow background section and close it in a separate Then step.

Previous Feature File

Feature: Convert Metrics for Nuclear Science
To do my nuclear-related job
As a Nuclear Engineer
I want to be able to convert different metrics.
Background:
Given web browser is opened
@testingFramework
Scenario: Successfully Convert Kilowatt-hours to Newton-meters
When I navigate to Metric Conversions
And navigate to Energy and power section
And navigate to Kilowatt-hours
And choose conversions to Newton-meters
And type 30 kWh
Then assert that 1.080000e+8 Nm are displayed as the answer
Then close the web browser
As point we need to start the browser in the background section and close it in Then step.

Bindings Class without Hooks

[Binding]
public class ConvertMetricsForNuclearScienceSteps
{
private HomePage homePage;
private KilowattHoursPage kilowattHoursPage;
[Given(@"web browser is opened")]
public void GivenWebBrowserIsOpened()
{
Driver.StartBrowser(BrowserTypes.Chrome);
}
[Then(@"close web browser")]
public void ThenCloseWebBrowser()
{
Driver.StopBrowser();
}
[When(@"I navigate to Metric Conversions")]
public void WhenINavigateToMetricConversions_()
{
this.homePage = new HomePage(Driver.Browser);
this.homePage.Open();
}
[When(@"navigate to Energy and power section")]
public void WhenNavigateToEnergyAndPowerSection()
{
this.homePage.EnergyAndPowerAnchor.Click();
}
[When(@"navigate to Kilowatt-hours")]
public void WhenNavigateToKilowatt_Hours()
{
this.homePage.KilowattHours.Click();
}
[When(@"choose conversions to Newton-meters")]
public void WhenChooseConversionsToNewton_Meters()
{
this.kilowattHoursPage = new KilowattHoursPage(Driver.Browser);
this.kilowattHoursPage.KilowatHoursToNewtonMetersAnchor.Click();
}
[When(@"type (.*) kWh")]
public void WhenTypeKWh(double kWh)
{
this.kilowattHoursPage.ConvertKilowattHoursToNewtonMeters(kWh);
}
[Then(@"assert that (.*) Nm are displayed as answer")]
public void ThenAssertThatENmAreDisplayedAsAnswer(string expectedNewtonMeters)
{
this.kilowattHoursPage.AssertFahrenheit(expectedNewtonMeters);
}
}
Here we have binding methods for starting and closing the browser. Also, every page is created using the new keyword.

Test Run Reuse Browser- Hooks Class

[Binding]
public sealed class TestRunSingleBrowserHooks
{
[BeforeTestRun]
public static void RegisterPages()
{
Driver.StartBrowser(BrowserTypes.Chrome);
UnityContainerFactory.GetContainer().RegisterType<HomePage>(new ContainerControlledLifetimeManager());
UnityContainerFactory.GetContainer().RegisterType<KilowattHoursPage>(new ContainerControlledLifetimeManager());
UnityContainerFactory.GetContainer().RegisterInstance<IWebDriver>(Driver.Browser);
}
// Reuse browser for the whole run.
[AfterTestRun]
public static void AfterTestRun()
{
Driver.StopBrowser();
}
}
The hooks need to be placed inside a class marked with the Binding attribute. Here we register all pages in the Unity IoC container and start the browser before each test run. This means that the browser will be reused accross all tests (scenarios). On AfterTestRun we close the browser.

Test Scenario Reuse Browser- Hooks Class

[Binding]
public sealed class TestScenarioBrowserHooks
{
[BeforeTestRun]
public static void RegisterPages()
{
UnityContainerFactory.GetContainer().RegisterType<HomePage>(new ContainerControlledLifetimeManager());
UnityContainerFactory.GetContainer().RegisterType<KilowattHoursPage>(new ContainerControlledLifetimeManager());
}
[BeforeScenario
public static void StartBrowser()
{
Driver.StartBrowser(BrowserTypes.Chrome);
UnityContainerFactory.GetContainer().RegisterInstance<IWebDriver>(Driver.Browser);
}
[AfterScenario]
public static void CloseBrowser()
{
Driver.StopBrowser();
}
}
If we place the code about the starting browser under BeforeScenario method, the browser will be started for each test (scenario). Also, we need to close it in the AfterScenario method.

Feature File with Hooks

@firefox
Feature: Convert Metrics for Nuclear Science
To do my nuclear-related job
As a Nuclear Engineer
I want to be able to convert different metrics.
@hooksExample @firefox
Scenario: Successfully Convert Kilowatt-hours to Newton-meters
When I navigate to Metric Conversions
And navigate to Energy and power section
And navigate to Kilowatt-hours
And choose conversions to Newton-meters
And type 30 kWh
Then assert that 1.080000e+8 Nm are displayed as the answer
The new feature file doesn't contain any code dealing with browsers.

Bindings Class with Hooks

The class that contains steps' bindings now doesn't hold any methods that are dealing with browsers either. In the constructor, we get the pages from the Unity container instead of creating them each time with the new keyword.
[Binding]
public class ConvertMetricsForNuclearScienceSteps
{
private readonly HomePage homePage;
private readonly KilowattHoursPage kilowattHoursPage;
public ConvertMetricsForNuclearScienceSteps()
{
this.homePage =
UnityContainerFactory.GetContainer().Resolve<HomePage>();
this.kilowattHoursPage =
UnityContainerFactory.GetContainer().Resolve<KilowattHoursPage>();
}
////[Given(@"web browser is opened")]
////public void GivenWebBrowserIsOpened()
////{
//// Driver.StartBrowser(BrowserTypes.Chrome);
////}
////[Then(@"close web browser")]
////public void ThenCloseWebBrowser()
////{
//// Driver.StopBrowser();
////}
[When(@"I navigate to Metric Conversions")]
public void WhenINavigateToMetricConversions_()
{
////this.homePage = new HomePage(Driver.Browser);
////this.homePage = UnityContainerFactory.GetContainer().Resolve<HomePage>();
this.homePage.Open();
}
[When(@"navigate to Energy and power section")]
public void WhenNavigateToEnergyAndPowerSection()
{
this.homePage.EnergyAndPowerAnchor.Click();
}
[When(@"navigate to Kilowatt-hours")]
public void WhenNavigateToKilowatt_Hours()
{
this.homePage.KilowattHours.Click();
}
[When(@"choose conversions to Newton-meters")]
public void WhenChooseConversionsToNewton_Meters()
{
////this.kilowattHoursPage = new KilowattHoursPage(Driver.Browser);
this.kilowattHoursPage.KilowatHoursToNewtonMetersAnchor.Click();
}
[When(@"type (.*) kWh")]
public void WhenTypeKWh(double kWh)
{
this.kilowattHoursPage.ConvertKilowattHoursToNewtonMeters(kWh);
}
[Then(@"assert that (.*) Nm are displayed as answer")]
public void ThenAssertThatENmAreDisplayedAsAnswer(string expectedNewtonMeters)
{
this.kilowattHoursPage.AssertFahrenheit(expectedNewtonMeters);
}
}

Configure SpecFlow Hooks' Execution Order

Another cool feature of the SpecFlow hooks is that you can specific execution order if multiple hooks are specified of the same type. By default, the execution order is unspecified, and they can be executed in any order. To ensure that they are performed in a specified order, the hook attribute allows an arbitrary order to be configured. The lowest order values run before the higher order methods. After some refactoring, our hooks’ file will look like this.
[Binding]
public sealed class Hooks
{
// Reuse browser for the whole run.
[BeforeTestRun(Order = 1)]
public static void RegisterPages()
{
System.Console.WriteLine("Execute BeforeTestRun- RegisterPages");
Driver.StartBrowser(BrowserTypes.Chrome);
UnityContainerFactory.GetContainer().RegisterType<HomePage>(new ContainerControlledLifetimeManager());
UnityContainerFactory.GetContainer().RegisterType<KilowattHoursPage>(new ContainerControlledLifetimeManager());
}
[BeforeTestRun(Order = 2)]
public static void RegisterDriver()
{
System.Console.WriteLine("Execute BeforeTestRun- RegisterDriver");
UnityContainerFactory.GetContainer().RegisterInstance<IWebDriver>(Driver.Browser);
}
// Reuse browser for the whole run.
[AfterTestRun]
public static void AfterTestRun()
{
System.Console.WriteLine("Execute AfterTestRun- StopBrowser");
Driver.StopBrowser();
}
[BeforeFeature]
public static void BeforeFeature()
{
}
[AfterFeature]
public static void AfterFeature()
{
}
[BeforeScenario(Order = 2)]
public static void StartBrowser()
{
// New Browser Instance for each test.
////Driver.StartBrowser(BrowserTypes.Chrome);
System.Console.WriteLine("Execute BeforeScenario- StartBrowser");
}
[BeforeScenario(Order = 1)]
public static void LoginUser()
{
System.Console.WriteLine("Execute BeforeScenario- LoginUser");
// Login to your site.
}
[AfterScenario(Order = 2)]
public static void CloseBrowser()
{
System.Console.WriteLine("Execute AfterScenario- CloseBrowser");
// New Browser Instance for each test.
////Driver.StopBrowser();
}
[AfterScenario(Order = 1)]
public static void LogoutUser()
{
System.Console.WriteLine("Execute AfterScenario- LogoutUser");
// Logout the user
}
[BeforeStep]
public void BeforeStep()
{
System.Console.WriteLine("BeforeStep- Start Timer");
}
[AfterStep]
public static void AfterStep()
{
System.Console.WriteLine("BeforeStep- Log something in DB.");
}
}

Hooks' Tag Scoping

We can scope based on tags. The tags are added to each test scenario starting with the ‘@’ symbol. Most of the hooks support tag scoping, meaning that they are executed only if the feature or the scenario has at least one of the tags specified in the filter.

Scope Attribute

You can use the new Scope attribute to specify the tag.
[AfterScenario(Order = 1)]
[Scope(Tag = "hooksExample")]
public static void LogoutUser()
{
System.Console.WriteLine("Execute AfterScenario- LogoutUser");
// Logout the user
}

Step Attribute

Also, you can specify the tag scoping in the steps' attribute constructor.
[AfterScenario(Order = 1)]
[AfterScenario("hooksExample")]
public static void LogoutUser()
{
System.Console.WriteLine("Execute AfterScenario- LogoutUser");
// Logout the user
}

Advanced Tag Scoping

If you use the ScenarioContext class, you can perform even more advanced scoping. In the below example we throw an exception if the browser tag is not specified.
[BeforeScenario(Order = 2)]
public static void StartBrowser()
{
// Advanced tag filtering
if (!ScenarioContext.Current.ScenarioInfo.Tags.Contains("firefox"))
{
throw new ArgumentException("The browser is not specfied");
}
// New Browser Instance for each test.
////Driver.StartBrowser(BrowserTypes.Chrome);
System.Console.WriteLine("Execute BeforeScenario- StartBrowser");
}

Hooks' Methods Execution Order

[Binding]
public sealed class OrderHooks
{
// Reuse browser for the whole run.
[BeforeTestRun(Order = 1)]
public static void RegisterPages()
{
System.Console.WriteLine("BeforeTestRun");
Driver.StartBrowser(BrowserTypes.Chrome);
UnityContainerFactory.GetContainer().RegisterType<HomePage>(new ContainerControlledLifetimeManager());
UnityContainerFactory.GetContainer().RegisterType<KilowattHoursPage>(new ContainerControlledLifetimeManager());
}
[BeforeTestRun(Order = 2)]
public static void RegisterDriver()
{
System.Console.WriteLine("Execute BeforeTestRun- RegisterDriver");
UnityContainerFactory.GetContainer().RegisterInstance<IWebDriver>(Driver.Browser);
}
// Reuse browser for the whole run.
[AfterTestRun]
public static void AfterTestRun()
{
System.Console.WriteLine("AfterTestRun");
Driver.StopBrowser();
}
[BeforeFeature]
public static void BeforeFeature()
{
System.Console.WriteLine("BeforeFeature");
}
[AfterFeature]
public static void AfterFeature()
{
System.Console.WriteLine("AfterFeature");
}
[BeforeScenario]
public void LoginUser()
{
System.Console.WriteLine("BeforeScenario");
}
[AfterScenario(Order = 1)]
public void AfterScenario()
{
System.Console.WriteLine("AfterScenario");
}
[BeforeStep]
public void BeforeStep()
{
System.Console.WriteLine("BeforeStep");
}
[AfterStep]
public void AfterStep()
{
System.Console.WriteLine("AfterStep");
}
}
SpecFlow Hooks Methods Execution Order
Actually, the after the test is executed, I am not sure why it was not printed in the output. Anyway, it is executed last.

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...