Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WebDriver Internals - Test Automation Bazaar

jarib
March 24, 2012

WebDriver Internals - Test Automation Bazaar

Slides from my talk at the Test Automation Bazaar in Austin, TX. March 2012.

jarib

March 24, 2012
Tweet

More Decks by jarib

Other Decks in Programming

Transcript

  1. WebDriver Internals Test Automation Bazaar 2012

  2. Who am I? • Senior Test Engineer at FINN.no •

    Engineering Productivity team • Norway’s largest online marketplace • 900 million page views / month • 4 million unique users / month
  3. Who am I? @jarib http://github.com/jarib [email protected]finn.no

  4. Who am I?

  5. Browser automation Watir Selenium WebDriver 2003 2004 2005 2006 2007

    2008 2009 2010 2002 2011
  6. Browser automation Watir Selenium WebDriver 2003 2004 2005 2006 2007

    2008 2009 2010 2002 2011
  7. Browser automation Watir Selenium WebDriver Selenium 2 Watir-Webdriver 2003 2004

    2005 2006 2007 2008 2009 2010 2002 2011
  8. WebDriver • Selenium 2: benefit of hindsight • design goal:

    small, object-oriented API • native code when needed, JavaScript elsewhere • still leverage HTTP as a transport • Language support • Java, Ruby, Python, C#, JavaScript, (PHP, Perl) • Browser support • Firefox, Chrome, Opera, IE, Safari, iOS, Android, HtmlUnit
  9. Selenium

  10. WebDriver

  11. Architectural themes • Emulate the user • Prove that the

    drivers work • You shouldn't need to understand everything • Every API call is an RPC
  12. Architectural themes Emulate the user

  13. Architectural themes • Designed to accurately emulate user interaction with

    a web application • Use native events where possible... • ...but make it easy to do cross-browser • API should match user interactions • e.g. no #fire_event Emulate the user
  14. Architectural themes Prove the drivers work

  15. Architectural themes • Extensive automated test suite • Mostly integration

    tests • Strong culture for adding tests when fixing bugs • Challening CI setup • 6 browsers on 3 OSes with 4 languages • 72 builds per commit Prove the drivers work
  16. Architectural themes You shouldn't need to understand how everything works

  17. Architectural themes • Lots of languages / technologies in use

    • Architecture should allow developers to focus their talents where they'll be most productive You shouldn't need to understand how everything works
  18. Architectural themes Every API call is an RPC

  19. Architectural themes • Need to communicate with external browser process

    • Performance at the mercy of network latency • Introduces tension in the API design • Coarseness (== improved performance) • Expressiveness, ease of use Every API call is an RPC
  20. Future • Browser automation standard • Make browser vendors to

    care • Delete implementations from the Selenium tree
  21. WebDriver Internals WebDriver API WebDriver SPI JSON wire protocol Browser

  22. API user facing

  23. API user facing SPI implementor facing

  24. API command –> { name: "findElement", parameters: { using: "name",

    value: "q" } } response <– { status: 0, value : <opaque element identifier> } command –> { name: "sendKeys", parameters: { element: <opaque element identifier>, value: ["webdriver"] } } response <– { status: 0 } SPI driver.find_element(name: 'q').send_keys('webdriver')
  25. API command –> { name: "findElement", parameters: { using: "name",

    value: "q" } } response <– { status: 0, value : <opaque element identifier> } command –> { name: "sendKeys", parameters: { element: <opaque element identifier>, value: ["webdriver"] } } response <– { status: 0 } SPI driver.find_element(name: 'q').send_keys('webdriver')
  26. driver.find_element(name: 'q').send_keys('webdriver') API command –> { name: "findElement", parameters: {

    using: "name", value: "q" } } response <– { status: 0, value : <opaque element identifier> } command –> { name: "sendKeys", parameters: { element: <opaque element identifier>, value: ["webdriver"] } } response <– { status: 0 } SPI
  27. API object oriented SPI procedural newSession(browser: 'firefox') findElement(using: 'name', value:

    'q') sendKeysToElement(id: '00cbe31e', value: ['webdriver']) getElementAttribute(id: '00cbe31e', name: 'value') driver = Selenium::WebDriver.for :firefox input = driver.find_element(name: 'q') input.send_keys('webdriver') puts input.attribute('value')
  28. API object oriented, user facing SPI procedural, implementor facing

  29. API SPI wire protocol browser automation atoms, native code

  30. API SPI browser automation standard reference implementation wire protocol browser

    automation atoms, native code
  31. Wire protocol • Reference implementation of the Service Provider Interface

    (SPI) • In spec terms, non-normative (not a requirement for implementors) • Though comes with some benefits • e.g. existing clients in multiple languages
  32. Wire protocol Language binding Java Ruby C# Python Browser Firefox

    Opera Chrome IE
  33. Wire protocol JSON HTTP Language binding Java Ruby C# Python

    Browser Firefox Opera Chrome IE
  34. Wire protocol JSON HTTP Language binding Java Ruby C# Python

    Browser Firefox Opera Chrome IE server client
  35. Wire protocol Machine A JSON HTTP Language binding Java Ruby

    C# Python Browser Firefox Opera Chrome IE
  36. Wire protocol JSON HTTP Machine B Remote WebDriver Server JSON

    HTTP Browser Firefox Opera Chrome IE Machine A Language bindings Java Ruby Python C#
  37. Wire protocol Selenium 2 Grid Hub JSON HTTP Grid Node

    JSON HTTP Language bindings Java Ruby Python C# Grid Node Grid Node CI server
  38. Wire protocol Maps SPI commands to RESTish HTTP resources POST

    /session POST /session/:sessionId/element POST /session/:sessionId/element/:id/value GET /session/:sessionId/element/:id/attribute/:name newSession(browser: 'firefox') findElement(sessionId: 'c688f8e4', using: 'name', value: 'q') sendKeysToElement(id: '00cbe31e', value: ['webdriver']) getElementAttribute(id: '00cbe31e', name: 'value')
  39. Wire protocol Maps SPI commands to RESTish HTTP resources POST

    /session POST /session/c688f8e4/element POST /session/c688f8e4/element/00cbe31e/value GET /session/c688f8e4/element/00cbe31e/attribute/value newSession(browser: 'firefox') findElement(sessionId: 'c688f8e4', using: 'name', value: 'q') sendKeysToElement(id: '00cbe31e', value: ['webdriver']) getElementAttribute(id: '00cbe31e', name: 'value')
  40. Wire protocol http://code.google.com/p/selenium/wiki/JsonWireProtocol

  41. Automation Atoms • Shared JavaScript library • Google Closure Compiler

    / Library • Advanced compilation
  42. Automation Atoms JavaScript Atoms (built on Google Closure Library) Google

    Closure Compiler Firefox extension (atoms.js) ChromeDriver (atoms.h) IE driver (atoms.h) Opera driver (OperaAtoms.java)
  43. Automation Atoms /** * @param {!Element} elem The element to

    consider. * @return {string} visible text. */ bot.dom.getVisibleText = function(elem) { var lines = []; bot.dom.appendVisibleTextLinesFromElement_(elem, lines); lines = goog.array.map( lines, bot.dom.trimExcludingNonBreakingSpaceCharacters_); var joined = lines.join('\n'); var trimmed = bot.dom.trimExcludingNonBreakingSpaceCharacters_(joined); // Replace non-breakable spaces with regular ones. return trimmed.replace(/\xa0/g, ' '); };
  44. Drivers client JS HTTPD wire protocol Firefox Dispatcher / Command

    Processor JS atoms XPCOM
  45. Drivers client wire protocol chromedriver mongoose.c HTTPD JS atoms Chrome

    Automation Proxy IPC
  46. Drivers client wire protocol IEDriver.dll mongoose.c HTTPD JS atoms IE

    COM APIs COM
  47. Drivers client wire protocol OperaDriver Jetty HTTPD JS atoms Opera

    Scope (protobuf)
  48. watir-webdriver • Watir implementation on WebDriver • Started 2009 •

    http://watirwebdriver.com/ • http://github.com/watir/watir-webdriver
  49. watir-webdriver selenium-webdriver driver = Selenium::WebDriver.for :firefox browser = Watir::Browser.new(driver)

  50. selenium-webdriver watir-webdriver >> driver.find_element(:id => "country") => #<Selenium::WebDriver::Element:0x..fa93ee tag_name="select"> >>

    browser.select_list(:id => "country") => #<Watir::Select:0x..fa349d located=false selector={:id=>"country", :ta >> d.text_field(:name => "user") => #<Watir::TextField:0x..fb63099fd1e2f6130 located=false selector={:name
  51. Watir::Anchor Watir::Applet Watir::Area Watir::Audio Watir::BR Watir::Base Watir::BaseFont Watir::Body Watir::Button Watir::Canvas

    Watir::CheckBox Watir::Command Watir::DList Watir::DataList Watir::Details Watir::Device Watir::Directory Watir::Div Watir::Embed Watir::FieldSet Watir::FileField Watir::Font Watir::Form Watir::Frame Watir::FrameSet Watir::HR Watir::HTMLElement Watir::Head Watir::Heading Watir::Hidden Watir::Html Watir::IFrame Watir::Image Watir::Input Watir::Keygen Watir::LI Watir::Label Watir::Legend Watir::Map Watir::Marquee Watir::Media Watir::Menu Watir::Meta Watir::Meter Watir::Mod Watir::OList Watir::Object Watir::OptGroup Watir::Option Watir::Output Watir::Paragraph Watir::Param Watir::Pre Watir::Progress Watir::Quote Watir::Radio Watir::Script Watir::Select Watir::Source Watir::Span Watir::Style Watir::Table Watir::TableCaption Watir::TableCell Watir::TableCol Watir::TableDataCel Watir::TableHeaderC Watir::TableRow Watir::TableSection Watir::TextArea Watir::TextField Watir::Time Watir::Title Watir::Track Watir::UList Watir::Unknown Watir::Video
  52. Ruby code generated from the HTML spec module Watir class

    Meter < HTMLElement attributes( :float => [:value, :min, :max, :low, :high, :optimum], :html_element => [:form], :list => [:labels] ) end end
  53. Voter turnout: <meter id=turnout value=0.75>75%</meter> >> meter = browser.meter(:id =>

    "turnout") #=> #<Watir::Meter:0x3ebf128988f2b418 located=false selector={: >> meter.value #=> 0.75 >> meter.value.class #=> Float
  54. Comparison with Watir 1 • Supports all browsers available in

    WebDriver • Mostly compatible API-wise. Some major changes: • 0-indexed instead of 1-indexed • All HTML elements supported • Revised table API • New window switching API • Collection methods can take locator arguments https://github.com/watir/watir-webdriver/wiki/Comparison-with-Watir-1.X
  55. Demo Goal: Implement the ability to maximize the browser window

    Step 1: selenium-webdriver Firefox Step 2: watir-webdriver browser.window.maximize
  56. Getting involved • Ask for help and input early •

    Keep the change small • Write tests
  57. Getting involved • Mailing lists: • wtr-development • selenium-developers •

    IRC: • irc.freenode.net (#watir or #selenium) • Code: • http://code.google.com/p/selenium/ • https://github.com/watir/watir-webdriver
  58. Questions?