How to add a jGrowl wrapper to your Selenium framework.

This all started because I have a Macintosh computer at home. I always got this nagging “growl” message in the upper right hand side of the screen and when I search google for this I found the jGrowl website. Since I am not only a quality assurance software developer, I usually experiment with web development technologies to improve my understanding of how websites work, and so I did. In the process of doing this I thought it would be nice to show messages like this in my browser as a test is running. At first this was just an idea, which I handed off to Dave Haeffner, but when I started keeping videos of my Selenium tests on SauceLabs, it became clear that this kind of logging can really help when watching a recorded video that had logged messages like this.

And so a new project was born. On my GitHub account you can find a project called jquery-growl-selenium-example and henceforth are some bits about how it works.

First, I had to create an event wrapper using Selenium’s AbstractWebDriverEventListener class.

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.support.events.AbstractWebDriverEventListener;
import org.openqa.selenium.support.events.EventFiringWebDriver;

public class EventWrapper extends AbstractWebDriverEventListener {
	
	private String standardHeader = "Selenium Event";
	private JavascriptExecutor js;
	private EventFiringWebDriver drv;
	
	// its nice to keep JavaScript snippets in separate files.
    private final String JGROWL_SCRIPT = "http://cdnjs.cloudflare.com/ajax/libs/jquery-jgrowl/1.2.12/jquery.jgrowl.min.js";
    private final String JQUERY_SCRIPT = "http://code.jquery.com/jquery-1.11.1.min.js";
    private final String JGROWL_STYLE = "http://cdnjs.cloudflare.com/ajax/libs/jquery-jgrowl/1.2.12/jquery.jgrowl.min.css";
    
	public EventWrapper( EventFiringWebDriver efwd ) {
		this.drv = efwd;
		if ( js == null ) enableGrowl( drv );
	}

	public void afterNavigateTo( String url, EventFiringWebDriver driver ) {
		displayGrowl( "Navigated to URL '" + url + "'." );
	}

	public void displayGrowl( String message ) {		
		js.executeScript( "$.jGrowl('" + message + "', { header: '" + standardHeader + "' });" );		
	}
	
	public void displayGrowl( String message, long life ) {
		js.executeScript( "$.jGrowl('" + message + "', { header: '" + standardHeader + "', life: " + life + " });" );		
	}

