views:

1097

answers:

3

I have two dropdown lists, one containing a list of countries and one for states/regions that is not populated until one of the countries is selected. Both of these dropdowns are wrapped in an updatepanel. When I select the USA, the state dropdown list is filled with the 50 states and I am able to move forward from there.

We are using Selenium to run tests on this code, and the tests always break when it reaches the state dropdown. It either takes too long to generate the state list, or perhaps it just can't find the values since they are not in the initial html that is rendered. I've seen some things about a javascript "WaitForCondition" field, but can't find any details about how to use this in the selenium documentation. I'm not a javascript slouch, but am not the greatest with it either. Can anyone explain to me how you might go about solving my dilemma, and if it happens to require knowledge of how the WaitForCondition field, can you explain to me how I can get that to work?

For the record, I have seen this post: (click here for semi-useful stackoverflow post) but I do not understand how to relate it to my own situation. Thanks in advance for anything you can give me.

+4  A: 

Hi Shizbiz,

Are you using Selenium IDE? This makes it very easy to write your code and then export it to the language you're using with Selenium RC.

In Selenium IDE, you'll find a method called "waitForText". This method takes an element locator as an the argument and a string as the value. Your locator would be the id of the state dropdown list (or a css selector if it has a dynamic id). For the value, use something that is present in the dropdown only after it is loaded (the last US state in the list is probably the best choice).

Let me know if you need any clarification or additional detail.

Regards, Mark

Mark Erdmann
I do have Selenium IDE. Your solution actually does work in an extremely weird (and not acceptable) way. The waitForText method searches for the value in question, does not find it, and ultimately times out. But because it waited so long to time out, that failure ultimately allows enough time to pass for the IDE to recognize that the dropdown has been populated and the statement that selects the option now finds the value it wants.
shizbiz
+1  A: 

So it turns out I have found the solution to my own problem.

I used the following line in my C# tests and it finds the value in my dropdown list instantly:

selenium.WaitForCondition("var ddl = selenium.browserbot.getCurrentWindow().document.getElementById('insert-id-of-dropdownlist-here'); ddl.options[ddl.selectedIndex].text == 'insert-text-value-to-search-for-in-dropdown-here';", "10000");

In the IDE I used the following parameters:

Command: waitForCondition

Target: var ddl = selenium.browserbot.getCurrentWindow().document.getElementById('insert-id-of-dropdownlist-here'); ddl.options[ddl.selectedIndex].text == 'insert-the-text-value-to-search-for-in-dropdown-here';

Value: 10000

This is the page that ultimately helped me figure out the solution: http://wiki.openqa.org/display/SEL/waitForCondition

shizbiz
Thank you for the interesting solution. I wasn't familiar with waitForCondition before reading the above code. I guess now the question is: which is the easiest to maintain? A few lines of javascript, or the clunky `for` loops that Selenium exports when you use the wait methods. :-) I'd generally go with the `for` loop so that it's easier for novice programmers to maintain my tests, but I'd be interested in hearing your opinion.
Mark Erdmann
There is no question the javascript is a pain. I hope I don't have to use this solution often, but it does execute extremely quickly and it does solve my problem. We ultimately are going to have an very large number of these unit tests, so speed is highly valued here, much more than code readability. But I definitely see where you are coming from. Thanks for your help here.
shizbiz
+1  A: 

Sorry, it was hard to test my code without having the actual page in front of me. The problem might be that each state is an option element under the select element (or maybe you're using a javascript framework that handles this differently?). If you have option elements, you could use this:

waitForElement | css=option:contains('someState')

which exports as:

for (int second = 0;; second++) {
       if (second >= 60) Assert.Fail("timeout");
       try
       {
        if (selenium.IsElementPresent("css=option:contains('someState')")) break;
       }
       catch (Exception)
       {}
       Thread.Sleep(1000);
      }
Mark Erdmann