Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Merge pull request #94 from semperos/assoc-exceptions
Browse files Browse the repository at this point in the history
Improve handling of nils and exceptions when working with elements of the page
  • Loading branch information
semperos committed Feb 11, 2013
2 parents 8ba9424 + eac6fa2 commit a45d70c
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 78 deletions.
2 changes: 1 addition & 1 deletion project.clj
@@ -1,4 +1,4 @@
(defproject clj-webdriver "0.6.0-beta2"
(defproject clj-webdriver "0.6.0-SNAPSHOT"
:description "Clojure API for Selenium-WebDriver"
:url "https://github.com/semperos/clj-webdriver"
:license {:name "Eclipse Public License"
Expand Down
15 changes: 11 additions & 4 deletions src/clj_webdriver/core.clj
Expand Up @@ -30,9 +30,7 @@
[org.openqa.selenium.firefox FirefoxDriver]
[org.openqa.selenium.ie InternetExplorerDriver]
[org.openqa.selenium.chrome ChromeDriver]
;; [com.opera.core.systems OperaDriver]
[org.openqa.selenium.htmlunit HtmlUnitDriver]
;; [org.openqa.selenium.security UserAndPassword]
[org.openqa.selenium.support.ui Select]
[org.openqa.selenium.interactions Actions CompositeAction]
[java.util Date]
Expand Down Expand Up @@ -133,7 +131,7 @@
(deselect-all [select-element] "Deselect all options for a given select list. Does not leverage WebDriver method because WebDriver's isMultiple method is faulty.")
(deselect-by-index [select-element idx] "Deselect the option at index `idx` for the select list described by `by`. Indeces begin at 0")
(deselect-by-text [select-element text] "Deselect all options with visible text `text` for the select list described by `by`")
(deselect-by-value [select-element value] "Deselect all options with value `value` for the select list described by `by`")
(deselect-by-value [select-element value] "Deselect all options with value `value` for the select list described by `by`")
(first-selected-option [select-element] "Retrieve the first selected option (or the only one for single-select lists) from the given select list")
(multiple? [select-element] "Return true if the given select list allows for multiple selections")
(select-option [select-element attr-val] "Select an option from a select list, either by `:value`, `:index` or `:text`")
Expand Down Expand Up @@ -200,6 +198,15 @@
:profile profile})
:cache-spec cache-spec}))))

