Posts Tagged ‘selenium tips’

Selenium Tips: How to Coordinate Multiple Browsers in Sauce OnDemand

September 3rd, 2010 by Santiago Suarez Ordoñez

Let’s imagine your team is making a chat application. Nothing too fancy, just something simple in which you need to make sure multiple users get together, talk, and read each other.

Doesn’t sound that bad, huh? But how about coordinating those browsers? You need to have different sessions running at the same time in coordination and interacting with each other through your web app.

Now, when we think about parallelization and multiple browsers, Sauce OnDemand is, of course, our first answer, but here, there can be a small limitation. Sauce OnDemand has a special timeout that waits for new commands for no more than 90 seconds*. If it doesn’t get any new command, it will kill the job and assume something went wrong.

This effects us, as we need to get multiple browsers running in parallel and in coordination. As we request them one after another, depending on the amount of browsers and the load our service is put under, the first ones might timeout while waiting for the others to come.

To avoid this, the best solution is to write a multi-threaded script, in which browsers will send heartbeat commands while they are waiting for the rest. Multi-threading can be done with every programming language, but I decided to write my example in Python because I think it’s understandable for almost anyone, even if you’ve never seen Python before. The complete example is in github as a gist, and here is a brief description of what each interesting part is doing:

def get_browser_and_wait(browser, browser_num):
    print "starting browser %s" % browser_num
    browser.start()
    browser.open("/") # if we get here, OnDemand already gave us the browser
    browsers_waiting.append(browser)
    print "browser %s ready" % browser_num
    while len(browsers_waiting) < len(browsers):
        print "browser %s sending heartbeat while waiting" % browser_num
        browser.open("/")
        time.sleep(3)

get_browser_and_wait is the function that will take care of the ‘start the browser’ request in OnDemand and wait till it comes back. Once the server is ready, it will keep sending open commands as heartbeats and waiting until the other requested browsers are ready and waiting too.

thread_list = []
for i, browser in enumerate(browsers):
    t = Thread(target=get_browser_and_wait, args=[browser, i + 1])
    thread_list.append(t)
    t.start()

for t in thread_list:
    t.join()

This is the magic multithreading part, in which we iterate over every Selenium instance and call get_browser_and_wait with it. Once we send each browser to a thread, the main thread will continue and get to the t.join() part. By this method, the main thread will wait for every browser thread to complete in order to proceed with the rest of the code.

Again, the full example is up in github: http://gist.github.com/511658. If you’re interested in learning what you can use this kind of test for, stay tuned!

* This helps avoid running (and charging) tests that get disconnected or crash.

  • Share/Bookmark

Selenium Tips: Finding elements by their inner text using :contains, a CSS pseudo-class

March 19th, 2010 by Santiago Suarez Ordoñez

As we already mentioned in our previous posts CSS Selectors in Selenium Demystified and Start improving your locators, CSS as a location strategy generally far outperforms XPATH.

That’s why for this Tip of the Week, we are presenting our users one more CSS pseudo-class to keep moving their test suites to this faster and cleaner location strategy.

Let’s imagine you have an element like the following:

<div>Click here</div>

The easiest way to locate it is using it’s “Click here” inner text and in XPATH you would do it using XPATH’s text() function:

//div[text() = "Click here"]

or even better (because the previous version can sometimes fail depending on the browser):

//div[contains(text(), "Click here")]

Now, if you want to move your locators to CSS in situations like this one, all you have to do is use the :contains() pseudo-class, with which your tests would end up using the following locator:

css=div:contains("Click here")

Did you find this useful? Are you still fighting with another XPATH functionality to completely move your tests to CSS? Let us know about it in the comments.

  • Share/Bookmark

Selenium Tips: Parametrizing Selenese tests

March 12th, 2010 by Santiago Suarez Ordoñez

Even though I believe Selenium IDE should just be a transition environment for new Selenium users to reach Selenium RC, we know a lot of our users keep all their tests in Selenese and run them using Selenium IDE as their main testing tool.

That’s why at Sauce we have developed Sauce IDE, our own extension of Selenium IDE that combines Selenium RC’s cross-browser capabilities with the simplicity and interactive design of Selenium IDE.

To continue empowering the IDE users, I’m writing this tip of the week that will help making Selenese tests easier to maintain and write.

As you all know, Selenese is not a real programming language. Variable storage in it is pretty rough and there isn’t an easy way to share information between different Test Cases in the same Test Suite.

