Talking testing, automation... and anything else.

Jan 14

Geb vs. Sahi vs. Selenium-Webdriver

gebAs an addendum to my original post comparing Selenium and Sahi, I offer the same test written in Geb.

I took a bit of flack for the original article, mainly people complaining that my comparison wasn’t an apples to apples comparison. Their argument was that because they share a more similar architecture, a more fair comparison would be to compare Sahi to Selenium RC. Of course this argument is complete rubbish. My comparison was (and is) merely a look into the raw code of each tool. But even if it wasn’t, Sahi and Selenium both aim to provide the same function: web application automation. Comparing these two tools is completely valid… though I do profess to enjoy the modicum of hyperbole. That all being said, I will paraphrase Mike Watt and say: “if you don’t like it, go out and start your own blog!”

Anyway, I’ll throw Geb’s hat in the same ring with one disclaimer: Geb runs on top of Webdriver… WORLD BEWARE. Please feel free to breath into a paper bag or the something…

Now, without further ado, I give you [gasp] the Google Translate test, written in raw Geb (no developers were hurt during the coding of this test (unless you equate drinking most of a bottle of wine to being “hurt” (which I do not (because I live in Wisconsin)))). Enjoy responsibly!

import geb.Browser {

    $('', text:'Norwegian').click()
    $('textarea#source') << 'ost'

    waitFor {
        $('span#result_box').text() == 'cheese'


Download the working code from GitHub...

Note: this code, like the original Sahi and Selenium code, is "in the raw", as it were. I.e. no page objects or custom methods to help readability/maintainability/*.ility.

Oct 13

Using Page Objects In Sahi (Javascript)

pageI read a nice post by Martin Fowler about Page Objects, that reminded me that I’ve not yet expanded on my original post about using them with Sahi. Let me correct that…

To demonstrate using page objects in Sahi, I refactored three tests from Sahi’s own demo. You’ll find the original three tests in your Sahi scripts folder, in: demo\testcases\training.sah.

Note, that this is my implementation of the page object pattern… I’m sure it could be improved upon. Also note that this code currently only works in Sahi Pro version 5.x. If you’re running the open source version of Sahi, you’ll need to wait until they update the OS version to 5.x. Feel free to lobby the Sahi dev team to do just that ;)

If you’d like to cut to the chase, you can just download the example code .zip or get it from GitHub.

What Is a Page Object?

A page object is code written to model an actual page (or part of a page) in a web application. Eg. each page in your app, would have an associated page object file that provides the “services” that the actual page offers. Eg. if there’s a button on a page in your application, you would have a reference to that button in your page object. If you then write a test that clicks that button, you would access the button through the page object.

Why Use Page Objects?

Page object provide many benefits, including:

  1. Make tests more readable/easier to understand
  2. Make tests easier to maintain
  3. Help organize code into logical chunks

Sahi Page Object Example (Javascript)

The following is the login page object you’ll find in my example code.

	Login Page Object... 

function LoginPage() {
	// properties: all accessors and data should be abstracted from tests... 
	this.$url = $BASEURL+"/login.htm";
 	this.$userTextBox = _textbox("user");
	this.$passwordBox = _password("password");
	this.$loginButton = _submit("Login");

	// helper methods... 
	this.go = function() {

    // pass in role array; helps test simplicity and readability... 
    this.loginAs = function($roleArray) {
		this.login($roleArray[0], $roleArray[1]);

	// handle login; allows manual logins... 
	this.login = function($userName, $password) {
		_setValue(this.$userTextBox, $userName);
		_setValue(this.$passwordBox, $password);

// extend CommonPage... 
LoginPage.prototype = new CommonPage();
// instantiate the object... 
loginPage = new LoginPage();

In our example, we first include a CommonPage (more on that in a minute) and then create our page object (Javascript’s version of a class), LoginPage. Then we abstract out all the elements we need from the actual page and store them as properties (variables). This is one of the biggest benefits of a page object. If an element is changed in your application, you need only update it’s associated property to fix your code.

We then add any methods (functions) we want to make use of on the page. In this case, we simplify the login method by also offering a loginAs method that takes a user role array as an argument. Thus to login (which we’ll do a LOT) we need only call: loginPage.loginAs($admin) or in this case, loginPage.loginAs($user).

Next, we extend the functionality of our LoginPage. You may wish to have certain properties and methods available to all of your page objects. You might also have common elements across multiple pages (eg. search box or nav bar). To accomplish this, we use Javascript’s prototype object to extend common objects. In our example, we have methods we’d like to make available in all of our page objects. Thus, we have LoginPage’s prototype object to extend CommonPage. Now, any method in CommonPage is also available in LoginPage.

Lastly, we simply instantiate the LoginPage object. I do this because I don’t care to have a bunch of “new” statements mucking up my tests. Therefore, when I include a page object, it’s already instantiated and I can just start using it. This might not jive with some folks… You’re of course welcome to instantiate each new page directly in your tests if you like ;)

Testing Login Using LoginPage Object

And now, here’s how we use our page object…

	brian [at]



var $currentPageURL= booksPage.getCurrentPageURL();

_assertEqual(booksPage.$url, $currentPageURL);

Pretty simple. We include our config.sah and the two page objects we need for the test. You’ll do this in every test. Then we login using our LoginPage object that we instantiated in the variable loginPage (note the object is uppercase and reference is lowercase). Once logged in, we grab the current page url and assert that we’re on the page we expected.

That’s it for our login test. The test code is simple and concise… we don’t use any Sahi code to access anything on the page, which should make maintaining our code MUCH easier down the line.

There are additional pages and tests in my example code. Feel free to give it a whirl and let me know what you think!

Jul 13

How To Connect To SQL Server In Sahi

1373908671_databaseSahi includes JDBC support that allows you to read and write to popular databases. In this example we’ll be connecting to a SQL Server database.

The Gist…

First off, you need to download the Microsoft Java Database Connectivity (JDBC) driver for SQL Server. This is just a jar that Sahi uses to connect to SQL Server. I’m using version 4 in this example but other versions should work. Next, tell Sahi where to find the JDBC jar (putting it in Sahi’s extlib folder is a good idea). And finally, use the dang thing.

Download and install the JDBC

  1. Download the Microsoft JDBC
  2. Check the sqljdbc_4.0.2206.100_enu.tar.gz
  3. Unzip the file and navigate to Microsoft JDBC Driver 4.0 for SQL Server\sqljdbc_4.0\enu\
  4. Copy the file sqljdbc4.jar to Sahi’s exlib folder: eg. C:\sahi_pro\extlib\db\ (your Sahi path might be different)

Add the JDBC jar to Sahi’s dashboard.bat

  1. Open sahi_pro\userdata\bin\start_dashboard.bat and add the following line:
  2. SET SAHI_EXT_CLASS_PATH=%SAHI_USERDATA_DIR%\extlib\db\sqljdbc4.jar;

Use it!

Now that you have the JDBC driver installed and configured in Sahi, it’s time to use it. Sahi includes a method _getDB to handle calls to a database. It uses two other methods, select and update to do the heavy lifting. The gist here is we create a variable to handle the db connection (which returns an object) and then use that object to select or update data in the database.

Here’s an example…

// config... 
var $dbServer = "localhost";
var $dbUser = "sa";
var $dbPass = "password";
var $dbName = "myDB"; 

// create a handle object...
var $db = _getDB("","jdbc:sqlserver://"+$dbServer+";databaseName="+$dbName+"", $dbUser, $dbPass);

// get all rows from a table...
var $rows = $"Select * from MyTable");
_alert($rows.length); // output number of rows returned...
_alert($rows[0].toString()); // output the first row returned...

That’s it!

Jan 13

Selenium-WebDriver vs Sahi

selenium.logoJari Bakken has a couple of nice example tests that show some of the differences between a Selenium-WebDriver test and a Watir-Webdriver test. I thought I would create another example to show how the same code could be written in Sahi.

Both of the following scripts perform the same test. The test itself is simple:

  1. Go to the Google Translate page
  2. Click the Detect Language button
  3. Select Norwegian as your language
  4. Log the button’s text
  5. Enter the word “ost” into the text field
  6. Verify “cheese” is the returned translateion

Selenium-Webdriver Example…

require 'selenium-webdriver'

driver = Selenium::WebDriver.for :firefox
driver.get ""

wait = => 5)

language_button = wait.until {
  element = driver.find_element(:id => "gt-sl-gms")
  element if element.displayed?

language_button.find_element(:tag_name => "div").click

menu = wait.until {
  element = driver.find_element(:id => "gt-sl-gms-menu")
  element if element.displayed?

langs = menu.find_elements(:class => "goog-menuitem")

norwegian = langs.find { |lang| lang.text == "Norwegian" }
norwegian.find_element(:tag_name => "div").click

puts language_button.text

driver.find_element(:id => "source").send_keys("ost")

result = wait.until {
  result = driver.find_element(:id => "result_box").text
  result if result.length > 0

puts result

Sahi Example…



_log("The selected button text is: " + _getText(_div("gt-sl-gms")));

_setValue(_textarea("source"), "ost");

_assertEqual("cheese", _getText(_span("result_box")));

The difference is pretty dramatic… at least in test size. Sahi handles all your waits for you so there’s no need to clutter up your tests with wait code. Accessor code is also less verbose in Sahi. Overall, I would argue the Sahi code is much more readable but code beautry, like beauty in general, is in the eye of the beholder. I.E. your millage may vary…

Note: I used an assert instead of just logging the returned translateion… same dif

UPDATE: I’ve also added Geb to the fray!

Jan 13

Verify Sorting With Sahi (or any tool really)

4800819674_3cf963deaa_bI recently found a bug when sorting table columns, while running IE9. Ignoring the obvious fix, I wrote up the bug and then as I’m a fan of doing, I wrote a failing automated test to test it (Defect Driven Development!).

Testing sort proved a bit tricky… I thought I would share the results to perhaps save others same pain. I would also not be surprised to find a more elegant solution out there. If you have one, do feel free to share!

My example is in Sahi but it should be easy to transfer to your tool of choice. The gist is:

  1. Sort your column
  2. Collect all the elements in the column in an array
  3. Copy the array and sort the copy using javascript’s sort()
  4. Compare the two arrays

And here’s the Sahi code…

/** ~sort test... 	**/


// initial sort... 

// collect table column cell values in an array...
_set($numRows, _table("table0").rows.length -1);
var $appSortedValues = new Array();
for(var $i=0; $i<$numRows; $i++) {
	$appSortedValues[$i] = _getText(_cell(0, _in(_row($i+1, _in(_table("table0"))))));

// copy array javascript style using slice... 
var $jsSortedValues = $appSortedValues.slice(0);

_assertEqual($jsSortedValues, $appSortedValues);

// Javascript's sort is case sensitive so we "fix" that thusly... 
function caseInsensitiveSort(a, b) {
    if (a.toLowerCase() < b.toLowerCase()) return -1;
    if (a.toLowerCase() > b.toLowerCase()) return 1;
    return 0;

First off, thanks to for providing an example for my example!

The script starts by navigating to and clicking on the Name table header to get our initial sort of that column.

Then we collect each element in the Name column, in table0 and store them in an array, $appSortedValues. To iterate through our loop, we get the number of rows in table0 by counting the number of rows and subtract 1 for each table header.

Now we need a copy of our $appSortedValues array but in Javascript, you can’t just set a new array from our existing array like so: $jsSortedValues = $appSortedValues; . This will actually create a reference to our original array; not what we want. Instead we use the slice() method to select elements 0 through the end of the array and put them all in our new array, thus copying it.

Finally, we use javascript’s sort() method to sort the copy of our array, $jsSortedValues. But the sort() method has a little wrinkle; by default, it sorts alphabetically and is case sensitive. This is unlikely to be how your application’s sort works… but luckily, you can roll your own sort filter by passing a function as an argument to the sort() method. In our case, we want it to be case-insensitive, hence our function caseInsensitiveSort.

Now we have two arrays and can simply use Sahi’s _assertEqual method to verify both arrays are sorted in the same order.

That’s it!