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

Automating 130 browser, platform and language combinations without going insane

Automating 130 browser, platform and language combinations without going insane

Slides from my talk at Web Rebels 2012

F95abaf24e2445d1089ad5a961000382?s=128

jarib

May 25, 2012
Tweet

More Decks by jarib

Other Decks in Programming

Transcript

  1. WebDriver Web Rebels 2012 Automating 130 browser, platform and language

    combinations without going insane
  2. None
  3. WebDriver?

  4. Selenium?

  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. Selenium

  9. Selenium WTF!?

  10. Selenium Selenium Remote Control

  11. WebDriver

  12. WebDriver • Selenium 2: benefit of hindsight • Language support

    • Browser support
  13. Future • Browser automation standard • Make browser vendors care

    • Delete implementations from the Selenium tree
  14. + ~ ?

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

    drivers work • You shouldn't need to understand everything • Every API call is an RPC
  16. 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 fireEvent() Emulate the user
  17. 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
  18. 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
  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 a RPC
  20. WebDriver Internals WebDriver API WebDriver SPI wire protocol browser

  21. API user facing

  22. API user facing SPI implementor facing

  23. 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')
  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. 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
  26. 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')
  27. API object oriented, user facing SPI procedural, implementor facing

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

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

    automation atoms, native code
  30. 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
  31. Wire protocol Language binding Java Ruby C# Python JS Browser

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

    JS Browser Firefox Opera Chrome IE
  33. Wire protocol server client JSON HTTP Language binding Java Ruby

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

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

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

    JSON HTTP Language bindings Java Ruby Python C# JS Grid Node Grid Node CI server
  37. 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')
  38. 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')
  39. Wire protocol http://code.google.com/p/selenium/wiki/JsonWireProtocol

  40. Automation Atoms • Cross-browser JavaScript library • Google Closure Library

    + Compiler • Advanced compilation
  41. 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)
  42. 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, ' '); };
  43. Drivers client httpd.js wire protocol Firefox CommandProcessor JS atoms XPCOM

  44. Drivers client wire protocol chromedriver mongoose.c HTTPD JS atoms Chrome

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

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

    Scope (protobuf)
  47. Drivers client wire protocol Android Jetty HTTPD JS atoms Android

    APIs
  48. Drivers client wire protocol iPhone CocoaHTTPServer JS atoms iOS APIs

  49. Drivers WS server wire protocol (over WS) Safari WebSocket client

    JS atoms
  50. Deep dive Goal: Implement the ability to maximize the browser

    window Ruby client Firefox extension Automation atoms 1 2 3
  51. None
  52. Questions? @jarib github.com/jarib jari@finn.no

  53. github.com/holderdeord beta.holderdeord.no kontakt@holderdeord.no