However there is a way to do it, through the use of the user-extensions.js file. Let me show you how in two easy steps:

First, create a user-extensions.js file with the following content:

storedVars["url"] = "/staging/search";
storedVars["title"] = "Search Your Item";
storedVars["search-string"] = "234234kjkj";

Then open Selenium IDE, or even better Sauce IDE, and in the Options menu, select the file in the “Selenium Core Extensions” field.
Close and open Selenium IDE again and you should be ready to use that variable in any test that you write. Even better, throughout your whole test suite.

For example:

open ${url}
assertText h1 ${title}
type search-field ${search-string}
click btnSearch
assertTextPresent Search Results for ${search-string}

This may not look super useful at first, but once your test suite grows, keeping things that change from time to time in a single place, makes it really easy to maintain, so if your application’s URL changes from “/staging/search” to “/search”, you will only need to fix the user-extensions.js file and all the hundreds of tests you could have will pass the same way as they did before.

Check the wikipedia’s page on DRY for more information about this programming technique.

Hope you found this useful. If you did, please let us know in the comments.

Santi

  • Share/Bookmark

Selenium Tips: CSS Selectors in Selenium Demystified

January 29th, 2010 by Santiago Suarez Ordoñez

Following my previous TOTW about improving your locators, this blog post will show you some advanced CSS rules and pseudo-classes that will help you move your XPATH locators to CSS, a native approach on all browsers.

Next sibling

Our first example is useful for navigating lists of elements, such as forms or ul items. The next sibling will tell selenium to find the next adjacent element on the page that’s inside the same parent. Let’s show an example using a form to select the field after username.

</input> </input>

Let’s write a css selector that will choose the input field after “username”. This will select the “alias” input, or will select a different element if the form is reordered.

css=form input.username + input

Attribute values

If you don’t care about the ordering of child elements, you can use an attribute selector in selenium to choose elements based on any attribute value. A good example would be choosing the ‘username’ element of the form without adding a class.

</input> </input> </input> </input>

We can easily select the username element without adding a class or an id to the element.

css=form input[name='username']

We can even chain filters to be more specific with our selections.

css=input[name='continue'][type='button']

Here Selenium will act on the input field with name=”continue” and type=”button”

Choosing a specific match

CSS selectors in Selenium allow us to navigate lists with more finess that the above methods. If we have a ul and we want to select its fourth li element without regard to any other elements, we should use nth-child or nth-of-type.

    <p>Heading</p>
  • Cat
  • Dog
  • Car
  • Goat

If we want to select the fourth li element (Goat) in this list, we can use the nth-of-type, which will find the fourth li in the list.

css=ul#recordlist li:nth-of-type(4)

On the other hand, if we want to get the fourth element only if it is a li element, we can use a filtered nth-child which will select (Car) in this case.

css=ul#recordlist li:nth-child(4)

Note, if you don’t specify a child type for nth-child it will allow you to select the fourth child without regard to type. This may be useful in testing css layout in selenium.

css=ul#recordlist *:nth-child(4)

Sub-string matches

CSS in Selenium has an interesting feature of allowing partial string matches using ^=, $=, or *=. I’ll define them, then show an example of each:

^= Match a prefix
$= Match a suffix
*= Match a substring
css=a[id^='id_prefix_']

A link with an “id” that starts with the text “id_prefix_”

css=a[id$='_id_sufix']

A link with an “id” that ends with the text “_id_sufix”

css=a[id*='id_pattern']

A link with an “id” that contains the text “id_pattern”

Matching by inner text

And last, one of the more useful pseudo-classes, :contains() will match elements with the desired text block:

css=a:contains('Log Out')

This will find the log out button on your page no matter where it’s located. This is by far my favorite CSS selector and I find it greatly simplifies a lot of my test code.

Tune in next week for more Selenium Tips from Sauce Labs.

Sauce Labs created Sauce OnDemand, a Selenium-based testing service that allows you to test across multiple browsers in the cloud. With Selenium IDE and Selenium RC compatibilities, you can get complete cross-platform browser testing today.

  • Share/Bookmark

Selenium Tips: HTTPS and self-signed certificate exceptions

January 22nd, 2010 by Santiago Suarez Ordoñez

This week in our support email, help@saucelabs.com, we’ve seen a considerable number of cases of problems with Firefox and the Invalid Certificate warning thrown when a development environment is using the production’s certificate for HTTPS URLs, which causes the browser to wonder about the website’s identity.

Invalid Certificate warning

Warning displayed by Firefox 3.5 in this situation