;; Chrome binary, common location of Chromium on Linux
(comment
(do
(import 'org.openqa.selenium.remote.DesiredCapabilities)
(let [cap (DesiredCapabilities/chrome)]
(.setCapability cap "chrome.binary" "/usr/lib/chromium-browser/chromium-browser")
(init-driver (ChromeDriver. cap))))
)

(defn start
"Shortcut to instantiate a driver, navigate to a URL, and return the driver for further use"
([browser-spec url]
Expand Down Expand Up @@ -298,7 +305,7 @@
Unless you need to wait to execute your composite actions, you should prefer `->actions` to this macro."
[driver & body]
`(let [acts# (doto (:actions ~driver)
`(let [acts# (doto (:actions ~driver)
~@body)]
(.build acts#)))

Expand Down
109 changes: 69 additions & 40 deletions src/clj_webdriver/core_driver.clj
Expand Up @@ -27,12 +27,15 @@
(let [this-handle (window-handle* (:webdriver driver))
idx (.indexOf handles this-handle)]
(cond
(zero? idx) (do ; if first window, switch to next
(.close (:webdriver driver))
(switch-to-window driver (nth handles (inc idx))))
:else (do ; otherwise, switch back one window
(.close (:webdriver driver))
(switch-to-window driver (nth handles (dec idx)))))
(zero? idx)
(do ; if first window, switch to next
(.close (:webdriver driver))
(switch-to-window driver (nth handles (inc idx))))

:else
(do ; otherwise, switch back one window
(.close (:webdriver driver))
(switch-to-window driver (nth handles (dec idx)))))
(cache/seed driver {}))
(do
(.close (:webdriver driver))
Expand Down Expand Up @@ -125,19 +128,28 @@

(switch-to-window [driver window]
(cond
(string? window) (do
(.window (.switchTo (:webdriver driver)) window)
driver)
(win/window? window) (do
(.window (.switchTo (:driver window)) (:handle window))
driver)
(number? window) (do
(switch-to-window driver (nth (windows driver) window))
driver)
(nil? window) (throw (RuntimeException. "No window can be found"))
:else (do
(.window (.switchTo (:webdriver driver)) window)
driver)))
(string? window)
(do
(.window (.switchTo (:webdriver driver)) window)
driver)

(win/window? window)
(do
(.window (.switchTo (:driver window)) (:handle window))
driver)

(number? window)
(do
(switch-to-window driver (nth (windows driver) window))
driver)

(nil? window)
(throw (RuntimeException. "No window can be found"))

:else
(do
(.window (.switchTo (:webdriver driver)) window)
driver)))

(switch-to-other-window [driver]
(if (not= (count (windows driver)) 2)
Expand All @@ -158,23 +170,23 @@
(add-cookie [driver cookie-spec]
(.addCookie (.manage (:webdriver driver)) (:cookie (init-cookie cookie-spec)))
driver)

(delete-cookie-named [driver cookie-name]
(.deleteCookieNamed (.manage (:webdriver driver)) cookie-name)
driver)

(delete-cookie [driver cookie-spec]
(.deleteCookie (.manage (:webdriver driver)) (:cookie (init-cookie cookie-spec)))
driver)

(delete-all-cookies [driver]
(.deleteAllCookies (.manage (:webdriver driver)))
driver)

(cookies [driver]
(set (map #(init-cookie {:cookie %})
(.getCookies (.manage (:webdriver driver))))))

(cookie-named [driver cookie-name]
(let [cookie-obj (.getCookieNamed (.manage (:webdriver driver)) cookie-name)]
(init-cookie {:cookie cookie-obj})))
Expand All @@ -186,7 +198,7 @@

(alert-obj [driver]
(-> driver :webdriver .switchTo .alert))

(alert-text [driver]
(-> driver :webdriver .switchTo .alert .getText))

Expand All @@ -196,7 +208,7 @@

(dismiss [driver]
(-> driver :webdriver .switchTo .alert .dismiss))

;; Find Functions
IFind
(find-element-by [driver by-value]
Expand All @@ -212,7 +224,7 @@
els (.findElements (:webdriver driver) by-value)]
(if (seq els)
(lazy-seq (map init-element els))
(lazy-seq (map init-element [nil])))))
(lazy-seq nil))))

(find-windows [driver attr-val]
(if (contains? attr-val :index)
Expand Down Expand Up @@ -307,17 +319,27 @@
([driver element]
(let [act (:actions driver)]
(.perform (.doubleClick act (:webelement element))))))

(drag-and-drop
[driver element-a element-b]
(let [act (:actions driver)]
(.perform (.dragAndDrop act (:webelement element-a) (:webelement element-b)))))
(cond
(nil? element-a) (throw-nse "The first element does not exist.")
(nil? element-b) (throw-nse "The second element does not exist.")
:else (let [act (:actions driver)]
(.perform (.dragAndDrop act
(:webelement element-a)
(:webelement element-b))))))

(drag-and-drop-by
[driver element x-y-map]
(let [act (:actions driver)
{:keys [x y] :or {x 0 y 0}} x-y-map]
(.perform (.dragAndDropBy act (:webelement element) x y))))
(if (nil? element)
(throw-nse)
(let [act (:actions driver)
{:keys [x y] :or {x 0 y 0}} x-y-map]
(.perform
(.dragAndDropBy act
(:webelement element)
x y)))))

(key-down
([driver k]
Expand Down Expand Up @@ -436,11 +458,18 @@
(cond
;; Accept by-clauses
(not (or (vector? attr-val)
(map? attr-val))) (find-elements-by driver attr-val)
;; Accept vectors for hierarchical queries
(vector? attr-val) (find-by-hierarchy driver attr-val)
;; Build XPath dynamically
:else (find-elements-by driver (by-query (build-query attr-val))))
(map? attr-val)))
(find-elements-by driver attr-val)

;; Accept vectors for hierarchical queries
(vector? attr-val)
(find-by-hierarchy driver attr-val)

;; Build XPath dynamically
:else
(find-elements-by driver (by-query (build-query attr-val))))
(catch org.openqa.selenium.NoSuchElementException e
;; NoSuchElementException caught here, so we can have functions like `exist?`
(lazy-seq [(init-element nil)])))))
;; NoSuchElementException caught here to mimic Clojure behavior like
;; (get {:foo "bar"} :baz) since the page can be thought of as a kind of associative
;; data structure with unique selectors as keys and HTML elements as values
(lazy-seq nil)))))

0 comments on commit a45d70c

Please sign in to comment.