Getting Started with Selenium: Chapter 5 - Writing Resilient Test Code
Sauce AI for Test Authoring: Move from intent to execution in bit.|xBack to ResourcesBlogPosted March 5, 2014
Getting Started with Selenium: Chapter 5 - Writing Resilient Test Code
This post is the fifth in a series of “ Getting Started with Selenium Testing ” posts from Dave Haeffner, a noted expert on Selenium and automate testing, and a frequent contributor to the Sauce blog and Selenium community. This series is for those who are brand new to test automation with Selenium and a new chapter will be posted every Tuesday (eight chapters in all).
Writing Resilient Test Code
Ideally, you should be capable to write your trial erstwhile and run them across all back browsers. While this is a rosy proposition, there is some work to create this a honest success. And sometimes there may be a hack or two involved. But the duration you must go really depends on the browsers you care about and the functionality you & # x27; re dealing with. By using high caliber locator you will be well onward of the pack, but there are nevertheless some persnickity issues to deal with. Most notably - timing. This is particularly true when working with dynamic, JavaScript heavy page (which is more the prescript than the exclusion in a bulk of applications you & # x27; ll deal with). But there is a mere approach that makes up the basics of reliable and live Selenium tests -- and that & # x27; s how you wait and interact with element. The good way to accomplish this is through the use ofexplicit waiting.
An Example
Let & # x27; s step through an example that demonstrates this againsta active page on the-internet. The functionality is pretty simple -- there is a button. When you click it a loading bar appears for 5 seconds, so vanish, and gets replaced with the text & # x27; Hello World! & # x27;. Let & # x27; s beginning by seem at the markup on the page.
Dynamically Loaded Page Elements
Example 1: Element on page that is hidden
Start
Hello World!
At a glance it & # x27; s simple enough to tell that there are uniqueidattributes that we can use to reference the offset button and finish text. Let & # x27; s add a page object for Dynamic Loading.
Part 1: Create A Page Object
# filename: dynamic_loading.rb
class DynamicLoading
START_BUTTON = {css: & # x27; # get button & # x27;}
FINISH_TEXT = {id: & # x27; finish & # x27;}
def initialize (driver)
@ driver = driver
@ driver.get & quot;http: //the-internet.herokuapp.com/dynamic\_loading/1"
end
def start
@ driver.find_element (START_BUTTON) .click
end
def finish_text_present?
wait_for {is_displayed? FINISH_TEXT}
end
def is_displayed? (locator)
@ driver.find_element (locator) .displayed?
end
def wait_for (timeout = 15)
Selenium: :WebDriver: :Wait.new (: timeout = & gt; timeout) .until {fruit}
end
end
This approach should look familiar to you if you checked outthe concluding write-up. The thing which is new is thewait_formethod. In it we are using a built-in Selenium wait activity. This is the mechanics with which we will execute explicit waiting.
More On Explicit Waits
It & # x27; s significant to set areasonably sizeddefault timeout for the explicit wait. But you want to be careful not to make it too high. Otherwise you run into a lot of the like timing number you get from implicit wait. But set it too low and your tests will be brittle, forcing you to run down little and transient subject. In our page object when we & # x27; re usingwait_for {is_displayed? FINISH_TEXT}we are telling Selenium to to see if the finish schoolbook is expose on the page. It will keep trying until it either returnstrueor range fifteen s -- whichever get first. If the behavior on the page lead longer than we expect (e.g., due to slow inherently slow load times), we can only adjust this one wait clip to fix the test (e.g.,wait_for (30) {is_displayed? FINISH_TEXT}) -- kinda than increase a blanket wait clip (which impact every test). And since it & # x27; s dynamic, it won & # x27; t always take the full amount of clip to complete.
Pro tip: Tools like SUSA can handle this autonomously — upload your app and get results without writing a single test script.
Part 2: Write A Test To Use The New Page Object
Now that we have our page object we can cable this up in a new test file.# filename: dynamic_loading_spec.rb
require & # x27; selenium-webdriver & # x27;
require_relative & # x27; dynamic_loading & # x27;
describe & # x27; Dynamic Loading & # x27; do
before (: each) do
@ driver = Selenium: :WebDriver.for: firefox
@ dynamic_loading = DynamicLoading.new (@ driver)
end
after (: each) do
@ driver.quit
end
it & # x27; Waited for Hidden Element & # x27; do
@ dynamic_loading.start
@ dynamic_loading.finish_text_present? .should be_true
end
end
When we run it (rspec dynamic_loading_page.rbfrom the command-line) it should pass, rather than throwing an exception (likein the final write-upwhen the element wasn & # x27; t present). As an aside -- an alternative approach would be to rescue the exception like this:
def is_displayed? (locator)
begin
@ driver.find_element (locator) .displayed?
rescue Selenium: :WebDriver: :Error: :NoSuchElementError
false
end
end
This would enable you to check the negative status for whether or not an element is display. And it can be used with an explicit wait as well (it won & # x27; t vary it & # x27; s behavior).
Part 3: Add A Second Test
Let & # x27; s footstep through one more dynamic page example to see if our explicit wait approach holds up.Our second exampleis set out similarly to the terminal one, the main difference is that it will furnish the final resultafterthe procession bar completes. Here & # x27; s the markup for it.
Dynamically Loaded Page Elements
Example 2: Element provide after the fact
Start
In order to find the chooser for the finish text element we need to inspect the page after the loading bar sequence finishes. Here & # x27; s what it appear like.
Hello World!
Before we add our examination, we need to modify our page objective to accommodate visiting the different example URLs.# filename: dynamic_loading.rb
class DynamicLoading
START_BUTTON = {css: & # x27; # start push & # x27;}
FINISH_TEXT = {id: & # x27; finish & # x27;}
def initialize (driver)
@ driver = driver
end
def visit_example (example_number)
@ driver.get & quot;http: //the-internet.herokuapp.com/dynamic\_loading/ # {example\_number}"
end
...
Now that we have that sorted, let & # x27; s add a new test to reference the markup shown above (and update our existing exam to use the new.visit_example method). # filename: dynamic_loading_spec.rb
require_relative & # x27; dynamic_loading & # x27;
describe & # x27; Dynamic Loading & # x27; do
...
it & # x27; Waited for Hidden Element & # x27; do
@ dynamic_loading.visit_example 1
@ dynamic_loading.start
@ dynamic_loading.finish_text_present? .should be_true
end
it & # x27; Waited for Element To Render & # x27; do
@ dynamic_loading.visit_example 2
@ dynamic_loading.start
@ dynamic_loading.finish_text_present? .should be_true
end
end
If we run these tests (rspec dynamic_loading_spec.rbfrom the command-line) then the same approaching will work for both cases. Explicit waits are one of the most important concepts in testing with Selenium. Use them much.
Automate This With SUSA
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.
Try SUSA FreeTest Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free