If you do much browser-based testing, you have surely dealt with this situation more than once. In the manual testing world, you just tell your browser to add an exception for that certificate and ignore further errors, and you can forget about seeing that annoying warning anymore.

But when you move on to automation in the Selenium world, things are not always that simple. In most browsers, adding a certificate exception will work, as Selenium shares the same session as the user and will find the exception as you do. In Firefox, though, Selenium RC creates a special profile each time the browser is started and there’s no trail of the user settings in it.

The workaround for this problem is to create your own Firefox profile, with the specific certificate added on it by hand, and then tell Selenium to launch the browser based on that profile.

Another interesting approach, the one we take at Sauce Labs, where we can’t do this kind of trick, because we just don’t know which certificate the user will need before their test starts, is the use of RCE (Remember Certificate Exception), which is  a plugin that will automatically detect the warning and make the browser go through it, returning the control to Selenium after 4 or 5 seconds. Notice that if you use this approach, you will need to make sure your tests will tolerate this 5 secs additional delay to open the page.

Note: We currently support RCE in our Firefox 3.0 machines, and will be porting this extension to Firefox 3.5 soon.

You can find more info about RCE on its plugin page or in the author’s blog post.

Update: Adam Goucher, one of the big minds in the testing world just wrote a blog post that we couldn’t have written better ourselves about the first and most important advice regarding HTTPS and testing: Do yourself a favour and don’t test using HTTPS

  • Share/Bookmark

Selenium Tips: Capturing Screenshots vs. Scrollbars!

December 11th, 2009 by Santiago Suarez Ordoñez

Capturing screenshots of your tests is one of the most important features you can give to an automation engineer. It’s the easiest way to actually understand from a report, why a test failed and how to reproduce it.

While our OnDemand will help you record videos of your entire test, sometimes you just want a screenshot. Selenium supports capturing screenshots on remote machines, as Sean discussed in a previous Tip of the Week (Taking ScreenShots on the Server).

Selenium has two methods dedicated to screenshot taking:

  • CaptureScreenshot
  • CaptureEntirePageScreenshot

An example of using the later function shows that it’s pretty amazing, giving you a full rendering of the page:

Entire Page Screenshot

While this function is perfect, it only works with Firefox, which greatly limits it’s usefulness. Unfortunately due to limited extension support in other browsers it’s going to be a while before we see this functionality ported.

If you’re stuck with the cross-browser version you’ll get limited success. We can see up to the fold after opening a new page, but we have no idea what’s going on in the depths of our page.

Regular Screenshot

This just isn’t going to work if we want to test something below the fold. There is a partial workaround, focus(). Focus will force all browsers to scroll the page so the selected element is visible. Here’s an example of a test we run to view the bottom of our homepage:

def test_case(self):
        browser = self.browser
        browser.open("/")
        browser.focus("css=a.indexTwitter")
        png = browser.capture_screenshot_to_string()
        f = open('screenshot.png', 'wb')
        f.write(png.decode('base64'))
        f.close()

Regular Plus Focus Screenshot

While this requires more code than Firefox + selenium, it will let you debug those hard to find rendering issues without having to boot up a virtual machine.

I hope you find this useful and start taking screenshots as soon your tests get harder to debug. If you need more visual debugging tools, our service Sauce OnDemand will capture full screen videos which will record every single selection event without any extra code!

Thank for tuning in, and check back after the new year for more Selenium Tip of The Week from Sauce Labs!

PS: You should follow us on twitter

Santiago

  • Share/Bookmark

Selenium Tips: Efficiently removing cookies

November 20th, 2009 by Santiago Suarez Ordoñez

We all know that when your tests run in firefox, things are easy. Even for sessions and cookies. Each time you run the start() method, Selenium will generate a clean Firefox profile and you can forget about previous tests or sessions.

Well, life is not always easy, and we don’t always have to test just Firefox… When IE comes to the game, Selenium can’t create clean profiles and cookies from previous tests will remain for future ones, causing unexpected issues.

For this, Selenium API’s has 2 methods you should use:

sel.delete_cookie(name, optionsString)

This method is useful when you only want to remove a specific cookie. The parameters it receives are sometimes hard to write and can take some time to actually make it work the way you need.

sel.delete_all_visible_cookies()

This one is my personal favorite. It just blows away any cookie that the current domain could have created in your browser.

But wait! I said “current domain”, not all domains. So, if your tests go though several domains, and you want to keep things clean, you’ll need something like the following:

