|
13 | 13 | [etaoin.impl.client :as client]
|
14 | 14 | [etaoin.keys :as k]
|
15 | 15 | [etaoin.test-report :as test-report]
|
16 |
| - [slingshot.slingshot :refer [try+]]) |
| 16 | + [slingshot.slingshot :refer [try+]] |
| 17 | + [slingshot.test]) |
17 | 18 | (:import [java.net ServerSocket]))
|
18 | 19 |
|
19 | 20 | (defn numeric? [val]
|
|
128 | 129 | report-browsers
|
129 | 130 | test-server)
|
130 | 131 |
|
| 132 | +(deftest test-browser-conditionals |
| 133 | + (testing "Chrome conditionals" |
| 134 | + (e/when-chrome *driver* |
| 135 | + (is (e/driver? *driver* :chrome))) |
| 136 | + (e/when-not-chrome *driver* |
| 137 | + (is (not (e/driver? *driver* :chrome))))) |
| 138 | + (testing "Firefox conditionals" |
| 139 | + (e/when-firefox *driver* |
| 140 | + (is (e/driver? *driver* :firefox))) |
| 141 | + (e/when-not-firefox *driver* |
| 142 | + (is (not (e/driver? *driver* :firefox))))) |
| 143 | + (testing "Safari conditionals" |
| 144 | + (e/when-safari *driver* |
| 145 | + (is (e/driver? *driver* :safari))) |
| 146 | + (e/when-not-safari *driver* |
| 147 | + (is (not (e/driver? *driver* :safari))))) |
| 148 | + (testing "Edge conditionals" |
| 149 | + (e/when-edge *driver* |
| 150 | + (is (e/driver? *driver* :edge))) |
| 151 | + (e/when-not-edge *driver* |
| 152 | + (is (not (e/driver? *driver* :edge))))) |
| 153 | + (testing "Headless conditionals" |
| 154 | + (e/when-headless *driver* |
| 155 | + (is (e/headless? *driver*))) |
| 156 | + (e/when-not-headless *driver* |
| 157 | + (is (not (e/headless? *driver*)))))) |
| 158 | + |
131 | 159 | (deftest test-navigation
|
132 | 160 | (is (= (test-server-url "test.html") (e/get-url *driver*)) "initial page")
|
133 | 161 | (e/go *driver* (test-server-url "test2.html"))
|
|
158 | 186 | (is (e/selected? *driver* :vehicle2))
|
159 | 187 | (is (e/selected? *driver* :vehicle3)))
|
160 | 188 |
|
| 189 | +(deftest test-submit |
| 190 | + (doto *driver* |
| 191 | + (e/fill-multi {:simple-input 1 |
| 192 | + :simple-password 2 |
| 193 | + :simple-textarea 3}) |
| 194 | + (e/submit :simple-input) |
| 195 | + ;; Both Safari and Firefox need a slight delay here before the URL |
| 196 | + ;; corresponding to the submitted form is valid. Chrome and Edge |
| 197 | + ;; seem to do OK without. As of Aug 28, 2024. |
| 198 | + (e/when-safari (e/wait 3)) |
| 199 | + (e/when-firefox (e/wait 3)) |
| 200 | + (-> e/get-url |
| 201 | + (str/ends-with? "?login=1&password=2&message=3") |
| 202 | + is))) |
| 203 | + |
161 | 204 | (deftest test-input
|
162 | 205 | (testing "fill multiple inputs"
|
| 206 | + ;; Test with map form |
163 | 207 | (doto *driver*
|
164 | 208 | (e/fill-multi {:simple-input 1
|
165 | 209 | :simple-password 2
|
166 | 210 | :simple-textarea 3})
|
167 | 211 | (e/click :simple-submit)
|
168 | 212 | (e/when-safari (e/wait 3))
|
| 213 | + (-> e/get-url |
| 214 | + (str/ends-with? "?login=1&password=2&message=3") |
| 215 | + is)) |
| 216 | + ;; Test with vector form |
| 217 | + (doto *driver* |
| 218 | + (e/fill-multi [:simple-input 1 |
| 219 | + :simple-password 2 |
| 220 | + :simple-textarea 3]) |
| 221 | + (e/click :simple-submit) |
| 222 | + (e/when-safari (e/wait 3)) |
169 | 223 | (-> e/get-url
|
170 | 224 | (str/ends-with? "?login=1&password=2&message=3")
|
171 | 225 | is)))
|
| 226 | + (testing "fill-multi bad inputs" |
| 227 | + (is (thrown+? [:type :etaoin/argument] |
| 228 | + (e/fill-multi *driver* #{:set :is :not :allowed}))) |
| 229 | + (is (thrown+? [:type :etaoin/argument] |
| 230 | + (e/fill-multi *driver* '(:list :is :not :allowed)))) |
| 231 | + (is (thrown+? [:type :etaoin/argument] |
| 232 | + (e/fill-multi *driver* [:vector :with :odd :length :is :not :allowed])))) |
172 | 233 | (testing "fill human multiple inputs"
|
173 | 234 | (doto *driver*
|
| 235 | + ;; Test with map form |
174 | 236 | (e/fill-human-multi {:simple-input "login"
|
175 | 237 | :simple-password "123"
|
176 | 238 | :simple-textarea "text"})
|
177 | 239 | (e/click :simple-submit)
|
178 | 240 | (e/when-safari (e/wait 3))
|
| 241 | + (-> e/get-url |
| 242 | + (str/ends-with? "?login=login&password=123&message=text") |
| 243 | + is)) |
| 244 | + (doto *driver* |
| 245 | + ;; Test with vector form |
| 246 | + (e/fill-human-multi [:simple-input "login" |
| 247 | + :simple-password "123" |
| 248 | + :simple-textarea "text"]) |
| 249 | + (e/click :simple-submit) |
| 250 | + (e/when-safari (e/wait 3)) |
179 | 251 | (-> e/get-url
|
180 | 252 | (str/ends-with? "?login=login&password=123&message=text")
|
181 | 253 | is)))
|
| 254 | + (testing "fill-human-multi bad inputs" |
| 255 | + (is (thrown+? [:type :etaoin/argument] |
| 256 | + (e/fill-multi *driver* #{:set :is :not :allowed}))) |
| 257 | + (is (thrown+? [:type :etaoin/argument] |
| 258 | + (e/fill-multi *driver* '(:list :is :not :allowed)))) |
| 259 | + (is (thrown+? [:type :etaoin/argument] |
| 260 | + (e/fill-multi *driver* [:vector :with :odd :length :is :not :allowed])))) |
182 | 261 | (testing "fill multiple vars"
|
183 | 262 | (doto *driver*
|
184 | 263 | (e/fill :simple-input 1 "test" 2 \space \A)
|
|
600 | 679 | (is (= init-handle (e/get-window-handle *driver*)) "wrapped around to original window")))
|
601 | 680 |
|
602 | 681 | (deftest test-maximize
|
603 |
| - (when-not (e/headless? *driver*) ;; skip for headless |
| 682 | + (e/when-not-headless *driver* ;; skip for headless |
604 | 683 | (e/set-window-position *driver* 2 2)
|
605 | 684 | (let [orig-rect (e/get-window-rect *driver*)
|
606 | 685 | target-rect (-> orig-rect
|
|
749 | 828 | (e/set-hash "goodbye")
|
750 | 829 | (-> e/get-url (str/ends-with? "/test.html#goodbye") is))))
|
751 | 830 |
|
752 |
| -(deftest test-find-element |
753 |
| - (let [text (e/get-element-text *driver* {:class :target})] |
754 |
| - (is (= text "target-1"))) |
755 |
| - (let [text (e/get-element-text *driver* [{:class :foo} |
756 |
| - {:class :target}])] |
757 |
| - (is (= text "target-2"))) |
758 |
| - (e/with-xpath *driver* |
759 |
| - (let [text (e/get-element-text *driver* ".//div[@class='target'][1]")] |
760 |
| - (is (= text "target-1")))) |
761 |
| - (let [text (e/get-element-text *driver* {:css ".target"})] |
762 |
| - (is (= text "target-1"))) |
763 |
| - (let [q [{:css ".bar"} ".//div[@class='inside']" {:tag :span}] |
764 |
| - text (e/get-element-text *driver* q)] |
765 |
| - (is (= text "target-3")))) |
766 |
| - |
767 |
| -(deftest test-find-elements-more |
| 831 | +(deftest test-query |
| 832 | + (testing "finding an element by id keyword" |
| 833 | + (let [el (e/query *driver* :find-element-by-id)] |
| 834 | + (is (= "target-1" (e/get-element-text-el *driver* el))))) |
| 835 | + (testing "XPath and CSS string syntax" |
| 836 | + (e/with-xpath *driver* |
| 837 | + (let [el (e/query *driver* ".//div[@class='target'][1]")] |
| 838 | + (is (= "target-1" (e/get-element-text-el *driver* el))))) |
| 839 | + (e/with-css *driver* |
| 840 | + (let [el (e/query *driver* ".bar .deep .inside span") ] |
| 841 | + (is (= "target-3" (e/get-element-text-el *driver* el)))))) |
| 842 | + (testing "XPath and CSS map syntax" |
| 843 | + (let [el (e/query *driver* {:xpath ".//*[@class='target']"})] |
| 844 | + (is (= "target-1" (e/get-element-text-el *driver* el)))) |
| 845 | + (let [el (e/query *driver* {:css ".target"})] |
| 846 | + (is (= "target-1" (e/get-element-text-el *driver* el))))) |
| 847 | + (testing "map syntax" |
| 848 | + ;; 1. tags |
| 849 | + (testing "tags" |
| 850 | + (let [el (e/query *driver* {:tag :h3 :id :find-element})] |
| 851 | + (is (= "Find element" (e/get-element-text-el *driver* el))))) |
| 852 | + ;; 2. class |
| 853 | + (testing "class" |
| 854 | + (let [el (e/query *driver* {:class :target})] |
| 855 | + (is (= "target-1" (e/get-element-text-el *driver* el))))) |
| 856 | + ;; 3. random attributes |
| 857 | + (testing "random attributes" |
| 858 | + (let [el (e/query *driver* {:strangeattribute :foo})] |
| 859 | + (is (= "DIV with strange attribute" (e/get-element-text-el *driver* el))))) |
| 860 | + ;; 4. :fn/* |
| 861 | + (testing ":fn/* functions" |
| 862 | + ;; :index and :fn/index |
| 863 | + (let [el (e/query *driver* {:class :list :index 3})] ; deprecated syntax |
| 864 | + (is (= "ordered 3" (e/get-element-text-el *driver* el)))) |
| 865 | + (let [el (e/query *driver* {:class :list :fn/index 3})] ; new syntax |
| 866 | + (is (= "ordered 3" (e/get-element-text-el *driver* el)))) |
| 867 | + ;; :fn/text |
| 868 | + (let [el (e/query *driver* {:fn/text "multiple classes"})] |
| 869 | + (is (= "multiple-classes" (e/get-element-attr-el *driver* el "id")))) |
| 870 | + ;; :fn/has-text |
| 871 | + (let [el (e/query *driver* {:fn/has-text "ple cla"})] ; pick out the middle |
| 872 | + (is (= "multiple-classes" (e/get-element-attr-el *driver* el "id")))) |
| 873 | + ;; :fn/has-string |
| 874 | + (let [el (e/query *driver* {:tag :ol :fn/has-string "ordered 3"})] |
| 875 | + (is (= "ordered-list" (e/get-element-attr-el *driver* el "id")))) |
| 876 | + ;; :fn/has-class |
| 877 | + (let [el (e/query *driver* {:fn/has-class "ol-class1"})] |
| 878 | + (is (= "ordered-list" (e/get-element-attr-el *driver* el "id")))) |
| 879 | + ;; :fn/has-classes |
| 880 | + ;; verify that order doesn't matter |
| 881 | + (let [elx (e/query *driver* {:fn/has-classes [:ol-class1 :ol-class2]}) |
| 882 | + ely (e/query *driver* {:fn/has-classes [:ol-class2 :ol-class1]}) |
| 883 | + elz (e/query *driver* :ordered-list)] |
| 884 | + (is (= elx ely elz))) |
| 885 | + ;; :fn/link |
| 886 | + (let [el (e/query *driver* {:fn/link "https://www.github.com/"})] |
| 887 | + (is (= "Link to GitHub" (e/get-element-text-el *driver* el)))) |
| 888 | + ;; :fn/enabled |
| 889 | + (let [el (e/query *driver* [:enabled-disabled {:type :checkbox :fn/enabled true}])] |
| 890 | + (is (= "checkbox-1" (e/get-element-attr-el *driver* el "id")))) |
| 891 | + (let [el (e/query *driver* [:enabled-disabled {:type :checkbox :fn/enabled false}])] |
| 892 | + (is (= "checkbox-2" (e/get-element-attr-el *driver* el "id")))) |
| 893 | + (let [el (e/query *driver* [:enabled-disabled {:type :checkbox :fn/enabled true :fn/index 2}])] |
| 894 | + (is (= "checkbox-3" (e/get-element-attr-el *driver* el "id")))) |
| 895 | + ;; :fn/disabled |
| 896 | + (let [el (e/query *driver* [:enabled-disabled {:type :checkbox :fn/disabled false}])] |
| 897 | + (is (= "checkbox-1" (e/get-element-attr-el *driver* el "id")))) |
| 898 | + (let [el (e/query *driver* [:enabled-disabled {:type :checkbox :fn/disabled true}])] |
| 899 | + (is (= "checkbox-2" (e/get-element-attr-el *driver* el "id")))) |
| 900 | + (let [el (e/query *driver* [:enabled-disabled {:type :checkbox :fn/disabled false :fn/index 2}])] |
| 901 | + (is (= "checkbox-3" (e/get-element-attr-el *driver* el "id")))))) |
| 902 | + (testing "vector syntax" |
| 903 | + ;; TODO: should check vectors with length 1, 2, and 3. |
| 904 | + (e/with-xpath *driver* ; force XPath because we use a string |
| 905 | + (let [el (e/query *driver* [{:css ".bar"} ".//div[@class='inside']" {:tag :span}])] |
| 906 | + (is (= "target-3" (e/get-element-text-el *driver* el))))) |
| 907 | + (let [el (e/query *driver* [{:class :foo} {:class :target}])] |
| 908 | + (is (= "target-2" (e/get-element-text-el *driver* el))))) |
| 909 | + (testing "variable arguments syntax" |
| 910 | + ;; Same as vector syntax but just provided as separate arguments to `query` |
| 911 | + (e/with-xpath *driver* |
| 912 | + (let [el (e/query *driver* {:css ".bar"} ".//div[@class='inside']" {:tag :span})] |
| 913 | + (is (= "target-3" (e/get-element-text-el *driver* el))))) |
| 914 | + (let [el (e/query *driver* {:class :foo} {:class :target})] |
| 915 | + (is (= "target-2" (e/get-element-text-el *driver* el))))) |
| 916 | + (testing "negative test cases" |
| 917 | + ;; TODO: |
| 918 | + ;; 1. searching for nothing |
| 919 | + (testing "zero-length vector queries" |
| 920 | + ;; 1. pass a vector of length 0 to query |
| 921 | + (is (thrown+? [:type :etaoin/argument] (e/query *driver* [])))) |
| 922 | + ;; 2. searching for an element that can't be found |
| 923 | + (testing "querying for missing elements" |
| 924 | + ;; 2a. searching for a missing element with missing ID |
| 925 | + (is (thrown+? [:type :etaoin/http-error] (e/query *driver* :missing-element))) |
| 926 | + (is (thrown+? [:type :etaoin/http-error] (e/query *driver* [:missing-element]))) |
| 927 | + ;; 2a. element not found in middle of a vector query |
| 928 | + (is (thrown+? [:type :etaoin/http-error] (e/query *driver* [{:css ".bar"} |
| 929 | + :missing-element |
| 930 | + {:tag :span}]))) |
| 931 | + ;; 2b. element not found at the end of a vector query |
| 932 | + (is (thrown+? [:type :etaoin/http-error] (e/query *driver* [{:css ".bar"} |
| 933 | + {:tag :div :class :inside} |
| 934 | + :missing-element])))) |
| 935 | + ;; 3. malformed XPath |
| 936 | + ;; 4. malformed CSS |
| 937 | + ;; 5. query isn't a string, map, or vector. Perhaps a list and set. |
| 938 | + ;; 6. bad :fn/... keywords |
| 939 | + ;; 7. vector queries with vector elements (vectors in vectors) |
| 940 | + )) |
| 941 | + |
| 942 | +(deftest test-query-all |
768 | 943 | (testing "simple case"
|
769 | 944 | (let [q {:class :find-elements-target}
|
770 | 945 | elements (e/query-all *driver* q)]
|
|
777 | 952 | texts (for [el elements]
|
778 | 953 | (e/get-element-text-el *driver* el))]
|
779 | 954 | (is (= (count elements) 2))
|
780 |
| - (is (= texts ["1" "2"]))))) |
| 955 | + (is (= texts ["1" "2"])))) |
| 956 | + (testing "returning multiple elements via XPath" |
| 957 | + (let [q {:xpath ".//div[@id='operate-multiple-elements']//*"} |
| 958 | + elements (e/query-all *driver* q) |
| 959 | + tag-names (for [el elements] |
| 960 | + (str/lower-case (e/get-element-tag-el *driver* el)))] |
| 961 | + (is (= (vec tag-names) |
| 962 | + ["div" "b" "p" "span"]))))) |
| 963 | + |
| 964 | +(deftest test-switch-default-locator |
| 965 | + (testing "xpath locator" |
| 966 | + (let [driver (e/use-xpath *driver*)] |
| 967 | + (is (= "target-1" (e/get-element-text driver ".//*[@class='target']"))))) |
| 968 | + (testing "css locator" |
| 969 | + (let [driver (e/use-css *driver*)] |
| 970 | + (is (= "target-1" (e/get-element-text driver ".target")))))) |
781 | 971 |
|
782 | 972 | (deftest test-fn-index
|
783 | 973 | (testing ":fn/index"
|
|
786 | 976 | (e/get-element-text-el *driver*)))]
|
787 | 977 | (is (= items ["One" "Two" "Three" "Four" "Five"])))))
|
788 | 978 |
|
789 |
| -(deftest test-multiple-elements |
790 |
| - (testing "tag names" |
791 |
| - (let [q {:xpath ".//div[@id='operate-multiple-elements']//*"} |
792 |
| - elements (e/query-all *driver* q) |
793 |
| - tag-names (for [el elements] |
794 |
| - (str/lower-case (e/get-element-tag-el *driver* el)))] |
795 |
| - (is (= (vec tag-names) |
796 |
| - ["div" "b" "p" "span"]))))) |
797 |
| - |
798 | 979 | (deftest test-query-tree
|
799 | 980 | (let [url (test-server-url "test2.html")
|
800 | 981 | _ (e/go *driver* url)
|
|
0 commit comments