Talking testing, automation... and anything else.



05
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... 
*/
_include("CommonPage.sah");

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() {
    	_navigateTo(this.$url);
    };

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

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

// 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] qualityshepherd.com

*/
_include("../config.sah");
_include("../Pages/LoginPage.sah");
_include("../Pages/BooksPage.sah");

loginPage.loginAs($user);

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!


11
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("com.microsoft.sqlserver.jdbc.SQLServerDriver","jdbc:sqlserver://"+$dbServer+";databaseName="+$dbName+"", $dbUser, $dbPass);

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

That’s it!


24
Feb 13

Amazon EC2 Ubuntu HowTos

ec2Having a server in the cloud is a nicety. That Amazon gives you one free for a year to tinker with… that’s being downright friendly!

The following are some notes/howtos for setting up an Ubuntu Amazon EC2 instance. I post them to help me remember them but they might also be useful to others…

Allow SSH Access

If you’d prefer to just ssh into your instance instead of using key/pair…

1. Login using the key/pair you created when setting up your EC2 instance:

ssh -i myprivatekey.pem [email protected]

2. edit your sshd_config file and uncomment and/or set PasswordAuthentication yes:

sudo pico /etc/ssh/sshd_config

3. Reload SSH:

sudo reload ssh

4. Create a new user and set the user’s password:

useradd NAME
passwd // enter password twice...

Install LAMP

1. Update Ubuntu’s package database, install and run Taskel. Select the LAMP server (don’t deselect anything that is also checked) and let it install:

sudo apt-get update
sudo tasksel

2. Install PHPMyAdmin; select Apache2, enter a root password and say No to config the database later:

sudo apt-get install phpmyadmin

3. Verify by going to: http://myIPaddress/phpmyadmin and login as root with the password you entered. Of course you’ll probably want to secure/move this!

Install XRDP on Ubuntu 12.10

Installing X11 on your instance–should you be so inclined–may prove tricky… I tried MANY ways of doing it (OpenBox/FluxBox, VNC, etc…) but each attempt ended in failure. I found victory with XRDP!

1. Found from the instructions here. First install Gnome (will take a while)…

export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
sudo apt-get install -y ubuntu-desktop

2. Ubuntu 12.10 no longer includes gnome-session-2d, so install fallback and edit .xession to use it:

sudo apt-get install gnome-session-fallback
pico .xsession
gnome-session --session=gnome-fallback // add/change this line in .xession 
/etc/init.d/xrdp restart

3. Edit Xwrapper file and set allowed_users=anybody:

pico /etc/X11/Xwrapper.config

4. Create a new Security Group Rule for RDP(i.e. open port 590x (where x is the vncserver id))

5. Install RDP client on your local machine…

Install Chromium brownser on Ubuntu 12.10

FireFox is in need of Unity by default and it appears it doesn’t exist on 12.10. I wanted Chrome on there anyway but it didn’t work either. Chromium does:

sudo apt-get install chromium-browser

13
Feb 13

Adding Copy Filename and Copy Path to Sublime Text’s Sidebar

Sublime_Text_Logo[1]My text editor of choice is Sublime Text but right out of the box, it does not include copy filename or copy file path in the sidebar (both of which I use constantly). Seems that whenever I install it on a new machine (which I just did) I forget how to install the Package Control package, which offers such goodies. Therefore, I thought I would park the instructions here for your–and more importantly, my–convenience.

It’s pretty easy…

  1. In Sublime Text, type ctrl+` to access the console
  2. Copy the code below, paste it in the console and hit return
  3. Restart Sublime Text
  4. import urllib2,os; pf='Package Control.sublime-package'; ipp=sublime.installed_packages_path(); os.makedirs(ipp) if not os.path.exists(ipp) else None; urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler())); open(os.path.join(ipp,pf),'wb').write(urllib2.urlopen('http://sublime.wbond.net/'+pf.replace(' ','%20')).read()); print('Please restart Sublime Text to finish installation')
    

Now, when right/ctrl-clicking a file or files in Sublime Text’s sidebar, you should see a wealth of options including copy path/name.

If for some reason this fails to work, you can download and install manually with the instructions here…

Now that you have Package Control installed, use it by typing shift-ctrl-p. You can then, as you might imagine, control Sublime packages. Eg. install, remove, etc…. My two must-haves are: SideBarEnhancements and All Complete. To install them:

  1. Click shift-ctrl-p
  2. Start typing “install” and select Package Control: Install Package
  3. A package prompt appears; start typing the package name, eg. All Auto Complete

That’s it! Just repeat these steps for each package you’d like to install.