This is the P2PU Archive. If you want the current site, go to www.p2pu.org!

Learning Web UI Automation

Week 3 - Working with AJAX sites

David Burns's picture
Thu, 2011-02-10 19:05

Web applications are increasingly moving towards having AJAX. It's quite ubiquitous for web applications to have it these days. This means that when our tests run we need to have mechanisms that allow our tests to synchronize with what is happening on the browser. To do this we can build our own wait methods to or we can use some of the built in methods.

There is only one thing that Selenium will implicitly wait for. This is when we call open(path). It will wait for the page to load but if the page as some JavaScript that then executes onLoad to create new elements on the page we might not be able to work with them straight away.

Let's dive into how we do this now.

wait_for_page_to_load(timeout)

Links are the most common way to navigate around a site. We do this by clicking on them. In the case that a link causes
a new page to load Selenium has a simple solution to wait for the next page. There is an API call
wait_for_page_to_load(). This takes one paramater, a string, that represents how long it should wait for before giving
up. The value of seconds is represented in milliseconds to take how long it should wait in seconds and multiply by 1000
to get the value in milliseconds.

The usual scenario is to wait for 30 seconds, if it hasn't loaded then raise an exception.

An example would be

 selenium.wait_for_page_to_load("30000")

wait_for_frame_to_load(frameLocator, timeout)

A similar call is wait_for_frame_to_load except that it works against 1 frame on the page. An example of this is if you
have a site that uses frame to do layout. On the left are links that will allow you to navigate the site by changing the
contents of the central frame. our test script would look something like this

selenium.click("link=foo")
selenium.wait_for_frame_to_load("mainFrame", "30000")

Frames are becoming increasingly uncommon so you will hardly use this. As a side note, they have been deprecated as of HTML5.

wait_for_condition("javascript snippet")

This is the most common wait command used when working with applications using AJAX. Wait for Condition allows us to pass through a JavaScript snippet to interrogate the App Under Test. Wait for condition needs to have a condition that needs to be met in JavaScript. If you have a multiline snippet of JavaScript, splitting lines with semi-colons, then the last line needs to have the conditional.

The other item that is needed is a way to access the DOM. We do this by using
selenium.browserbot.getUserWindow().document. I will go into more depth with this in a future lecture.

So if you are working with a jQuery DatePicker widget you would have to have something like the code below to wait for it to be fully rendered

 self.selenium.wait_for_condition("""selenium.
                                browserbot.
                                getCurrentWindow().
                                document.getElementById('ui-datepicker-div').scrollWidth == 251""", 10000)

The next approach that is commonly seen is by rolling your wait for commands.

These are simple loops that rely on the is_* API calls that are available. An example of this can be seen below

def wait_for_element_present(self, element):
    count = 0
    while not self.selenium.is_present(element):
        time.sleep(1)
        count += 1
        if count == 30:
            raise Exception(element + ' has not loaded')

At Mozilla we use a mixture of the wait for commands because they all serve a purpose in the right places.

Task

This week I want you to try working against another one of Mozilla's staging servers. Input is a project that allows people to feedback to Mozilla what they think of the current version of Firefox. What I would like you to do write a test that clicks on the check box for Russian and then checks that language is the only language available to select and then deselects it.


from selenium import selenium
import unittest

class TestInputStageSite(unittest.TestCase):

    def setUp(self):
        self.selenium = selenium("localhost", 4444, 
                                 "*firefox", "http://input.stage.mozilla.com")
        self.selenium.start()
        self.selenium.open("/")
        self.selenium.window_maximize()

    def tearDown(self):
        self.selenium.stop()

    def test_that_clicking_on_a_language_checkbox_makes_other_language_choices_disappear(self):
        # Insert your test here
        pass

As always please email me your answers. If you need help please feel free to email me or get me on irc at
irc.mozilla.org in the #mozwebqa channel or on irc.freenode.net in the #Selenium channel!