Difference between revisions of "Lapis Lazuli:Why use lapis lazuli over watir as a ruby test automation solution"

From Test Automation Wiki
Jump to: navigation, search
(Created page with "Lapis Lazuli is a layer on top of Watir Webdriver, so it has all the functions Watir has, and more! Often the question is asked why someone would use it, if Watir can do anyt...")
 
Line 12: Line 12:
 
<source>
 
<source>
 
button = browser.button(:text => 'NotExistingElement')
 
button = browser.button(:text => 'NotExistingElement')
=> #<Watir::Button:0x..f908e3510 located=false selector={:text=>"NotExistingElement", :tag_name=>"button"}>
+
#=> #<Watir::Button:0x..f908e3510 located=false selector={:text=>"NotExistingElement", :tag_name=>"button"}>
 
button.click
 
button.click
=> Watir::Exception::UnknownObjectException: unable to locate element, using {:text=>"sadfsad", :tag_name=>"button"}
+
#=> Watir::Exception::UnknownObjectException: unable to locate element, using {:text=>"sadfsad", :tag_name=>"button"}
 
</source>
 
</source>
 
In Watir an error is thrown after you try to interact with it instead of the moment you try to search for the element. Also, to do a customized error, you have to catch the default error with your custom text.
 
In Watir an error is thrown after you try to interact with it instead of the moment you try to search for the element. Also, to do a customized error, you have to catch the default error with your custom text.
Line 21: Line 21:
 
<source>
 
<source>
 
button = browser.find(:button => {:text => 'NotExistingElement'})
 