	private void enableGrowl( EventFiringWebDriver driver ) {
		this.drv = driver;
		js = (JavascriptExecutor)drv;
		//TODO Add check for existing jQuery on page

		js.executeScript( "var jq = document.createElement('script'); jq.type = 'text/javascript'; jq.src = '" +
		JQUERY_SCRIPT + "'; document.getElementsByTagName('head')[0].appendChild(jq);" );

		js.executeScript( "$.getScript(\"" + JGROWL_SCRIPT + "\");" );

		js.executeScript( "var lnk = document.createElement('link'); lnk.rel = 'stylesheet'; lnk.href = '" +
		JGROWL_STYLE + "'; lnk.type = 'text/css'; document.getElementsByTagName('head')[0].appendChild(lnk);" );
		
		displayGrowl( "Logging with jGrowl enabled.", 2000 );	
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

Then, the actual test needs to generate an EventFiringWebDriver and register the above listener.

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.events.EventFiringWebDriver;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

/**
 * An example of loading jQuery dynamically using WebDriver.
 * Some notes here: https://gist.github.com/djangofan/7677995
 */
public class JQueryTest {
	
	private EventFiringWebDriver efwd;
	private String initialUrl;
	
	@BeforeTest
	public void setUp() {
		initialUrl = "data:text/html,<html><head></head><body><h2>Test of <i>jGrowl</i> messaging.</h2></body></html>";
		WebDriver wd = new FirefoxDriver();
		efwd = new EventFiringWebDriver( wd );
		efwd.navigate().to( initialUrl );
		EventWrapper ew = new EventWrapper( efwd );
		efwd.register( ew );
	}

	@Test
	public void runTest() {
		JavascriptExecutor js = (JavascriptExecutor)efwd;
		js.executeScript( "$.jGrowl('Hello world!');" );
		js.executeScript( "$.jGrowl('Stick this!', { sticky: true });" );
		js.executeScript( "$.jGrowl('A message with a header', { header: 'Important' });" );
		js.executeScript( "$.jGrowl('A message that will live a little longer.', { life: 10000 });" );
		//js.executeScript( "$.jGrowl('A message with a beforeOpen callback and a different opening animation.', " +
		//    "{ beforeClose: function(e,m) { alert('About to close this notification!'); }, animateOpen: {height: 'show' }});" );		
	}
	
	@AfterTest
	public void cleanUp() {		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		efwd.quit();
	}

}
Monday, June 23rd, 2014 Uncategorized No Comments

Using Java for a recursive Fibonacci sequence calculation.

Fibonacci sequence is: f(n) = f(n – 1) – f(n – 2)

Here is the Fibonacci sequence calculated in Java.

public class TestIt {

	public static void main(String[] args) {

		System.out.println( "Fib1: " + fibonacci(0) );
		System.out.println( "Fib1: " + fibonacci(5) );
        System.out.println( "Fib1: " + fibonacci(12) );
        System.out.println( "Fib1: " + fibonacci(16) );

        System.out.println( "Fib2: " + f(1) );
        System.out.println( "Fib2: " + f(5) );
        System.out.println( "Fib2: " + f(12) );
        System.out.println( "Fib2: " + f(16) );
	}
	
	// recursive
        public static int fibonacci( int n )  {
	    if( n == 0 )
	        return 0;
	    else if(n == 1)
	      return 1;
	   else
	      return fibonacci(n - 1) + fibonacci(n - 2);
	}
	
       // non-recursive
	public static int f( int n ) {
		int a=1,b=1,c=0;
        //System.out.print(a);
        //System.out.print( " " + b );
        for( int i = 0; i < n-2; i++ ) { 
        	c=a+b;
            a=b;
            b=c; 
        	//System.out.print( " " + c );
        }
		return b;
	}	

}
Monday, April 14th, 2014 Interview, Java, Musings No Comments

Take DB snapshots using Schemacrawler with Oracle from a Windows batch script

I created an example of using Schemacrawler with Oracle from a Windows batch script. I stored the code in a Gist at this location, but here is the basic script.

@ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION
SET TITLE=Schema crawler
TITLE %TITLE%
ECHO.&ECHO.
 
:: FORMAT can be csv or html
SET FORMAT=html
SET INPUTFILE=table.names
SET USER=user
SET PW=myp@ssword
SET HO=tools.domain.com
SET PO=1521
SET SC=TOOLS
 
ECHO #############################################################
ECHO ## Connecting to Oracle at '%US%@%HO%:%PO%/%SC%'
ECHO #############################################################
 
FOR /F "skip=1 tokens=2-4 delims=(-)" %%a IN ('"echo.|date"') DO (
FOR /F "tokens=1-3 delims=/.- " %%A IN ("%DATE:* =%") DO (
SET %%a=%%A&SET %%b=%%B&SET %%c=%%C))
SET /A "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
FOR /F "tokens=1-4 delims=:. " %%A IN ("%time: =0%") DO @SET UNIQUE=%yy%%mm%%dd%-%%A%%B
 
IF NOT EXIST snapshot_%UNIQUE% (
ECHO Creating snapshot in directory ^"snapshot_%UNIQUE%^".
MKDIR snapshot_%UNIQUE%
)
 
:: Loop through input file
FOR /F "tokens=*" %%A IN (%INPUTFILE%) DO (
ECHO Processing table '%%A' ...
CALL :SNAPSHOT %%A
)
GOTO :END
 
:SNAPSHOT table
java.exe -classpath lib/*;. schemacrawler.tools.oracle.Main ^"-command=SELECT * FROM %1^" -infolevel=minimum^
-database=%SC% -user=%USER% -password=%PW% -schemas=%SC% -port=%PO% -host=%HO% -table_types=TABLE -sortcolumns=true^
-outputformat=%FORMAT% -outputfile=snapshot_%UNIQUE%\%SC%.%1.%FORMAT% -g=schemacrawler.config.properties
EXIT /B 0
 
:END
ECHO Finished processing '%INPUTFILE%' . Closing in 20 seconds...
ECHO.
FOR /l %%a IN (20,-1,1) DO (TITLE %TITLE% -- closing IN %%as&ping -n 2 -w 1 127.0.0.1>nul)
Saturday, April 5th, 2014 Powershell, SQL, Uncategorized No Comments

JMeter WebDriver sampler example.

Here is some sample code for a JMeter WebDriver sampler example.

var pkg = JavaImporter(org.openqa.selenium)
var support_ui = JavaImporter(org.openqa.selenium.support.ui.WebDriverWait)
var wait = new support_ui.WebDriverWait(WDS.browser, 5000)
WDS.sampleResult.sampleStart()
WDS.log.info("Opening page...");
WDS.browser.get('http://duckduckgo.com')
var searchField = WDS.browser.findElement(pkg.By.id('search_form_input_homepage'))
searchField.click()
WDS.log.info("Clicked search field")
searchField.sendKeys(['blazemeter'])
WDS.log.info("Inserted blazemeter keyword")
var button = WDS.browser.findElement(pkg.By.id('search_button_homepage'))
button.click()
WDS.log.info("Clicked search button");
var link = WDS.browser.findElement(pkg.By.ByCssSelector('#r1-0 > div.links_main > h2 > a.large > b'))
link.click()
WDS.log.info("Clicked blazemeter link");
WDS.log.info(WDS.name + ' finishing...');
WDS.sampleResult.sampleEnd()
Friday, April 4th, 2014 Uncategorized No Comments

Example of a DOS do-for loop

A neat example of a DOS do-for loop. You wont find an example like this very often:

@echo off
setlocal
for /f "delims=: tokens=1*" %%A in ('systeminfo') do for %%S in (
  "OS Name:OSNAME"
  "OS Version:OSVER"
  "Original Install Date:INSTDATE"
  "System Manufacturer:SYSMFG"
  "System Model:SYSMDL"
) do for /f "delims=: tokens=1*" %%a in ("%%~S") do if %%A==%%a (
  for /f "tokens=*" %%s in ("%%B") do set "%%B=%%s"
  echo %%A = %%B
)
echo Done.
pause>Nul
Monday, March 10th, 2014 Uncategorized No Comments

In Progress…

Coming soon. An TestNG DataProvider example using XMLBeam.

http://xmlbeam.org/index.html

Monday, March 10th, 2014 Uncategorized No Comments

Selecting parent or child element with Selenium cssSelector

A cssSelector can be used for locating dynamically changing elements.

css = a[title='textA']

If some part of your id remains constant,for instance,in your case if id47 changes to id48 or id200 and so on, you can use contains (i.e. *) or starts with (i.e. ^) :

css = a[id*='id'][title='textA']
or
css = a[id^='id'][title='textA']
For span (textB),the following would work :
css = span.icon + span
Here + is used to locate following sibling.

Using the cssParentSelector project, you can select a parent from the following XHTML example:

<div class="input-wrap">
    <input type="text" class="Name"/>
    <span class="help hide">Your name sir</span>
</div>

You can also select that span.help when the input is active and show it:
.input-wrap! .help > input[type=text]:focus { display: block; }

Wednesday, February 26th, 2014 Uncategorized No Comments

A simple framework for replaying ‘Selenium Builder’ scripts.

I created a simple framework for replaying Selenium scripts that were recorded using Selenium Builder.

Simple-Selenium-Builder-Framework

Monday, February 24th, 2014 Uncategorized No Comments

Using Apache incubator MetaModel for TestNG DataProvider

I created a sample project showing how to use Apache incubator project MetaModel for generating data in a TestNG DataProvider. This can be used to generate test data from .XLS, .XML, or .CSV files.

https://github.com/djangofan/MetaModelExample

Tuesday, February 18th, 2014 Uncategorized No Comments

Address handler class for unit testing with Java.

I created a address handler class for unit testing with Java. This is my own version but you could adjust it for your own purposes.

import org.testng.Reporter;

public class AddressWrapper implements Comparable<Object> {
	
	private boolean isCompactForm; // when true, represent address without spaces after commas
	private boolean separatedZip; // when true, separates state and zip and country with commas
	private boolean isShort; // when true, this address class is a short-form address, otherwise it is long-form
	private boolean isValid;
	private String spacer;
	private String zipspacer;
    private String street;
    private String city;
	private String state;
    private String zip;
	private String country;

	public AddressWrapper ( String city, String state ) {
		setSpacerEnabled( false );
		setSeparatedZip( false );
		setShort( true );
		this.isShort = true;
		this.street = "";
        this.city = city.trim();
        this.state = state.trim();
        this.zip = "";
        this.country = "";
        setValid( true );
    }

    public AddressWrapper ( String street, String city, String state, String zip, String country ) {
    	setSpacerEnabled( false );
    	setSeparatedZip( false );
    	setShort( false );
        this.street = street.trim();
        this.city = city.trim();
        this.state = state.trim();
        this.zip = zip.trim();
        this.country = country.trim();
        setValid( true );
    }
    
    public AddressWrapper ( String commaSeparatedAddress ) {
    	parseAddress( commaSeparatedAddress );
    }
    
	public AddressWrapper parseAddress( String location, boolean spacers, boolean zipspacers ) {
		String[] address = location.split(",");
		if ( address.length == 2 ) {
			setSpacerEnabled( spacers );
			setSeparatedZip( zipspacers );
			setAddress( address[0].trim(), address[1].trim() );
		} else if ( address.length == 5 ) {
			setSpacerEnabled( spacers );
			setSeparatedZip( zipspacers );
	    	setAddress( address[0].trim(), address[1].trim(), address[2].trim(), address[3].trim(), address[4].trim() );
		} else {
			throw new IllegalArgumentException("The address is not length of 2 or 5.");
		}
		Reporter.log( "Parsed address: " + getFullAddress(), true );
		return this;
	}
	
	public AddressWrapper parseAddress( String location ) {
		Reporter.log( "Parsing address with default of spacers: true, and zipspacers: false", true );
		return parseAddress( location, true, false );
	}
    
    public void setShort( boolean isShort ) {
		this.isShort = isShort;
	}

	public void clearAddress() {
    	this.street = "";
        this.city = "";
        this.state = "";
        this.zip = "";
        this.country = "";
        setValid( false );
    }
    
    public int compareTo( Object object ) {
        AddressWrapper address = (AddressWrapper)object;
        int compare = this.city.compareToIgnoreCase( address.city );
        if ( compare == 0 ) {
            compare = this.state.compareToIgnoreCase( address.state );
        }
        return (compare);        
    }
    
    public String getCity() {
    	if ( !isValid() ) {
    		throw new IllegalStateException( "Get city not available from this address right now." );
    	}
    	return this.city;
    }
    
    public String getCityState() {
    	if ( !isValid() ) {
    		throw new IllegalStateException( "Get city and state not available from this address right now." );
    	}
    	return this.city + "," + spacer + this.state;
    }
    
    public String getCountry() {
    	if ( !isValid() || !isShortAddress() ) {
    		throw new IllegalStateException( "Get country not available from this address right now." );
    	}
    	return this.country;
    }
    
    public String getFullAddress() {
    	if ( !isValid() ) {
    		throw new IllegalStateException( "Full address not available from this address right now." );
    	}
    	if ( isShortAddress() ) {
    		Reporter.log( "WARNING: The full address is incomplete.");
    		return this.getCityState();            
    	} else {
    		return this.street + "," + getSpacer() + this.city + "," + getSpacer() + this.state + getZipSpacer() + 
            		this.zip + getZipSpacer() + this.country;
    	}
    }
    
    public String getSpacer() {
    	if ( spacer == null ) {
    		if ( hasCompactForm() ) {
		        return "";
    		} else {
    			return " ";
    		}
    	}
    	return spacer;
	}

    public String getState() {
    	if ( !isValid() ) {
    		throw new IllegalStateException( "Get state not available from this address right now." );
    	}
    	String stateCode = this.state;
    	if ( stateCode.length() == 2 ) {
    		return stateCode;
    	} else {
    		Reporter.log( "Invalid state code: " + this.state, true );
    		return "NULL";
    	}
    }    

    public String getStreet() {
    	if ( !isValid() || isShortAddress() ) {
    		throw new IllegalStateException( "Get street not available from this address right now." );
    	}
    	if ( this.street != null ) {
            return this.street;
    	} else {
    		return "NULL";
    	}
    }
    
    public String getZip() {
    	if ( !isValid() || isShortAddress() ) {
    		throw new IllegalStateException( "Get zip not available from this address right now." );
    	}
    	if ( this.zip != null ) {
            return this.zip;
    	} else {
    		return "00000";
    	}
    }

    public String getZipSpacer() {
    	if ( zipspacer == null ) {
    		if ( hasSeparatedZip() ) {
		        return ",";
    		} else {
    			return " ";
    		}
    	}
    	return spacer;
	}
    
    public boolean hasSeparatedZip() {
    	return this.separatedZip;
    }

	public boolean hasCompactForm() {
		return isCompactForm;
	}

	public boolean isShortAddress() {
		return isShort;
	}

	public void setAddress( String city, String state ) {
    	clearAddress();
        this.city = city;
        this.state = state;
    	setShort( true );
    	setValid( true );
    }

	public void setAddress( String street, String city, String state, String zip, String country ) {
    	clearAddress();
        this.street = street;
        this.city = city;
        this.state = state;
        this.zip = zip;
        this.country = country;
        setShort( false );
        setValid( true );
    }

	public void setCompactForm( boolean isCompact ) {
		this.isCompactForm = isCompact;
	}

	public void setSeparatedZip( boolean separateZip ) {
		this.separatedZip = separateZip;
	}

	public boolean setSpacerEnabled( boolean val ) {
		if ( val ) {
			this.spacer = " ";
			this.setCompactForm( false );
			return this.isCompactForm;
		} else {
			this.spacer = "";
			this.setCompactForm( true );
			return this.isCompactForm;
		}
	}

	public boolean isValid() {
		return isValid;
	}

	public void setValid( boolean isValid ) {
		this.isValid = isValid;
	}

	public boolean setZipSpacer( boolean val ) {
		if ( val ) {
			this.zipspacer = ",";
			this.separatedZip = true;
			return this.separatedZip;
		} else {
			this.zipspacer = " ";
			this.separatedZip = false;
			return this.separatedZip;
		}
	}	

	public String toString() {
    	String address;
    	if ( isShortAddress() ) {
    		address = this.getCityState();            
    	} else {
    		address = this.getFullAddress();
    	}
		return address;
    }

}
Friday, February 14th, 2014 Uncategorized No Comments