def clean_history(sel, domains):
    temp = sel.get_location()
    for domain in domains:
        sel.open(domain)
        sel.delete_all_visible_cookies()
    sel.open(temp)

This is a python function you can add anywhere, and by calling it with the selenium browser as the first parameter and a list of all domains used in the second one, will make you session clean without too much hassle. Off course you can always make this part of your own version of the selenium client, for then being able to call:

sel.clean_history(domains)

or even better, make selenium keep a record of each domain and then you can call:

sel.clean_history()

But that will have to go in another TOTW.

  • Share/Bookmark

Selenium Tips: Upload files on browsers running over remote machines

November 13th, 2009 by Santiago Suarez Ordoñez

Having your tests upload files to the test application is something that becomes confusing when moving Selenium RC servers to different machines.

Browsers can only upload files from the local machine, but when the RC server (and consequently the browser) are on a different machine than the one running the test, this can be very hard to do.

Luckily, for this kind of situations, Selenium has the attach_file method which receives both a locator and a URL as parameters, then the RC Server takes care of downloading the file to the test machine at a temporary location and then attaching the file completing with this path in the desired field.
Here’s the reference from Selenium’s documentation:

In [5]: sel.attach_file?
Definition:    a.attach_file(self, fieldLocator, fileLocator)
Docstring:
Sets a file input (upload) field to the file listed in fileLocator
'fieldLocator' is an element locator
'fileLocator' is a URL pointing to the specified file.
Before the file  can be set in the input field (fieldLocator), Selenium RC may need to transfer the file to the local machine before attaching the file in a web page form.
This is common in selenium  grid configurations where the RC server driving the browser is not the same  machine that started the test.
Supported Browsers: Firefox ("*chrome") only.

The only drawback of using this method is that the files will have to be placed in a public URL. However, if you don’t want them to be 100% public, you can still keep them safe using basic HTTP Auth and get them using the auth information in the same URL.

Here’s an example usage of the command in python:

sel.attach_file("css=input[type=file]", "http://url.com/file.txt")

Another caveat in the implementation, is that the file must be placed on top level in the URL, so using the following URL will not work:

http://saucelabs.com/subdirectory/subdirectory2/file.txt

while the following will:

http://saucelabs.com/file.txt

Hope you find this useful, and if you need more info, let us know in the comments.

  • Share/Bookmark

Selenium Tips: Start improving your locators

October 30th, 2009 by Santiago Suarez Ordoñez

Almost everyone in the Selenium world knows of the power of XPATH as a locating strategy, at the same way, most of them also know of its slowness on IE.

Now, if your tests have relatively simple XPATH  locators, putting some effort to change them to CSS (which has native support on all browsers) is a very good investment and will impact your tests with instant time improvements.

For this week’s tip, we’ve decided to start addressing the basic rules for the move of simple locators from XPATH to CSS.

Direct child

A direct child in XPATH is defined by the use of a “/“, while on CSS, it’s defined using “>

Examples:

//div/a

css=div > a

Child or subchild

If an element could be inside another or one it’s childs, it’s defined in XPATH using “//” and in CSS just by a whitespace

Examples:

//div//a

css=div a

Id

An element’s id in XPATH is defined using: “[@id='example']” and in CSS using: “#

Examples:

//div[@id='example']//a

css=div#example a

Class

For class, things are pretty similar in XPATH: “[@class='example']” while in CSS it’s just “.

Examples:

//div[@class='example']//a

css=div.example a

Thats’ all for now, as you can see, the first rules a pretty simple, and you even make you locators shorter and cleaner.

Stay tuned for our next Tip of the Week, we will keep addressing more complex locators soon!

  • Share/Bookmark

Selenium Tips: Taking ScreenShots on the Server

October 23rd, 2009 by Sean McQuillan

Taking screenshots of tests as they run is a great tool for discovering rendering issues with your pages. However, taking screenshots from SeleniumRC can be a bit hard, especially if you’re using it in a grid or are using a service like ours. Luckily Selenium provides a command that’s perfect for getting past exactly these kinds of configuration problems, `captureScreenshotToString`. It returns a base64 encoded png of the current page, which you can then write to a file on your local machine. Here’s an example in python:

def test_case(self):
        browser = self.browser
        browser.open("/")
        png = browser.capture_screenshot_to_string()
        f = open('screenshot.png', 'wb')
        f.write(png.decode('base64'))
        f.close()

Tune in next week for another Selenium Tip of The Week!

  • Share/Bookmark