Selenium – Please do the dishes!
In the testing community, lots of companies use many different automation tools. It saves a lot of trouble going through repetitive tasks that the computer is quite capable of doing by itself. At Testuff, we don’t try to compete with those tools. They’ve been around for a while, they do a pretty good job, and trying to beat them at their own game is not what we’re after. Nevertheless, we do our best to integrate with as many automation tools as we can (as we do with bug trackers). The only problem so far is that they can’t do your dishes (yet).

I ended up playing with Selenium recently, when we created a Selenium Extension which integrates with Testuff. It got me thinking: Wouldn’t it be useful (and cool) to use those test automation tools to help me keep up with stuff on my personal life as well? How about checking my bank balance, and sending an email with the latest transactions every day? What about the mobile or home phone bill? Track electricity usage? The possibilities are endless.
Many companies nowadays offer web-based access to your own information, from banks to utility companies, mobile phone operators and so on. However, logging in every time, just to check your balance can be tedious.
I’m sure many of our customers are more experienced Selenium users than we are, but I still wanted to give a few hints about making selenium a little more tedious-task-friendly. One of the main differences in running Selenium for testing and for automating those tasks, is that when you’re testing – if a step fails – the test fails and that’s good enough. All you need is to abort the script and report it back to Testuff via our Automation API. However, for checking your online bank balance, you might want your selenium script to be a little, erm, more intelligent! It should keep trying a few times if a step fails. It should perhaps restart the whole process and try again. It could in fact ignore a few small issues and carry on. Maybe the web page didn’t load completely, but the link to the next page is available. Maybe if a link or text is not available, clicking on another link and then re-loading the page helps.
We’re using python primarily. It’s a simple and powerful language, very easy to read and write, and Selenium easily exports scripts to it. I’ll just list a couple of simple helper functions that I ended up using. They are fairly self-explanatory, but feel free to comment if you have a question.
def wait_for_text(self, text, wait=60):
""" Waits for text to appear on screen for a
given number of seconds. It does not
raise any exception if the text is
not present, but rather returns False
"""
sel = self.selenium
for i in range(wait):
try:
self.failUnless(sel.is_text_present(text))
break
except:
pass
time.sleep(1)
return False
def wait_until_text_disappears(self, text, wait=60):
""" Waits for text to disappear off screen for a given number
of seconds. It does not raise any exception if the text
is still present, but rather returns False.
This is useful for some websites which put
pages like "processing your request"
"""
sel = self.selenium
for i in range(wait):
try:
self.failIf(sel.is_text_present(text))
break
except:
pass
time.sleep(1)
return False
def wait_for_page(self, wait):
""" Replaces the wait_for_page_to_load built-in
function, but catches any exception, so the
script can carry on despite the page
not being fully loaded.
"""
sel = self.selenium
try:
sel.wait_for_page_to_load("%d" % wait * 1000)
except Exception, e:
print "Exception caught: %s" %e
A ‘typical’ automation script will look something like (simplified slightly):
def get_mobile_balance(self):
""" retrieves the mobile phone and remaining Mb balance
and emails it
It retries several times, in case there's a temporary issue with
the website.
"""
sel = self.selenium
retry_count = 0
MAX_TRIES = 5
while retry_count <= MAX_TRIES:
try:
balance = self._get_balance(sel)
self._email("me@address.com", "Mobile Phone Balance", "Here's your balance for today: %s" % balance)
except:
retry_count = retry_count + 1
if retry_count >= MAX_TRIES:
raise
time.sleep(15)
def _get_balance(self, sel):
sel.open(sel.browserURL)
sel.click("//div[@id='check_balance']/div[1]/div/a/h2")
sel.click("link=mobile phone")
self.wait_for_page(30)
sel.type("txtMobileNo", "12345678")
sel.type("txtPassword", "my_password")
sel.click("continue")
self.wait_for_page(30)
self.wait_for_text("Account is ready.")
sel.click("//input[@type='image']")
self.wait_for_text("Your Package", 60)
sel.click("link=view your current usage")
self.wait_for_page(30)
self.wait_until_text_disappears("processing... please wait", 60)
self.wait_for_text("view package balance", 60)
sel.click("link=view package balance")
self.wait_for_page(30)
self.wait_until_text_disappears("processing... please wait", 60)
self.wait_for_text("minutes available", 60)
remaining_minutes = sel.get_text("//div[1]/span[2]")
remaining_mb = sel.get_text("//div[4]/div[1]/span[2]")
sel.click("link=log out")
return "%sn%s" % (remaining_minutes, remaining_mb)
def _email(self, email_address, subject, bodyText):
...
Feel free to share any other cool ideas for using Selenium, or any other automation tool.

This looked fun. It is similar to some of the mechanize based perl modules on CPAN.
http://search.cpan.org/~mwilson/Finance-Bank-HSBC-1.06/lib/Finance/Bank/HSBC.pm
The password encryption is a problem is someone steals your laptop and they can access your bank using selenium. But I expect the conviction rate of selenium users is quite a bit lower than average. Indicating that most thieves do not know selenium.
I started off with perl and python mechanize, but it takes much harder work, and sites use some fairly complex mechanisms that make it really hard for you (dynamic hidden fields, tokens and whatnot). With Selenium, it’s much easier. Most of the work is done by recording using the IDE. Then only a few tweaks are necessary to get it to run more intelligently. That said, perl mechanize scripts are much ‘leaner’. They don’t require you launch a browser to run, so they take less memory and CPU, and can run virtually anywhere.
Passwords are a problem regardless of selenium vs. perl. I recommend using an encrypted drive like Truecrypt (http://www.truecrypt.org/), which you mount when you log on, and then as soon as your computer is rebooted, it’s no longer available. Hopefully you lock your screen when you’re away from your computer anyway, and I’m running these scripts on a home computer and not a laptop.
Throw in Watir http://watir.com/ and you are off on your merry automation ways.