Asynchronous delays are the second biggest automation issue you need to nail down in your environment—locators/find logic being the first. Asynch operations cause all kinds of grief for even experienced automators. It can be extraordinarily frustrating to try and figure out exactly which thing you need to delay your test script’s execution for.
I’ve said it once, I’ve said it a thousand times: DO NOT EVER rely on execution delays, manual pauses, or Thread.Sleep() to handle your tests’ timing issues. Ever. Period. (OK, maybe once in an extreme situation. I’ve written tens of thousands of UI tests. I’ve justifiably used an execution delay perhaps two or three times in the last five years. Just don’t do it, OK?)
Instead, figure out exactly what condition you need to move forward with your test, then create an explicit wait for that condition. This is a rock-solid pattern that works in nearly every situation. Again, figure out the state or condition your test needs and craft a wait explicitly for that condition.
Here’s a practical example for you using Telerik’s neat demo of our RadComboBox. This is a totally common flow: the page loads and the user clicks in the combo box. At this point there’s an AJAX call back to the server and the user sees the “Loading…” feedback while the call’s completing.
Once the call’s completed the user sees the contents of the combo box rendered.
Remember the basic page flow: when the page itself loads, the browser sets a “STOP!” flag on the page DOM. Automation tools like Test Studio, WebDriver, etc., all monitor that flag and pause their scripts’ execution until the DOM’s loaded and the browser clears the flag.
AJAX and other asynchronous operations are different, though. They don’t set/clear that same flag, so the automation tool has no idea it needs to pause. As a result, subsequent actions like selections and validations fail because the content hasn’t yet returned from the server and been rendered in the browser. I often use the example of my impatient 12 year old daughter blasting through things without caring whether they’re ready or not.
Following my rule above, let’s look at how we can successfully automate a test here and use a couple different wait conditions to meet our needs. We’ll also throw in some flexible find logic to help you along.
Open Test Studio, create a new project and test, and point your recorder at http://demos.telerik.com/aspnet-ajax/combobox/examples/overview/defaultcs.aspx. Remember the first action is a navigation action with is a page load—Test Studio (and other tools) will patiently wait until your browser’s ready to carry on.
For our first example we’re just going to verify something is loaded in the combobox. It’s a simple, straightforward test you might use to just validate the control’s wired up properly.
Once the page is loaded you’ll need to explicitly add a Left Mouse Click event to the proper box—Clicking in the box during recording simply sets focus there for input. Highlight the element and select Mouse Actions | Left Mouse Click | Center. (Please note the image below is a composite. No, you won’t see all those options in one go!)
Now go ahead and actually click in that field—this will start the AJAX callback. Wait until the contents actually load—the “Loading…” indicator is done and the list populates.
Now let’s build a good validation that we’ll use for a wait condition. For our current case we only care that some content is in the list. There are a couple ways to approach this, but I’m just going to add a text validation on the first row, then change that to a wait condition.
In this case, we want to simply validate the first row has some text in it. This is one of the few places a Regular Expression makes perfect sense to use, so we’ll set up a validation with RegEx as our compare type.
This regex simply looks for at least one word-type character in the element. (Regular expressions are far beyond the scope of this blog post. They’re a wonderful tool for developers and testers to use, so I highly recommend you get a copy of Jeff Friedl’s Mastering Regular Expressions.)
Change that validation’s role to a Wait, then run the test to make sure things pass.
Right now this test’s locator is likely not a great one. If you inspect the element’s Find Logic, you’ll likely see it’s something very brittle—in this case it’s totally dependent on the inner text of the first list item. This will break instantly the first time there’s some other text, or if we can’t find that text at all.
Let’s get something more appropriate in place. Generally, I prefer to not use position-based locators in find logic because they can cause your tests to needlessly break if your underlying data changes. That said, in this case we want to always inspect the first row of that ComboBox’s list!
Here’s what one approach for this looks like when viewed in the Edit Element UI:
(If you haven’t already, please have a look at my blogpost on Flexible Find Logic, plus watch the video on it!)
Make those changes, then please rename the element to something sensible and clear for you. At this point the test looks something roughly like this:
Now let’s take this a second step and work on a search using the ComboBox. In this case we’re going to validate when we search for “Chef” we get the appropriate returned value for the first item.
Record a step entering “Chef” in the combo box, or use the Step Suggestions to add a “Enter text…” step to your test and update it appropriately.
At this point there are various options, all of which hinge on how you want to approach your test case design. You could re-use the existing element we tailored for the first row, or you could create an entire new element using the same approach but basing it off the InnerText value of the appropriate value. (“Chef Anton’s Cajun Seasoning”)
I’m going for simplicity for this example, so we’ll re-use the existing element and set it up as a verify, then change its role to an explicit wait. Start with the Step Suggestions menu again and add a verify for the first row element.
Update the Verify step with the text “Cajun Seasoning” and make sure to change the comparison scope to InnerText from TextContent, otherwise your test won’t work since it’s looking at the incorrect scope. Ask me how I know this…
At this point your test should look pretty much like this, and pass successfully:
We’ve covered quite a bit in this post, so focus in on the key points:
Jim Holmes is the Director of Engineering for Test Studio. He has around 25 years IT experience. He's a blogger and the co-author of "Windows Developer Power Tools" and Chief Cat Herder of the CodeMash Conference. Find him as @aJimHolmes on Twitter.