Thursday, July 21, 2016

A combination of SoapUI, Selenium WebDriver, PhantomJS and Groovy!

      Our company has a monitoring system for most of sensitive web services and websites, including local and intranet sites. Most of this monitoring is being done in few Linux centos boxes that execute SoapUI tool using NRPE-Nagios and return the final results into a dashboard.

Writing SoapUI projects and scripts for web services or even web GUIs with 1-2 pages are not hard, even in our case, that most of the page elements require extensive authentication process and passing security tokens in various ways. However, the job gets painful when a full user scenario should be created as a monitoring script. 

Lets give you an example: If the usecase is to open a login page, input the credentials and ensure all elements in the main page exist and are valid, it is possible to be done using SoapUI http methods by following network activity sequences. This activities can be sniffed using any browser "developer" tool, or SoapUI recorder itself.
Now, if the use case is more complicated, like filling up  a form after login, submit it, check the next page, submit the second form, wait for an email to come and reply it for confirmation, then ensure the subscription is finished successfully, that would be no easy way to do it using SoapUI steps and simple groovy coding.

The solution here is using a WebDriver in a Headless browser such as PhantomJS.

I managed to make it work after 2 days, and here are the lessons I learnt:

1- After unzipping the phantomjs tar file, make sure the /bin/phantomjs binary file is executable for all groups.
2-Do a "ldd phantomjs" and ensure all libraries are installed. Most probably you'll need to update your GLIBC and GLIBCXX (via libstdc++).
3- Make sure your phantomjs works. to do that create a file like loadepage.js :

var page = require('webpage').create();'', function(status) {
  console.log("Status: " + status);
  if(status === "success") {

4- Then execute it like this "./phantomjs loadpage.js" . If you received a failure and you are sure that there is no network restriction to your destination, try this "./phantomjs --ignore-ssl-errors=true loadpage.js"

5- If your machine has jre 1.6 , then you have to use older Selenium jars (I recommend selenium-java-2.45.0 because it has most recent phantomservice jar)

6- Here is how I opened my groovy script, every piece of this code is vital and has its good reason:

import org.openqa.selenium.*
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.interactions.Actions
import org.openqa.selenium.remote.DesiredCapabilities
import java.util.concurrent.TimeUnit
import java.util.Random
import java.util.logging.Level;
import java.util.logging.Logger;

def baseurl = context.expand( '${#TestCase#baseurl}' )
def username = context.expand( '${#TestCase#username}' )
def password = context.expand( '${#TestCase#password}' )
def outfolder = context.expand( '${#TestCase#outfolder}' )
def phantomfile = context.expand( '${#TestCase#phantomdriver}' )

dCaps = new DesiredCapabilities();
 dCaps.setCapability("elementScrollBehavior", true);
 dCaps.setCapability("", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36");
 ArrayList<String> cliArgsCap = new ArrayList<String>();
 dCaps.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cliArgsCap);
def WebDriver driver = new PhantomJSDriver(dCaps)
Dimension d = new Dimension(1280,1024);

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

7- Now go ahead and write your code as you usually do. Java and groovy are very similar when it comes to WebDriver. Just mae sure you use a bunch of try{..}catch{..}

8- Don't forget to log,assert, fail, and quit properly when you got to the catch{} part. The proper way would be in following order:

  1. logs
  2. quit the driver
  3. fail the test case
  4. assert

     log.error (failure_text_message)
      assert "XX Page Elements Not found, please chaeck the logs"==failure_text_message