This repository has been archived by the owner on Nov 9, 2017. It is now read-only.
/
util.clj
129 lines (117 loc) · 4.48 KB
/
util.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
(ns clj-webdriver.util
(:require [clojure.string :as str])
(:import [org.openqa.selenium WebDriver WebElement]))
(defn build-xpath-attrs
"Given a map of attribute-value pairs, build the bracketed portion of an XPath query that follows the tag"
[attr-val]
(apply str (for [[attr value] attr-val]
(cond
(= :text attr) (str "[text()='" value "']")
(= :index attr) (str "[" (inc value) "]") ; in clj-webdriver,
:else (str "[@" ; all indeces 0-based
(name attr)
"="
"'" value "']")))))
(declare contains-regex?)
(defn build-xpath
"Given a tag and a map of attribute-value pairs, generate XPath"
[tag attr-val]
(if (contains-regex? attr-val)
nil
(str "//"
(name tag)
(if (empty? attr-val)
nil
(build-xpath-attrs attr-val)))))
(defn build-xpath-with-ancestry
"Given a vector of queries in hierarchical order, create XPath.
For example: `[:div {:id \"content\"}, :a {:class \"external\"}]` would
produce the XPath \"//div[@id='content']//a[@class='external']"
[attr-val]
(apply str (let [tag-to-attrs (partition 2 attr-val)]
(for [xpath-parts tag-to-attrs]
(build-xpath (first xpath-parts) (second xpath-parts))))))
(defn contains-regex?
"Checks if the values of a map contain a regex"
[m]
(boolean (some (fn [entry]
(let [[k v] entry]
(= java.util.regex.Pattern (class v)))) m)))
(defn all-regex?
"Checks if all values of a map are regexes"
[m]
(and (not (empty? m))
(not (some (fn [entry]
(let [[k v] entry]
(not= java.util.regex.Pattern (class v)))) m))))
(defn query-with-ancestry-has-regex?
"Check if any values in maps as part of ancestry-based query have a regex"
[v]
(let [maps (flatten (for [chunk (partition 2 v)]
(second chunk)))]
(boolean (some true? (for [m maps]
(contains-regex? m))))))
(defn first-60
"Get first twenty characters of `s`, then add ellipsis"
[s]
(str (re-find #"(?s).{1,60}" s)
(if (> (count s) 60)
"..."
nil)))
(defn elim-breaks
"Eliminate line breaks; used for REPL printing"
[s]
(str/replace s #"(\r|\n|\r\n)" " "))
;; borrowed from Clojure's 1.2 Contrib
(defn call-method
[klass method-name params obj & args]
(-> klass (.getDeclaredMethod (name method-name)
(into-array Class params))
(doto (.setAccessible true))
(.invoke obj (into-array Object args))))
(defmacro when-attr
"Special `when` macro for checking if an attribute isn't available or is an empty string"
[obj & body]
`(when (not (or (nil? ~obj) (empty? ~obj)))
~@body))
(defmethod print-method WebDriver
[q w]
(let [caps (.getCapabilities q)]
(print-simple
(str "#<" "Title: " (.getTitle q) ", "
"URL: " (first-60 (.getCurrentUrl q)) ", "
"Browser: " (.getBrowserName caps) ", "
"Version: " (.getVersion caps) ", "
"JS Enabled: " (.isJavascriptEnabled caps) ", "
"Native Events Enabled: " (boolean (re-find #"nativeEvents=true" (.toString caps))) ", "
"Object: " q ">") w)))
(defmethod print-method WebElement
[q w]
(let [tag-name (.getTagName q)
text (.getText q)
id (.getAttribute q "id")
class-name (.getAttribute q "class")
name-name (.getAttribute q "name")
value (.getAttribute q "value")
href (.getAttribute q "href")
src (.getAttribute q "src")
obj q]
(print-simple
(str "#<"
(when-attr tag-name
(str "Tag: " "<" tag-name ">" ", "))
(when-attr text
(str "Text: " (-> text elim-breaks first-60) ", "))
(when-attr id
(str "Id: " id ", "))
(when-attr class-name
(str "Class: " class-name ", "))
(when-attr name-name
(str "Name: " name-name ", "))
(when-attr value
(str "Value: " value ", "))
(when-attr href
(str "Href: " href ", "))
(when-attr src
(str "Source: " src ", "))
"Object: " q ">") w)))