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

WebDriver Internals

jarib
February 28, 2012

WebDriver Internals

Slides from my presentation at SeleniumCamp 2012 in Kiev

jarib

February 28, 2012
Tweet

More Decks by jarib

Other Decks in Programming

Transcript

  1. 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
  2. Watir • Nice API • Native control over IE (using

    COM) + - • Ruby only • IE only (thus Windows only) • Internals not pretty
  3. Selenium • Jason Huggins @ Thoughtworks • Needed to test

    in-house Time and Expenses app • Open source release in 2004
  4. Selenium • Languages: Java, Python, C#, Ruby ++ • Core

    written in JavaScript • Supports "all" browsers + - • Restricted by JS sandbox • Bloated, procedural API • Complicated architecture
  5. Selenium public void testNew() throws Exception { selenium.open("/"); selenium.type("q", "selenium

    rc"); selenium.click("btnG"); selenium.waitForPageToLoad("30000"); assertTrue(selenium.isTextPresent("Results * for selenium rc")); }
  6. Selenium selenium.open "/" selenium.type 'q', 'selenium' puts selenium.title POST /selenium-server/driver/?cmd=open&1=%2F&sessionId=24f8bcc

    POST /selenium-server/driver/?cmd=type&1=q&2=selenium&sessionId=24f8bcc POST /selenium-server/driver/?cmd=getTitle&sessionId=24f8bcc
  7. WebDriver • 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#) • Browser support • Firefox, Chrome, Opera, IE, iPhone, Android
  8. Architectural themes • Emulate the user • Prove that the

    drivers work • You shouldn't need to understand everything • Every API call is an RPC
  9. 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
  10. 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
  11. 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
  12. 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) vs expressiveness and ease of use Every API call is an RPC
  13. driver.findElement(By.name("q")).sendKeys("webdriver"); API command –> { command : "findElement", parameters: {

    using: "name", value: "q" } } response <– { status: 0, value : <opaque element identifier> } command –> { command: "sendKeys", parameters: { element: <opaque element identifier>, value: ["webdriver"] } } response <– { status: 0 } SPI
  14. API command –> { command : "findElement", parameters: { using:

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

    "name", value: "q" } } response <– { status: 0, value : <opaque element identifier> } command –> { command: "sendKeys", parameters: { element: <opaque element identifier>, value: ["webdriver"] } } response <– { status: 0 } driver.findElement(By.name("q")).sendKeys("webdriver"); SPI
  16. API object oriented SPI procedural WebDriver driver = new FirefoxDriver();

    WebElement input = driver.findElement(By.name("q")); input.sendKeys("webdriver"); input.getAttribute("value"); newSession(browser: 'firefox') findElement(using: 'name', value: 'q') sendKeysToElement(id: '00cbe31e', value: ['webdriver']) getElementAttribute(id: '00cbe31e', name: 'value')
  17. Wire protocol • Reference implementation of the Service Provider Interface

    (SPI) • In spec terms, not a requirement for implementors • Though comes with some benefits • e.g. existing clients in multiple languages
  18. Wire protocol JSON HTTP Language binding Java Ruby C# Python

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

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

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

    JSON HTTP Language bindings Java Ruby Python C# Grid Node Grid Node CI server
  22. 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')
  23. 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')
  24. 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)
  25. 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, ' '); };
  26. Demo Goal: Implement the ability to maximize the browser window

    Step 1: Ruby + Firefox Step 2: Java client + Remote Server driver.manage().window().maximize();
  27. Getting involved • Ask for help and input early •

    Keep the change small • Write tests
  28. Getting involved • selenium-developers mailing list • #selenium on irc.freenode.net

    • http://code.google.com/p/selenium/ • http://code.google.com/p/selenium/issues/list • Look for the GettingInvolved label