Post on 21-Jan-2018
Application Testing
• Don’t need to change source code
• Can test (almost) anything
• Less focused than unit testing
Supported Languages
• Official:
• Java, C#, Ruby, Python, JavaScript
• Community:
• perl, php, Haskell, Objective-C
Sample Driver Coderequire 'selenium-webdriver' !driver = Selenium::WebDriver.for :firefox driver.navigate.to "https://duckduckgo.com/" !!driver.find_element(:id, 'search_form_input_homepage') .send_keys("webdriver") !driver.find_element(:id, 'search_button_homepage') .click !puts "Search page title = #{driver.title}" !driver.quit
Online Resources
• Ruby Selenium Wiki: https://code.google.com/p/selenium/wiki/RubyBindings
• Selenium Ruby API: http://selenium.googlecode.com/git/docs/api/rb/index.html
Main Classes
# Create a driver for Firefox driver = Selenium::WebDriver.for :firefox !# Create a driver for Safari driver = Selenium::WebDriver.for :safari !# If your FF is installed in a non-default location # Use this before creating the driver Selenium::WebDriver::Firefox.path = "/path/to/firefox"
WebDriver Functions# Load a web page driver.navigate.to "http://www.google.com" !# Returns page title driver.title !# Returns HTML page source driver.page_source !# Call a JS function driver.execute_script("alert('hello world');") !# Quit the browser driver.quit
Web Element
• Query and interact with elements on the page
• Both visual and functional
• Get using a locator
Locating Web Elements# Get an element on the page # By name el = driver.find_element(:name, 'btnK') !# By css selector el = driver.find_element(:css, '.menu-item') !# By id el = driver.find_element(:id, 'login-form') !# By xpath el = driver.find_element(:xpath, "//h2[@class='title']")
Web Element
• Visual Methods:
el = driver.find_element(:css, '.menu-item') !# Get the location of the element # (top-left corner) el.location !# Get size of an element el.size !# Bool: is element visible el.displayed?
Web Element• Functional Methods# Get attribute value el.attribute('id') !# Get inner text value el.text !# Mouse click on the element el.click !# Focus and send keyboard presses el.send_keys('hello')
RSpec 1 require 'person'! 2 ! 3 describe 'Person' do! 4 describe '#grow_up' do! 5 it "should increase a persons's age" do! 6 p = Person.new(10)! 7 p.grow_up! 8 ! 9 expect(p.age).to eq(11)!10 end!11 end!12 end!
Running RSpec
• Save your code in lib/
• Save your spec in spec/
• Just type rspec
1 " Press ? for help!2 !3 .. (up a dir)!5 ▾ lib/!6 Person.rb!7 ▾ spec/!8 person_spec.rb!
Sauce Cloud Demo
• Use ruby-sauce gem
• Specify all browsers in Config
1 require 'sauce'! 2 ! 3 Sauce.config do |c|! 4 c[:browsers] = [! 5 ["Windows 7","Firefox","18"],! 6 ]! 7 end! 8 ! 9 # s / selenium are automatically available!10 # inside the test!11 describe 'Testing Google', :sauce => :true do!12 it 'should be Google' do!13 s.navigate.to('http://www.google.com')!14 expect(s.title).to eq('Google')!15 end!16 end!
Demos
• Let’s test duckduckgo’s title for the input search string (http://duckduckgo.com/)
• Let’s test designmodo’s siedbar disappears on small screen (http://designmodo.com/)
RSpec Hooks
• Use hooks for setup/teardown code
• before(:each), before(:all), after(:each) and after(:all)
describe Thing do! before(:each) do! @thing = Thing.new! end!! describe "initialized in before(:each)" do! it "has 0 widgets" do! expect(@thing.widgets.count).to eq(0)! end!! it "can get accept new widgets" do! @thing.widgets << Object.new! end!! it "does not share state across examples" do! expect(@thing.widgets.count).to eq(0)! end! end
Target Locator
• Selenium driver is “focused” on a single frame or modal dialog
• Change active frame using switch_to
Target Locator
1 frame = driver.find_elements(:css, 'iframe').first!2 !3 driver.switch_to.frame(frame['id'])!4 element = driver.find_element(:css, 'button')!5 element.click!6 !7 alert = driver.switch_to.alert!8 puts alert.text!9 alert.accept!
Demo URL: http://jsfiddle.net/Wchm5/embedded/result/
Explicit Waits
• When async JS is involved, you may need to wait for state change
• Selenium has a Wait object
Explicit Wait# Create a wait object with 30 seconds timeout wait = Selenium::WebDriver::Wait.new( :timeout => 30 ) !driver.find_element(:name, 'q').send_keys('webdriver') driver.find_element(:name, 'btnK').click !# Page title is not yet changed # so this just prints google puts driver.title !# So we wait... wait.until { driver.title != 'Google' } !# And now get the right value puts driver.title
Selenium Actions# Use method chaining to describe the sequence, # and perform to execute !# Move mouse to el1 center and click driver.action.move_to(el1).click.perform !# Press and hold shift, move mouse to el1 and click # then move mouse to second_element and click again # release shift key, and drag element to third_element driver.action.key_down(:shift). click(el1). click(second_element). key_up(:shift). drag_and_drop(element, third_element). perform
Live Demo #1
• Enter AccuWeather
• Check weather for Tel Aviv
• Make sure (F) and (C) match
• Use SaucaLabs to run on multiple browsers
Takeaways
• Wrap website access in your own ruby class (which uses Selenium)
• Aim for short test specs