Browser API

smidas edited this page Aug 27, 2012 · 9 revisions

The entry-point into any clj-webdriver application involves "starting up" a browser. After that, you can perform various browser-level actions like going to a new URL, refreshing the page, or quitting. For more information about interacting with individual page elements, read the Element API section of the wiki.

Starting a Browser

Starting a browser means two things: an actual web browser is opened (Firefox, Chrome, etc.) and clj-webdriver returns a Driver record that controls it. In your Clojure code, you obviously want to keep a reference to that Driver record to use the rest of the clj-webdriver API. (Terminology Note: I have tried to limit my use of the word "browser" below to instances referring to the actual GUI browser application, and use the word "driver" when referring to the Clojure datastructure that gives you access to that browser via clj-webdriver's API).

To start a browser, you can use one of two functions, as follows:

(def driver (new-driver {:browser :firefox}))

(def driver (start {:browser :firefox} "http://example.com"))

The start function calls new-driver and immediately points the driver at a URL, instead of the default blank page.

(Related topics: The new-driver function is the entry point for initializing the Driver cache; see Caching Support for more details. These functions also have equivalents for dealing with the Grid, which you can read about on the Grid Support page.)

Driver Actions

Once you've started your driver, there are a number of things you can do it with before interacting with the actual page.

Basics

The following functions are defined in the IDriver protocol, which encapsulates what I've termed "browser basics":

Navigation:

  • get-url - Point driver at a new URL
  • to - Synonym for get-url
  • back - Go back in the driver's history
  • forward - Go forward in the driver's history
  • refresh - Refresh the page currently loaded in the driver

Driver Information:

  • current-url - Return driver's current URL
  • title - Return driver's current title
  • page-source - Return source code of the currently loaded page

Screenshots:

  • get-screenshot - Return a screenshot as a :file, :bytes or :base64, optionally saving to a permanent file if a destination is given

Closing/Quitting:

  • close - Close the current browser window (does not quit the browser if multiple windows are open)
  • quit - Quit the browser application (closes all open windows)

Finding Things

The heart of clj-webdriver's API is the find-element function. This function wraps the various ways that Selenium-WebDriver allows you to find elements and condenses them into a handful of "mini languages" for finding elements on the page, hopefully in a more Clojure-amenable fashion. Since this is the initial way people start playing with this API, I will continue to maintain the most up-to-date information about it on the README:

README

Waiting

The protocol IWait provides two functions that allow you to determine how long or under what conditions the driver should "wait" while looking for elements on the page:

  • implicit-wait - Set a global wait time that the driver will wait before throwing an exception
  • wait-until - Make the driver wait a certain maximum amount of time for a given predicate to evaluate to true

The first is implicit-wait. This function accepts a numeric value which represents the number of milliseconds the driver should wait on all pages when testing for the presence of page elements. This comes in handy when you repeatedly wait for portions of webpages to load via AJAX, and the only variable in your test execution is the length of time it takes to load those portions.

The second function is wait-until. Unlike implicit-wait, which affects the driver for the duration of its life, the wait-until function is meant for one-off situations where you require the Driver to wait. It accepts both a predicate, which must eventually evaluate to true, and a timeout maximum, to cap wait-until at a certain number of milliseconds before throwing an exception.

Window Handling

The protocol ITargetLocator provides functionality for handling multiple open windows. Windows are uniquely identified by "handles," which live in the Clojure code as WindowHandle records.

  • window-handle - Return handle for currently-active window
  • window-handles - Return a seq of window handles for all open browser windows
  • other-window-handles - Return a seq of window handles that does not include the currently-active window
  • switch-to-window - Make the window handle passed into this function the new currently-active one
  • switch-to-other-window - Iff two windows are open, switch to the other

Cookie Handling

The protocol IOptions manages cookie handling (thus called to be consistent with Selenium-WebDriver's API).

  • add-cookie - Add a new cookie to the driver session
  • cookies - Return a seq of cookies in the current driver session
  • cookie-named - Return a cookie given its name
  • delete-cookie - Delete a cookie
  • delete-cookie-named - Delete a cookie, given only its name
  • delete-all-cookies - Delete all cookies in the current driver session

Remote WebDriver

In addition to the all-in-one browser drivers that Selenium-WebDriver comes with, the API also provides a way to start a standalone server that acts as a "hub" for any number of browsers you might want to start up.

The RemoteWebDriver functionality is used by all the existing browser drivers under the hood, but this requires you to depend on the API support for each individual browser. By providing a mechanism for starting up a server manually, you have maximum control over protocol that lies at the heart of Selenium-WebDriver, the JsonWireProtocol.

More documentation will be forthcoming, but for now you can look at the code in clj-webdriver.remote.server for starting up this standalone "hub" server and for starting up driver instances against it. You can look at clj-webdriver.remote.driver for functionality that (to my mind) seems only useful when dealing with remote drivers. For an example of how to use all of this together, see clj-webdriver.wire at the bottom.