Selenium Clinic Eurostar 2012 WebDriver Tutorial


Published on

Slides from the Selenium Clinic Tutorial from Eurostar 2012 hosted by Simon Stewart and Alan Richardson. The tutorial was awarded "Best Tutorial" at the conference.

The reference slides were excerpted from Alan Richardson's online WebDriver course hosted at Udemy.

Published in: Technology

Selenium Clinic Eurostar 2012 WebDriver Tutorial

  1. 1. Selenium Clinic Alan Richardson (@eviltester), Simon Stewart (@shs96c) @esconfs #esconfs
  2. 2. What Is This? These slides were used in the “Best Tutorial” Award winning tutorial from Eurostar 2012 hosted by Simon Stewart and Alan Richardson Most of these slides form part of the slide deck for Alan Richardson's Online Course So if you like what you read here – check out the full 18+ hour tutorial with 200+ slides
  3. 3. Selenium Conference Do you with there was a conference dedicated to all things Selenium? Well there is: It may be happening soon. It may be near you. Check the site for more details.
  4. 4. Source Code The source code developed during the tutorial and in preparation for the tutorial can be found on github:
  5. 5. Tutorial Agenda
  6. 6. Clinic ('klinik) 1. A tutorial, often associated with a conference that is devoted to the discussion of a single tool 2. A group session, often led by bearded gentlefolk, which offers hints and tips, points out oft neglected practices, and may offer practical hands on challenges 3. A place where such instruction occurs
  7. 7. A Short History of Selenium “All Selenium trainers, are mandated* to provide a short history of Selenium where they describe Selenium (including WebDriver & Selenium-RC & grid etc.), they must also provide a brief history.” * it is a tradition or a law or an old charter or something Selenium-RC WebDriver 7
  8. 8. Intro & Capabilities  Hello from Alan & Simon  Current Group Capabilities
  9. 9. My First WebDriver Test 9
  10. 10. What makes good tests go bad? Wherein we discuss real world test practices for making your testing bad, and conversely, what you can do to mitigate your self destructive tendencies. 10
  11. 11. By any means necessary Wherein locators are discussed, including the use of Custom locators because you deserve to be in control 11
  12. 12. Basic WebDriver Commands  Driver level  WebElement level 12
  13. 13. WebDriverWait exposed Wherein we discuss Fluently the intricacies of waiting; an oft forgotten art of Explicitly taking control of your waiting time rather than Implicitly assuming the passage of time 13
  14. 14. JavaScript Wherein we discuss the nuances of working with the ubiquitous; synchronously, asynchronously and on taking as well as giving. 14
  15. 15. “I have to handle an alert in my application but WebDriver doesn't let me...” Wherein we discuss the handling of alerts and learn what an alert is, what an alert is not, and what to do about it. 15
  16. 16. Refactoring and Abstracting Wherein we discuss the modeling of test automation in the real world and consider; should we refactor to models, or build from models, and how much of a good thing is too much before a good thing goes bad and becomes a bad thing from whence it was once good. 16
  17. 17. Questions and Challenges  Answered & Discussed  Offered 17
  18. 18. Alan Richardson     @eviltester 18
  19. 19. Simon Stewart   @shs96c 19
  20. 20. WebDriver Tutorial Reference Slides For More like this visit:  Http://  The following slides are excerpts from the Online course 20
  21. 21. In Selenium 2.0 The Driver is King  Selenium 1.0   The Server is King Selenium 2.0  The Driver is King WebDriver is the most important Object in the hierarchy. 21
  22. 22. First Test @Test public void driverIsTheKing(){ WebDriver driver = new HtmlUnitDriver(); driver.get(""); assertTrue(driver.getTitle().startsWith( "Selenium Simplified")); } 22
  23. 23. First Test Explained Junit test A headless Implementation of a Driver Core Interface to understand @Test public void driverIsTheKing(){ WebDriver driver = new HtmlUnitDriver(); driver.get(""); assertTrue(driver.getTitle().startsWith( "Selenium Simplified")); Most basic navigation command } Return page title as a string A JUnit assert 23
  24. 24. Real Browser Explored Implementations exist for Firefox, Chrome, IE Opera, etc. @Test public void firefoxIsSupportedByWebDriver(){ WebDriver driver = new FirefoxDriver(); driver.get(""); assertEquals(true, driver.getTitle(). startsWith("Selenium Simplified")); driver.close(); } close() or quit() physical browsers 24
  25. 25. What are the basics that we need to know so that we can automate the web? 25
  26. 26. Basic Knowledge Chunked Open a browser  Navigate to page Navigate Read the page title  Read the url  Get text from the page Interrogate Click on links  Fill in forms  Click on buttons Manipulate    & Synchronize 26
  27. 27. Assertions  assertTrue(“description”, expected, actual)    AssertFalse(...) assertEquals(“description”, expected, actual) Used to check results 27
  28. 28. Junit Example import org.junit.Test; import static junit.framework.Assert.assertEquals; public class JUnitExampleTest { @Test public void aBasicJUnitTest(){ assertEquals("2+2=4", 4, 2+2); } } Actual Value Expected Value Message 28
  29. 29. More JUnit   Avoid repeating code in your @Test methods Before and after each @Test    @Before @After Once per class  @BeforeClass  @AfterClass  Declare methods as static 29
  30. 30. Navigation Annotated  driver  .get(<url>)  driver.get(“”); .navigate      'to' a URL String 'to' a Object .to(<url>) .to(URL) .back() .forward() .refresh() 'back' through browser history 'forward' through browser history 'refresh' the current browser page 30
  31. 31. Navigation Example Test private static WebDriver driver; @BeforeClass public static void createDriver(){ } driver = new FirefoxDriver(); driver needs to be static because of @BeforeClass and @AfterClass Execute this method once per class. Before any of the @Test methods have run. @Test public void navigateWithNavigateTo(){ driver.navigate().to( "" ); assertTrue(driver.getTitle(). startsWith("Selenium Simplified Search Engine")); } @AfterClass public static void quitDriver(){ } driver.quit(); 31 Execute this method once per class. After all @Test methods have run.
  32. 32. DriverInterrogateTest @Test public void driverLevelPageInterrogateMethods(){ WebDriver driver; final String theTestPageURL = ""; driver = new FirefoxDriver(); driver.navigate().to(theTestPageURL); assertEquals(driver.getTitle(), "Basic Web Page Title"); assertEquals(driver.getCurrentUrl(), theTestPageURL); String pageSource = driver.getPageSource(); assertTrue(pageSource.contains("A paragraph of text")); driver.close(); } 32
  33. 33. Be Careful with getPageSource <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ""> <html> <head> <title>Basic Web Page Title</title> </head> <body> <p id="para1" class="main">A paragraph of text</p> <p id="para2" class="sub">Another paragraph of text</p> </body> </html> Line separation Additional attributes Attribute Ordering File on server Firefox Driver Differences <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ""> <html xmlns=""><head> <title>Basic Web Page Title</title> String </head> returned <body> <p class="main" id="para1">A paragraph of text</p> by <p class="sub" id="para2">Another paragraph of text</p> method </body></html> 33
  34. 34. Dom Element Interrogation Approach  Find the Dom Element (WebElement)    .findElement .findElements Use the WebElement Object methods:  .getText()  .isSelected()  .getAttribute()  .isDisplayed()  .getTagName()  .getSize()  .isEnabled()  .getLocation()  34 . getCssValue()
  35. 35. Driver .findElement(By) driver.findElement("para1"))   By.xpath  By.cssSelector  By.className  By.linkText   By.tagName  By.partialLinkText 35 We find an element By using a locator strategy. e.g. by using the id, by evaluating an xpath expression, by executing a css selector, etc.
  36. 36. ExampleFirstFindByTest public class ExampleFirstFindByTest { static WebDriver driver; @BeforeClass public static void createDriverAndVisitTestPage(){ driver = new FirefoxDriver(); driver.get("" + "selenium/find_by_playground.php"); } @Test public void findByID(){ WebElement cParagraph = driver.findElement("p3")); assertEquals("This is c paragraph text", cParagraph.getText()); } } @AfterClass public static void closeBrowser(){ driver.quit(); } 36
  37. 37. .findElements    .findElement only returns 1 WebElement If the By could return more elements then .findElement retursn the first in the list .findElements returns the full list of matching WebElements  e.g. driver.findElements(By.className(“normal”)); 37
  38. 38. Useful Tools For CSS and XPath  Firefox   Install FireBug and FirePath plugins Chrome  Developer tools are supposed to allow search using xpath or css (sometimes this breaks between releases) 38
  39. 39. WebElement Manipulation  .click()  .clear()   .sendKeys(String) actually (CharSequence)    Clear a field Sends the appropriate events to a WebElement keyup, keydown, etc. Helper Keys class (org.openqa.selenium.Keys) .submit()  Submit a form 39
  40. 40. Introducing WebDriverWait    WebDriver has a helper class WebDriverWait which can help us synchronise our tests Used in conjunction with another helper class ExpectedConditions We can write simple synchronisation statements new WebDriverWait(driver,10). until( ExpectedConditions.titleIs("HTML Form Elements")); 40
  41. 41. Manipulation Example Test public class ManipulateExampleTest { static WebDriver driver; @BeforeClass public static void createDriverAndVisitTestPage(){ driver = new FirefoxDriver(); driver = driver.get( "" + "/selenium/basic_html_form.html"); } @Test public void simpleInteraction(){ WebElement checkBox1 = driver.findElement( By.cssSelector("input[value='cb1']")); assertFalse("Starts not selected", checkBox1.isSelected());; } } assertTrue("Click selects", checkBox1.isSelected()); @AfterClass public static void closeBrowser(){ driver.quit(); } 41
  42. 42. Manipulation Summary   Filename fields use .sendKeys Checkbox and radio items    .isSelected, .click  Can clear text or text area 42 Cannot clear a checkbox, multiselect, drop down, or radiobutton Simple manipulation has a very simple set of methods
  43. 43. More on SendKeys  Keys.chord to send Key Sequences  Shift, CTRL etc start a modifier sequence  Keys.NULL ends a modifier sequence commentTextArea.sendKeys( Keys.chord(Keys.SHIFT, "bob", Keys.NULL, " Dobbs")); assertEquals("BOB Dobbs", commentTextArea.getText()) 43
  44. 44. User Interactions Example Actions actions = new Actions(driver); click(multiSelectOptions.get(1)). click(multiSelectOptions.get(2)).perform(); clickSubmitButton();   Previously all 3 were selected, which didn't mirror real life Here, only 1 is selected, which does mirror real life 44
  45. 45. Use User Interactions Carefully  Can vary between machines & browsers  If plain WebDriver works then use it   Use User Interactions for 'complex' situations If you are having problems then check the forums, you might not be the only one 45
  46. 46. Alerts  Handle Alerts with  driver.switchTo().alert()      The hierarchy is 'kinda' obvious When you think About it. Keep searching. Learn the API. .getText() .dismiss() .accept() .sendKeys(String) .alert() returns an Alert object 46
  47. 47. Frames Example @Test public void switchToFrameExample(){ WebDriver driver = Driver.get(""); assertEquals("Frameset Example Title (Example 6)", driver.getTitle()); Switch to the If I don't switch menu frame. then I'll get a NoSuchElementException driver.switchTo().frame("menu"); driver.findElement( By.cssSelector("a[href='frames_example_1.html']")).click(); String titleForExample1 = "Frameset Example Title (Example 1)"; new WebDriverWait(driver,Driver.DEFAULT_TIMEOUT_SECONDS). until(ExpectedConditions.titleIs(titleForExample1)); } assertEquals(titleForExample1,driver.getTitle()); Had to Synchronise on the page change. 47
  48. 48. Windows  Each Browser window has a unique handle     e.g {b3e5c07c-fac7-492f-a86d-d2fa57608185} driver.getWindowHandle() returns handle for current window driver.getWindowHandles() returns a Set<String> of all window handles driver.switchTo.window(String handle) switches control to the chosen window 48
  49. 49. @Test public void switchToNewWindow(){ Window Example WebDriver driver = Driver.get( ""); assertEquals("Expected only 1 current window", 1, driver.getWindowHandles().size()); We start with one window open String framesWindowHandle = driver.getWindowHandle(); driver.switchTo().frame("content"); driver.findElement(By.cssSelector( "a[href='']")).click(); assertEquals("Expected a New Window opened", 2, driver.getWindowHandles().size()); Set<String> myWindows = driver.getWindowHandles(); String newWindowHandle=""; for(String aHandle : myWindows){ if(!framesWindowHandle.contentEquals(aHandle)){ newWindowHandle = aHandle; break; } } driver.switchTo().window(newWindowHandle); assertTrue("Expected Selenium Simplified site", driver.getTitle().contains("Selenium Simplified")); } 49 Remember the current window handle Clicking on this Link opens a new window Find the new window handle Switch to the new window Driver commands now act on new window
  50. 50. Manage Window Example @Test public void manageWindow(){ Position moves The window around WebDriver driver = Driver.get( ""); driver.manage().window().setPosition(new Point(10,20)); Point pos = driver.manage().window().getPosition(); assertEquals(10, pos.getX()); assertEquals(20, pos.getY()); Position uses X & Y co-ords Position uses a Point object driver.manage().window().setSize(new Dimension(350,400)); Dimension winSizes = driver.manage().window().getSize(); } assertEquals(350, winSizes.getWidth()); assertEquals(400, winSizes.getHeight()); Size uses Dimensions i.e width and height 50 Size... Resizes the browser window
  51. 51. Custom ExpectedCondition new WebDriverWait(driver,10).until( new SelectContainsText("combo2"),"Java") );  Why?     ExpectedConditions doesn't have what you need You want to make your tests read well for your usage scenario You want to pass additional values to the apply method ... create a Custom ExpectedCondition 51
  52. 52. Custom ExpectedCondition Example I made it private because It is local to my test, normally this would be public You can return either Boolean or WebElement. I chose Boolean for this. private class SelectContainsText implements ExpectedCondition<Boolean> { Pass in whatever you need in the constructor private String textToFind; private By findBy; public SelectContainsText(final By comboFindBy, final String textToFind) { this.findBy = comboFindBy; this.textToFind = textToFind; Override apply, this is } called by WebDriverWait @Override public Boolean apply(WebDriver webDriver) { WebElement combo = webDriver.findElement(this.findBy); List<WebElement> options = combo.findElements(By.tagName("option")); for(WebElement anOption : options){ if(anOption.getText().equals(this.textToFind)) return true; } } } Implement your checking code using the passed in WebDriver return false; 52
  53. 53. Use WebDriverWait Fluently  Additional methods   .ignoring  .withTimeout  .withMessage   .pollingEvery .etc Allow us to customise WebDriverWait fluently 53
  54. 54. Use WebDriverWait Fluently Override polling time new WebDriverWait(driver, 1). pollingEvery(100, TimeUnit.MILLISECONDS). ignoring(IllegalStateException.class). Ignore Exceptions Override timeout withTimeout(5, TimeUnit.SECONDS). withMessage("will wait 5 seconds"). ); Include text in Timeout Message until( new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver webDriver) { throw new IllegalStateException(); } } 54
  55. 55. ExpectedCondition & Function  An ExpectedCondition implements Function applying to WebDriver objects   Function<WebDriver, T> The apply acts on a WebDriver but it can return any Object e.g. Boolean, WebElement 55
  56. 56. FluentWait   WebDriverWait extends FluentWait so everything you have seen is really FluentWait Main difference between FluentWait and WebDriver Wait:  FluentWait can apply to anything  e.g. WebElement, not just WebDriver 56
  57. 57. Function & Predicate  FluentWait can use Predicate or Function, on any object  Function<F, T>  Predicate<T> 57
  58. 58. FluentWait Example Declare that a WebElement will be passed to the wait countdown = driver.findElement("javascript_countdown_time")); Pass in WebElement new FluentWait<WebElement>(countdown). Configure wait fluently withTimeout(10, TimeUnit.SECONDS). pollingEvery(100,TimeUnit.MILLISECONDS). until(new Function<WebElement, Boolean>() { } ); @Override public Boolean apply(WebElement element) { return element.getText().endsWith("04"); } Declare returning a Boolean 58
  59. 59. Implicit or Explicit?  Implicit can make initial tests faster to write   It can be harder to add synchronisation later   you don't worry about synchronisation when writing tests You have to identify a source of intermittency If you start with implicit then you can expose synchronisation problems by gradually reducing the implicit wait time 59
  60. 60. Implicit or Explicit?  Implicit can make initial tests faster to write   It can be harder to add synchronisation later   you don't worry about synchronisation when writing tests You have to identify a source of intermittency If you start with implicit then you can expose synchronisation problems by gradually reducing the implicit wait time 60
  61. 61. Cookies  Inspect  driver.manage    .getCookies() .getCookieNamed(“name”) Interact  driver.manage     .addCookie(Cookie) .deleteAllCookies .deleteCookie(Cookie) .deleteCookieNamed(“name”) 61
  62. 62. Cookies Example @Test public void visitSearchPageAndCheckNoLastSearchCookie(){ WebDriver driver; driver = Driver.get(""); Delete all cookies for current domain driver.manage().deleteAllCookies(); driver.navigate().refresh(); Refresh page to get an initial set of cookies Find a named cookie Return null if not found Cookie aCookie = driver.manage().getCookieNamed("SeleniumSimplifiedLastSearch"); } assertEquals("Should be no last search cookie", null, aCookie); 62
  63. 63. Javascript Execution  Cast WebDriver to JavascriptExecutor    .executeScript(script, args...) .executeAsyncScript(script, args...) Arguments are accessed using   arguments[index] e.g. "document.title=arguments[0]" Return values are converted to Java types  Html Element = WebElement, decimal = Double, non-decimal = Long, boolean = Boolean, array = List<Object>, else String or 63 null
  64. 64. (JavascriptExecutor) Example @Test public void callAJavaScriptFunctionOnThePage(){ Test page is at selenium/canvas_basic.html WebDriver driver = Driver.get( ""); JavascriptExecutor js =(JavascriptExecutor)driver; int actionsCount = driver.findElements( By.cssSelector("#commandlist li")).size(); assertEquals("By default app has 2 actions listed", 2, actionsCount); js.executeScript("draw(1, 150,150,40, '#FF1C0A');"); } actionsCount = driver.findElements( By.cssSelector("#commandlist li")).size(); assertEquals("Calling draw should add an action", 3, actionsCount); 64 Cast driver to JavascriptExecutor to access the JavaScript methods Execute the 'draw' Function in the page
  65. 65. ChromeDriver   Download the driver server   Command line switches    set "" to the location Pass in as options ChromeDriver.log is useful debugging tool 65
  66. 66. Remote Driver  When server is running on another machine  e.g. DesiredCapabilities capabilities; Remote driver configured by capabilities capabilities = DesiredCapabilities.firefox(); capabilities.setCapability("version", "5"); capabilities.setCapability("platform", Platform.XP); try { String sauceURL = System.getenv("SAUCELABS_URL"); aDriver = new RemoteWebDriver( new URL(sauceURL), capabilities); Watch out for UnsupportedCommandException } catch (MalformedURLException e) { during your tests e.printStackTrace(); } 66
  67. 67. Try Different Browsers  Some tests will fail due to:  Driver issues   Aaargh, I knew it was too easy! Bugs in the drivers Driver differences   different exceptions thrown, new exceptions thrown  Incompatible driver/browser versions  Driver scope   Some functionality not implemented Documentation differences  67 Look at log output or read source … etc.
  68. 68. WebDriver Summary Sheet WebDriver Interact = new <driverClass>() Inspect .close() .quit() Finding elements WebDriver .getTitle() .getCurrentUrl() Navigate .navigate WebElement = .findElement(BY) .getPageSource() WebDriver .get(“URL”) WebDriver List<WebElement> = .findElements(BY) WebElement Interact WebElement SwitchTo. .click() .alert() .submit() .clear() By .id(“an_id”) .getText() .sendKeys(String) .sendKeys(Keys.x) .to(Url) .getAttribute(“name”) .to(“URL”) .getTagName() .xpath(“xpath”) .back() .isEnabled() .cssSelector(“css”) support.ui.Select .forward() .isSelected() .className(“class”) .isDisplayed() .linkText(“text”) .getSize() .name(“name” .getLocation() .tagName(“a_tag”) .getCssValue() .partialLinkText(“t”); .accept() .dismiss() .<methods>() .refresh() .getText() Synchronise .sendKeys(String) .frame(...) Cookies WebDriver .manage() .deleteAllCookies() Support .addCookie(Cookie) WebDriverWait ByChaining(By, By) .deleteCookie(Cookie) (driver, timeout in Seconds) .until(ExpectedCondition) ByIdOrName(“idName”) .deleteCookieNamed(String) ExpectedConditions .titleIs(String) … a lot of helper methods Cookies Actions (JavascriptExecutor) WebDriver .keyUp() etc. .executeScript .perform() .manage() .getCookieNamed(String) .getCookies() 68
  69. 69. End Points   You will encounter problems we haven't covered here You will need to download and read the Selenium 2.0 source code as you test 69
  70. 70. Basic Practice Pages    calculate.php  basic_ajax.html  find_by_playground.php  basic_web_page.html  refresh.php  basic_html_form.html  search.php   alert.html ajaxselect.php Source available at 70
  71. 71. Advanced Practice Pages    Showcase/Showcase.html Source available at 71
  72. 72. WebDriver Tutorial Reference Slides For More like this visit:  Http://  Online Course: The reference slides are excerpts from the above online course 72