$30 off During Our Annual Pro Sale. View Details »

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

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

    View Slide

  2. View Slide

  3. WebDriver?

    View Slide

  4. Selenium?

    View Slide

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

    View Slide

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

    View Slide

  7. Browser automation
    Watir
    Selenium
    WebDriver
    Selenium 2
    watir-webdriver
    2003 2004 2005 2006 2007 2008 2009 2010
    2002 2011

    View Slide

  8. Selenium

    View Slide

  9. Selenium
    WTF!?

    View Slide

  10. Selenium
    Selenium Remote Control

    View Slide

  11. WebDriver

    View Slide

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

    View Slide

  13. Future
    • Browser automation
    standard
    • Make browser vendors care
    • Delete implementations
    from the Selenium tree

    View Slide

  14. +
    ~
    ?

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  20. WebDriver Internals
    WebDriver API
    WebDriver SPI
    wire protocol
    browser

    View Slide

  21. API user facing

    View Slide

  22. API user facing
    SPI implementor facing

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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')

    View Slide

  27. API object oriented, user facing
    SPI procedural, implementor facing

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  31. Wire protocol
    Language
    binding
    Java
    Ruby
    C#
    Python
    JS
    Browser
    Firefox
    Opera
    Chrome
    IE

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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')

    View Slide

  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')

    View Slide

  39. Wire protocol
    http://code.google.com/p/selenium/wiki/JsonWireProtocol

    View Slide

  40. Automation Atoms
    • Cross-browser JavaScript library
    • Google Closure Library + Compiler
    • Advanced compilation

    View Slide

  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)

    View Slide

  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, ' ');
    };

    View Slide

  43. Drivers
    client httpd.js
    wire protocol
    Firefox
    CommandProcessor
    JS atoms
    XPCOM

    View Slide

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

    View Slide

  45. Drivers
    client
    wire protocol
    IEDriver.dll
    mongoose.c
    HTTPD
    JS atoms
    IE
    COM APIs
    COM

    View Slide

  46. Drivers
    client
    wire protocol
    OperaDriver
    Jetty
    HTTPD
    JS atoms
    Opera
    Scope
    (protobuf)

    View Slide

  47. Drivers
    client
    wire protocol
    Android
    Jetty
    HTTPD
    JS atoms Android APIs

    View Slide

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

    View Slide

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

    View Slide

  50. Deep dive
    Goal:
    Implement the ability to maximize the browser window
    Ruby client
    Firefox
    extension
    Automation
    atoms
    1 2 3

    View Slide

  51. View Slide

  52. Questions?
    @jarib
    github.com/jarib
    jari@finn.no

    View Slide

  53. github.com/holderdeord
    beta.holderdeord.no
    [email protected]

    View Slide