Chuan Chuan Law

DevOps | Software Automation | Continuous Integration

Category: Selenium Automation (page 1 of 3)

Getting Selenium Test Running On Gradle Framework

Gradle + Selenium is probably not a popular framework yet when I was developing it as I find it difficult to look for relevant resources online. There were bits and pieces of information here and there which I then glue then up together.

My build.gradle contains the following implementations:

(1) Add cucumberRuntime under Configurations

configurations {
cucumberRuntime {
extendsFrom testRuntime
}

}

(2) Source sets

sourceSets{
test{
groovy{
srcDirs ‘src/test’
}
}

}

(3) Compile test output

task testJar(type: Jar){
from(sourceSets.test.output){
include ‘**/*.class’
exclude ‘**/*StepDef*.class’
}

}

(4) Glue everything together

task cucumber() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {
            main = "cucumber.api.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['-f', 'json:target/cucumber-report.json','--plugin','pretty', '--glue', 'src/test/groovy/au/com/story/steps', 'src/test/groovy/au/com/story/features']
        }
    }
}

Building A Selenium Web Driver Test Framework From Scratch

Selenium UI test is the most used high level test these days for web applications. Regardless of which language you use, the framework is pretty much the same. I would like to share with everybody the Selenium web driver testing framework I worked on recently using Selenium in Java on a Groovy Gradle framework.

I will provide the step-by-step guideline on how to create a skeleton framework from scratch:

  1. Import libraries you need

dependencies {

    compile 'org.codehaus.groovy:groovy-all:2.4.3'
    testCompile 'junit:junit:4.12'
    testCompile 'org.seleniumhq.selenium:selenium-java:2.46.0'
    testCompile 'info.cukes:cucumber-groovy:1.2.3'
}

You will need the Selenium Java from Maven repository, Cucumber in Groovy as a BDD layer (although this is not necessary), JUnit to assert test values.

2. Create a webdriver class

import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.chrome.ChromeDriver

public class CsWebDriver {

 private static WebDriver _driver

 public static WebDriver get(String browserType)
 {
 if (browserType.equals("chrome"))
 {
 System.setProperty("webdriver.chrome.driver","srcmainresourceschromedriver.exe")
 ChromeOptions options = new ChromeOptions();
 options.setBinary("c:Chrome.V41GoogleChromePortable.exe");

 _driver=new ChromeDriver(options)

 }

 return _driver

 }

This is where we declare a new web driver object from the library and initialize it with a copy of driver downloaded from  ChromeDriver. You could create or extend all browser related functionalities in this class, such as Open a URL, Quit, Wait, Move To Click, etc.

For example: Move to an element to click using Action class

public static WebElement WaitTillElementExist(WebElement ele, int seconds)
{

   WebDriverWait wait = new WebDriverWait(_driver,seconds)
   return wait.until(ExpectedConditions.elementToBeClickable(ele))
}

3. Create Page Factory to host Page Objects

public class PageFactory {

    private static WebDriver _driver

    public static LoginPage LoginPage

   public static void InitialisePages(WebDriver driver)
   {
     _driver=driver
     LoginPage= new LoginPage(driver)
   }
   public static void ResetPages()
   {
     LoginPage=null
   }

 public static GetDriver() 
 { return _driver 
 }

Page Factory above is where we declare, initialize, and reset our Page Objects. An instance of web driver will be passed into each Page Object.

import org.openqa.selenium.support.FindBy 
import org.openqa.selenium.support.How

@InheritConstructors
class LoginPage extends BasePage {

    @FindBy(how=How.ID, using="Username")
    private WebElement userName

    @FindBy(how=How.ID, using="Password")
    private WebElement password
    @FindBy(how=How.CSS, using="button[class='btn']")
    private WebElement loginBtn

    public void Login(String username, String pwd)
    {
      userName.sendKeys(username)
      password.sendKeys(pwd)
      loginBtn.click()
    }
}

Every webpage that we are testing is treated as an object. By importing the Selenium library FindBy and How we can select the element that we want using ID, CSS, XPATH, etc. The page object will also contain functions specific to the page, for eg. Login function. As we can see, the page object is extended from the BasePage. A BasePage looks like this:

import org.openqa.selenium.support.PageFactory

public class BasePage {

