views:

38

answers:

1

Hello world!

I'm testing a django app with selenium, and one of my pages uses the jquery ui tabs element. One of the tabs contains a simple table listing some users, and is loaded via ajax. When using the app, the tab works just fine, but when automating the test with selenium, the tab doesn't appear to load it's content! I'm writing the tests myself in python. At first, I was using the click method of selenium RC, but as I -painfully- learned from a previous test, that is rather buggy when it comes to anchor tags, so I resorted to the solution I used before: the wait_for_condition method and explicitly called the tab click event (and even the load event!) and nevertheless the tab was still not working!

I'm in despair here, the majority of my tests depend on that page and almost half of them are on that table, but, alas, it seems selenium is screwing up the javascript! (I have other tests in the class, and they run just fine, so nothing weird is going on at the server level, it seems to be a problem caused by selenium in the client side) My test code is similar to this:

class TestMyApp(TransactionTestCase):
urls = 'myapp.test_urls'

def setUp(self):
    self.verificationErrors = []
    self.selenium = selenium("localhost", 4444, "*chrome", "http://localhost:8000/")
    self.selenium.start()
    #self.selenium.set_speed(2000)
    self.selenium.window_maximize()
def test_users_list(self):
    """Test that an app's users are correctly listed"""
    sel = self.selenium
    users = []
    for u in range(settings.FREE_USER_LIMIT/2):
        users.append(self.app.users.create(name="testUser_%s"%uuid4()))

    sel.open("/")        
    sel.wait_for_page_to_load("30000")
    sel.wait_for_condition('selenium.browserbot.getCurrentWindow().jQuery("#tabs").tabs("select",1);\
    selenium.browserbot.getCurrentWindow().jQuery("#tabs").tabs("load",1);',
                             3000)
    for user in users:
        try: self.failUnless(sel.is_text_present(user.name))
        except AssertionError, e: self.verificationErrors.append(str(e))
        try: self.failUnless(sel.is_text_present(str(user.added.date())))
        except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
    self.selenium.stop()
    self.assertEqual([], self.verificationErrors)
+1  A: 

This could be a few things. It could be that Selenium is having trouble clicking the anchor but I actually haven't heard of that trouble and it sounds less likely. It sounds like the click() method returns OK, it doesn't give you "element not found", right? When you do the click the jquery tab javascript just isn't doing what's expected. In my experience this usually comes down to the same issue -- since Selenium executes very quickly, when javascript is rendering portions of the page and effecting the DOM continuously sometimes when Selenium goes to interact with dynamically generated parts of the page (say to click this tab), the piece it's interacting with depends on some other piece that actually hasn't fully loaded yet. It's probably microseconds away from fully loading in fact, but selenium is too fast. You already understand this of course, you have the right idea with the wait_for condition looking for the tabs to be loaded. My guess would be it's probably just not long enough. You have to find some evaluation to make that says the whole UI tabs thing is loaded and rendered. Does the tabs API have some callbacks you can add to set a "done loading" variable or does it expose a variable like that? Barring figuring out what the proper expression is to find the point in time when the UI tabs are actually ready to be clicked, which possibly could be tricky, you can resort to outright pauses to make sure the part of the page is ready to go before you interact with it. I see no problem in sleep(2), or even sleep(5), etc. in the code if it's necessary to get it to work. One way you can test that this is really what's going on is by firing up the scenario in the interactive interpreter (gotta love Python, beats the pants off of doing this in Java). Paste the code in line by line to get to the trouble point, or comment out the selenium.stop() call in your teardown method and any test code after the trouble point, so it leaves the selenium window open and exits. Then instantiate a selenium object in the interactive interpretter and hijack the open session:

selenium = selenium("localhost", 4444, "*chrome", "http://localhost:8000/")
selenium.sessionId = "0asdd234234023424foo" #Get this from the Se window

...to get interactive control of the window. Then you can see about making the selenium.click() or make selenium.get_eval('...js...') calls to investigate the javascript landscape at that point in time. My guess is when you do this, the click() will actually work fine when you type it in, because by the time you get the session loaded and get around to typing in selenium.click('blah_tab_locator'), the tab guts will all be loaded and ready to go. It's just that when Python is making the calls it does it way too fast for the browser when there are these dynamic renderings going on. If the click works fine when you do it manually through selenium like this, then you know it's a timing issue. Find that proper wait_for_condition or condescend to a python sleep(). Otherwise, if the click continues to not work when you do this, then it's probably a problem with the locator being used. The tab UI has a click or a mouseup or a focus or some kind of event handler on some part of the tab structure, maybe it's just about finding the right part of the tab to click or the right event to fire. If it isn't that then it perhaps could be as you mention some kind of strange interaction between Selenium and Jquery UI, but that would surprise me and I'd be curious to know. Poke around with get_eval() to see what's going on in the javascript if so. It sounds like a timing issue to me though.

perrierism
ipython is great for this, btw. http://ipython.scipy.org/moin/
perrierism
Nice, I actually installed ipython a few days ago and it's really cool! So, I did what you say, took it step by step patiently and found out that it was, actually *my* fault: for the tests I was using a custom URLConf (mapping for the urls in django) and the ajax call was raising -silently- a 404, so the element never did actually appear! Your answer is excellent, and surely will help me with similar issues, thanks!
lfborjas
:) Yeah no problem at all, I'm glad it helped. I've been in the same situation dozens (hundreds?) of times so I know what it's like. That sort of thing can come up frequently so I really try to minimize the troubleshooting time beforehand by being extra careful, but the ipython interactive debugging trick works wonders and saves time when the unavoidable quirks come up. I've seen engineering shops that try to do Se test suites in Java... whew, be happy for Python the interpreter!Cheers!
perrierism