button = browser.find(:button => {:text => 'NotExistingElement'})
=> RuntimeError: Error in find - Cannot find elements with selectors: {:pick=>:first, :mode=>:match_one, :selectors=>[{:button=>{:text=>"NotExistingElement"}}]} [ https://www.google.nl/?gfe_rd=cr&ei=QGqgV4jRL7DH8AfVmq2IBg&gws_rd=ssl ]
+
#=> RuntimeError: Error in find - Cannot find elements with selectors: {:pick=>:first, :mode=>:match_one, :selectors=>[{:button=>{:text=>"NotExistingElement"}}]} [ https://www.google.nl/?gfe_rd=cr&ei=QGqgV4jRL7DH8AfVmq2IBg&gws_rd=ssl ]
  
 
button = browser.find(
 
button = browser.find(
Line 27: Line 27:
 
   :message => "The button was not found, but that's no problem, we didn't want to find it anyway."
 
   :message => "The button was not found, but that's no problem, we didn't want to find it anyway."
 
)
 
)
=> RuntimeError: The button was not found, but that's no problem, we didn't want to find it anyway.
+
#=> RuntimeError: The button was not found, but that's no problem, we didn't want to find it anyway.
 
button = browser.find(
 
button = browser.find(
 
   :button => {:text => 'NotExistingElement'},
 
   :button => {:text => 'NotExistingElement'},
Line 72: Line 72:
 
'''Watir'''
 
'''Watir'''
 
<source>
 
<source>
browser.
+
browser.divs(:class => 'fox').each{|elm|
 +
  if elm.id == 'red'
 +
    selection = elm
 +
  end
 +
}
 +
print selection.html
 +
# "<img src="1"/>"
 
</source>
 
</source>
  
 +
'''Lapis lazuli'''
 +
<source>
 +
selection = browser.find(
 +
  {:div => {:class => 'fox'}},
 +
  {:div => {:id => 'red'}}
 +
)
 +
print selection.html
 +
# "<img src="1"/>"
 +
</source>
  
 
===No need for wait loops===
 
===No need for wait loops===
 +
In automation, often you have to wait for an element to become visible. Either because of something loading with Javascript or a page between your last and next action.
 +
 +
''Example: We've clicked the login button and are waiting for <code><div id="login_form">(...)</div></code> to become visible.
 +
 +
'''Watir'''
 +
<source>
 +
starttime = Time.now
 +
wait_time = 60
 +
login_present = false
 +
while !login_present and Time.now-starttime<wait_time
 +
  if browser.div(:id => 'login_form').present?
 +
    login_present = true
 +
  end
 +
  sleep 0.5
 +
end
 +
unless login_present
 +
  raise "Login field did not become present after #{wait_time} seconds!"
 +
end
 +
</source>
 +
 +
'''Lapis Lazuli'''
 +
<source>
 +
browser.wait(:div => {:class => 'login_field'}
 +
</source>
 +
The above is enough. It will wait a default of 10 seconds and will show a default error if the field is not found withing the given time.
 +
A more extended version would be the following:
 +
<source>
 +
browser.wait(
 +
  :div => {:class => 'login_field',
 +
  :timeout => 60,
 +
  :message => "Login field did not become present after 60 seconds!"
 +
)
 +
</source>
 +
LL also supports <code>:condition => :while</code>, in which case it would wait as long as the element is present.
  
 
===Interaction with multiple results===
 
===Interaction with multiple results===

Revision as of 13:47, 2 August 2016

Lapis Lazuli is a layer on top of Watir Webdriver, so it has all the functions Watir has, and more!

Often the question is asked why someone would use it, if Watir can do anything they need to do automating a website. The short answer is: LL enforces the developer to use best practices over quick and dirty solutions without costing extra effort.

So what are the advantages:

Error reporting

» More detailed, can suppress error, easy customized error message.

Watir

button = browser.button(:text => 'NotExistingElement')
#=> #<Watir::Button:0x..f908e3510 located=false selector={:text=>"NotExistingElement", :tag_name=>"button"}>
button.click
#=> Watir::Exception::UnknownObjectException: unable to locate element, using {:text=>"sadfsad", :tag_name=>"button"}

In Watir an error is thrown after you try to interact with it instead of the moment you try to search for the element. Also, to do a customized error, you have to catch the default error with your custom text.

Lapis Lazuli

button = browser.find(:button => {:text => 'NotExistingElement'})
#=> RuntimeError: Error in find - Cannot find elements with selectors: {:pick=>:first, :mode=>:match_one, :selectors=>[{:button=>{:text=>"NotExistingElement"}}]} [ https://www.google.nl/?gfe_rd=cr&ei=QGqgV4jRL7DH8AfVmq2IBg&gws_rd=ssl ]

button = browser.find(
  :button => {:text => 'NotExistingElement'},
  :message => "The button was not found, but that's no problem, we didn't want to find it anyway."
)
#=> RuntimeError: The button was not found, but that's no problem, we didn't want to find it anyway.
button = browser.find(
  :button => {:text => 'NotExistingElement'},
  :throw => false
)
unless button
  #Do something else
end

In Lapis Lazuli the default error already contains 'readable text', an automatic screenshot is taken and the URL is shown where the problem occurred. Besides that, it's also easy to customize the error message to your own likes. If a not-found element is not necessarily an issue, you can simply suppress the error with :throw => false

Finding elements

Prevents using regular expressions (quicker)

Watir

browser.goto 'tweakers.net'
browser.as(:class => /e/).length
# Returns 111 after 3 seconds

Lapis Lazuli

browser.goto 'tweakers.net'
browser.find_all(:like => [:a, :class, 'e']).length
# Returns 111 after 0.5 seconds

Lapis Lazuli provides the :like functionality, which is handy for multiple purposes. In the above it enables us to look for elements that include the letter "e" rather than using a regular expression. Doing this using a lot less processing (600%!). On a small scale it might not matter much, but on a larger projects, these seconds can mean 2 hours of running versus 15 minutes.

Easier to match on multiple attributes

HTML

<div class="fox" id="red"><img src="1"/></div>
<div class="fox" id="blue"><img src="2"/></div>
<div class="fence" id="red"><img src="3"/></div>
<!-- I know, an ID that's no unique, like that ever happens!? :-) -->

» Select the div with image src="1"

Watir

browser.divs(:class => 'fox').each{|elm|
  if elm.id == 'red'
    selection = elm
  end
}
print selection.html
# "<img src="1"/>"

Lapis lazuli

selection = browser.find(
  {:div => {:class => 'fox'}},
  {:div => {:id => 'red'}}
)
print selection.html
# "<img src="1"/>"

No need for wait loops

In automation, often you have to wait for an element to become visible. Either because of something loading with Javascript or a page between your last and next action.

Example: We've clicked the login button and are waiting for

(...)

to become visible.

Watir

starttime = Time.now
wait_time = 60
login_present = false
while !login_present and Time.now-starttime<wait_time
  if browser.div(:id => 'login_form').present?
    login_present = true
  end
  sleep 0.5
end
unless login_present
  raise "Login field did not become present after #{wait_time} seconds!"
end

Lapis Lazuli

browser.wait(:div => {:class => 'login_field'}

The above is enough. It will wait a default of 10 seconds and will show a default error if the field is not found withing the given time. A more extended version would be the following:

browser.wait(
  :div => {:class => 'login_field',
  :timeout => 60,
  :message => "Login field did not become present after 60 seconds!"
)

LL also supports :condition => :while, in which case it would wait as long as the element is present.

Interaction with multiple results

Can look for custom attributes

Debugging

Just as simple to start in IRB

Simple remote testing

Build in screenshot system

Project level

Build in Configuration variables