    public WebDriver driver

    public BasePage(WebDriver webdriver)
    {
        this.driver=webdriver
        PageFactory.initElements(webdriver,this)

    }
}

We use the Selenium PageFactory library to easily implement this.

    4. Binding everything together

So we now have the web driver class, page factory, and page objects, how do we glue this all together into an executable test? To make test easier to understand and read, we usually like to use a BDD tool to describe a test Scenario. I will not go into depth on the BDD tool in this post, but I would like to touch base on the Before Scenario Hook of a BDD tool that is used to glue all pieces together.

this.metaClass.mixin(cucumber.api.groovy.Hooks) this.metaClass.mixin(cucumber.api.groovy.EN) Before("@web") 
{ 
  scenario -> PageFactory.InitialisePages(WebDriver.get("chrome")) 
  WebDriver.Open(oagUrl) 
}

Before every scenario, we initialize all Page Objects with a Chrome driver and then  open the URL.

After("@web") { scenario ->

    if (scenario.isFailed()) {
        String fileName=scenario.getName()
        WebDriver.PrintPageSource()
        WebDriver.TakeScreenShot(fileName, scenario)
    }

    WebDriver.Quit()
    PageFactory.ResetPages()
}

After every scenario, we check if the scenario is failed, if so, we print out the scenario name and take a screen shot. We then quit the driver and reset all Page Objects to null.

  5. Run the test via command line

To enable the test to be run on a CI box, we have to make the test run via command line. The example below is using Gradle to run the Cucumber Groovy test:

configurations {
    cucumberRuntime {
        extendsFrom testRuntime
    }
}
sourceSets{
    test{
        groovy{
            srcDirs 'src/test'
        }
    }
}
task cucumber() {
    dependsOn assemble, compileTestJava
    doLast {
        javaexec {
            main = "cucumber.api.cli.Main"
            classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
            args = ['-f', 'json:target/cucumber-report.json','--plugin','pretty', '--glue', 'src/test/groovy/au/com/test/story/steps', 'src/test/groovy/au/com/test/story/features']
        }
    }
}

We created a Gradle task called “cucumber” and execute the test using “javaexec”.  We need to define in the Source Sets the directory of the test. In “args –glue”, we define where the Feature  files and Steps Definitions are.

  6. Finally, run your test!

Using JavaScript To Manipulate The Web Page

There are circumstances when we need to manipulate the web page in order to test some scenarios:
 
Below are some examples in C#:
 

Use JavaScript to Change Value

 
Changing value of an input field with ID input-confirm to iambot to simulate SpamBot’s action:
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
js.ExecuteScript(“$(‘#input-confirm’).val(‘iamabot’)”);
 
 

Use JavaScript to Disable Client Side Validation 

 
 
Remove JavaScript validation classes from submit button and form before clicking on button. This test case is to ensure that we do have server side validation in place.
 

var js = driver as IJavaScriptExecutor;

js.ExecuteScript(“$(‘button.primary-cta.button.fn_validate_submit’).removeClass(‘button.primary-cta.button.fn_validate_submit disabled’)”);

js.ExecuteScript(“$(‘form’).removeClass(‘form fn_validate fn_validate_container’)”);

Submit.Click();

Chrome Driver Bug – Disable Developer Mode Extensions Pop Up

There is a bug in the Chrome Driver where you will get a Disable Developer Mode Extensions pop up occasionally in your test.
I still cannot work out why we started to get this problem as we have not upgraded the version of the Chrome driver.
The even more odd thing is that I found out that the pop up appears on bigger pages with lots of data and by cleaning up the data is able to temporarily get rid of the pop up.
However, the proper solution is to have the following line in your code:

options.AddArguments(“chrome.switches”, “–disable-extensions”)

So, the final code looks like this:
    var options = new ChromeOptions();
    options.AddArguments(“chrome.switches”, “–disable-extensions”);
    var driver = new ChromeDriver(_CHROME_DRIVER_PATH, options);
However, you might get this message on the browser while you run your tests:
But don’t panic, because everything will work perfectly without the pop up message!

Selenium Webdriver: How To Deal With Pages With Complex Ajax Calls

If the web page that you testing consists of complex ajax calls, you may be facing the problem where the tests will fail occasionally due to incomplete ajax calls returned.

To deal with this problem, I have added a function in my test:

driver.WaitForAjaxLoadComplete();

And what the function does is:

 public static void WaitForAjaxLoadComplete(this IWebDriver driver   {

            IWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60.00));

            wait.Until(driver1 => (bool)(driver1 as IJavaScriptExecutor).ExecuteScript(“return jQuery.active == 0”));

        }

Basically, it tells Selenium to wait until all jQuery calls are completed before the next actions.

Selenium Webdriver: How To Deal With “WebDriverException: Element is not clickable at point (x, y). Other element would receive the click:”

Recent task of me is to make the Selenium tests reliable. Functional tests have the following drawback:

  • Update of tests are required when DOM changes
  • Selenium work differently when you use different web drivers
           Eg: A checkbox is visible when you use Firefox, but hidden in Google driver
  • Depending on how the web page is constructed, you may get inconsistent behavior with the tests.
          Eg: Element is clickable now but not when you run it again
In my previous post, I talked about the “Stale element exception” which we have to find some other creative ways to get around. Please note that there are multiple ways to get around that problem which I will share with everybody in my future post.
Today, I am going to talk about a specific problem I have when using the Google Driver –
WebDriverException: Element is not clickable at point (x, y). Other element would receive the click
 
 
The solution is:
Instead of using the usual Click method:

driver.FindElement(By.Id(“id”)).Click;

We use the Actions method:

IWenElement element=driver.FindElement(By.Id(“id”));

Actions actions = new Actions (driver);

actions.MoveToElement(element).Click().Perform();

Selenium Webdriver: How To Deal With “Element Is No Longer Attached To The DOM”

I got an inconsistent scenario where sometimes I got the error “Element Is No Longer Attached To The DOM”.

To deal with this I have added the following code while accessing the element:

 int count = 0;
            while (count < 5)
            {
                try
                {
                    IWebElement textFound = driver.FindElement(By.LinkText(text));
                    textFound.Click();
                }
                catch (StaleElementReferenceException e)
                {
                    e.ToString();
                    Console.WriteLine(“Trying to recover from stale element:” + e.Message);
                    count = count + 1;
                }
                count = count + 5;
            }

Thus, instead of failing straightaway, the test will attempt a few times to click the element, or else exception will be caught to allow the test to fail gracefully.

How To Bypass Untrusted SSL Connection II

I guess I have blogged about how to bypass Untrusted SSL Connection before by using your local computer’s FireFox with stored certificate. However, there are cases when by doing this itself is not sufficient.

Below is what you can do besides that:

1. Enter “about:config” in the address bar of your FireFox
2. Enter the following settings (https://pusso is the website I want to bypass)

3. Use the following code in your Selenium code

FirefoxProfile profile = new FirefoxProfile(@”pathtolocalfirefoxprofile”);
profile.SetPreference(“network.http.phishy-userpass-length”, 255);
profile.SetPreference(“network.automatic-ntlm-auth.trusted-uris”, “pusso”);

Uploading Files in Windows Using Selenium C#

I have encountered a situation where I need to click on a button in order to upload a file.

I test this using Selenium C# by:

1. Entering the file path into the box

driver.FindElement(By.Id(“uploadFile”)).SendKeys(“C/testFile.txt”);

2. Calling the Javascript function to simulate what happens when “Upload” button is clicked

IJavaScriptExecutor js = driver as IJavaScriptExecutor;

string script = “__doPostBack(‘uploadFileButton’,”)”;

js.ExecuteScript(script);

Selenium – How To Bypass Untrusted SSL Connection

In order to bypass the untrusted SSL connection error, you will need to:

  • Launch the browser from desktop
  • Manually adds the exception to bypass the untrusted SSL message
  • Declare the web driver to use the desktop browser’s profile instead of Selenium’s default profile
FirefoxProfile profile = new FirefoxProfile(@”C:UserschuanlAppDataRoaming MozillaFirefoxProfilesqu7su2xj.default”);
IWebDriver driver = new FirefoxDriver(profile); 
  • Once that is done, when you run Selenium, you will not get the untrusted SSL message again.
« Older posts

© 2019 Chuan Chuan Law

Theme by Anders NorenUp ↑