From 4754d946ce66d97a02e5824dcbd1936bba719feb Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Sun, 15 Sep 2024 21:11:04 -0500 Subject: [PATCH 01/11] Move test-fn-index into test-query --- test/etaoin/api_test.clj | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index f95fd4e..cdfc9e6 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -847,6 +847,10 @@ (is (= "ordered 3" (e/get-element-text-el *driver* el)))) (let [el (e/query *driver* {:class :list :fn/index 3})] ; new syntax (is (= "ordered 3" (e/get-element-text-el *driver* el)))) + (let [items (for [index (range 1 6)] + (->> (e/query *driver* {:class :indexed :fn/index index}) + (e/get-element-text-el *driver*)))] + (is (= items ["One" "Two" "Three" "Four" "Five"]))) ;; :fn/text (let [el (e/query *driver* {:fn/text "multiple classes"})] (is (= "multiple-classes" (e/get-element-attr-el *driver* el "id")))) @@ -955,13 +959,6 @@ (let [driver (e/use-css *driver*)] (is (= "target-1" (e/get-element-text driver ".target")))))) -(deftest test-fn-index - (testing ":fn/index" - (let [items (for [index (range 1 6)] - (->> (e/query *driver* {:class :indexed :fn/index index}) - (e/get-element-text-el *driver*)))] - (is (= items ["One" "Two" "Three" "Four" "Five"]))))) - (deftest test-query-tree (let [url (test-server-url "test2.html") _ (e/go *driver* url) From 832240765a0f79ce4188dbe3fd9c93c8953f4c31 Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Sun, 15 Sep 2024 21:18:47 -0500 Subject: [PATCH 02/11] Move :fn/has-string test from test-has-text to test-query --- test/etaoin/api_test.clj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index cdfc9e6..1508a83 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -860,6 +860,7 @@ ;; :fn/has-string (let [el (e/query *driver* {:tag :ol :fn/has-string "ordered 3"})] (is (= "ordered-list" (e/get-element-attr-el *driver* el "id")))) + (is (boolean (e/query *driver* {:fn/has-string "From the depth"}))) ;; :fn/has-class (let [el (e/query *driver* {:fn/has-class "ol-class1"})] (is (= "ordered-list" (e/get-element-attr-el *driver* el "id")))) @@ -1054,9 +1055,7 @@ (-> (e/has-text? "'quote") is))) (deftest test-has-text - (testing "test :fn/has-string" - (is (boolean (e/query *driver* {:fn/has-string "From the depth"})))) - (testing "gloval" + (testing "global" (is (e/has-text? *driver* "From the depths I've come!")) (is (e/has-text? *driver* "I've come from the dark"))) (testing "relative" From ef8e23827c697254bbd607d57b2af057c9e53f0f Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Sun, 15 Sep 2024 22:24:25 -0500 Subject: [PATCH 03/11] Refactor test-visible for better clarity --- test/etaoin/api_test.clj | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index 1508a83..e820986 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -182,11 +182,10 @@ (is (= (test-server-url "test2.html") (e/get-url *driver*)) "forward to 2nd page")) (deftest test-visible - (doto *driver* - (-> (e/visible? {:id :button-visible}) is) - (-> (e/invisible? {:id :button-hidden}) is) - (-> (e/invisible? {:id :div-hidden}) is) - (-> (e/invisible? {:id :dunno-foo-bar}) is))) + (is (e/visible? *driver* {:id :button-visible})) + (is (e/invisible? *driver* {:id :button-hidden})) + (is (e/invisible? *driver* {:id :div-hidden})) + (is (e/invisible? *driver* {:id :dunno-foo-bar}))) (deftest test-select (testing "test `select` on select-box" From 3356221dec24bca3823a289baadbb550979bc26d Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Sun, 15 Sep 2024 23:22:34 -0500 Subject: [PATCH 04/11] Add negative tests in test-query for invalid XPath and CSS --- test/etaoin/api_test.clj | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index e820986..15b51fc 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -901,7 +901,6 @@ (let [el (e/query *driver* {:class :foo} {:class :target})] (is (= "target-2" (e/get-element-text-el *driver* el))))) (testing "negative test cases" - ;; TODO: ;; 1. searching for nothing (testing "zero-length vector queries" ;; 1. pass a vector of length 0 to query @@ -920,7 +919,14 @@ {:tag :div :class :inside} :missing-element])))) ;; 3. malformed XPath + (testing "invalid XPath" + (e/with-xpath *driver* + (is (thrown+? [:type :etaoin/http-error] (e/query *driver* "..///[@@]"))))) ;; 4. malformed CSS + (testing "invalid CSS" + (e/with-css *driver* + ;; Turns out "..///[@@]" is also malformed CSS, too. + (is (thrown+? [:type :etaoin/http-error] (e/query *driver* "..///[@@]"))))) ;; 5. query isn't a string, map, or vector. Perhaps a list and set. ;; 6. unknown :fn/... keywords (testing "unknown :fn/* keywords" From eac8bd90924b302d3093066233863f2d10e53bfc Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Mon, 16 Sep 2024 10:49:07 -0500 Subject: [PATCH 05/11] Add negative tests for unsupported query types --- test/etaoin/api_test.clj | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index 15b51fc..367c472 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -927,7 +927,14 @@ (e/with-css *driver* ;; Turns out "..///[@@]" is also malformed CSS, too. (is (thrown+? [:type :etaoin/http-error] (e/query *driver* "..///[@@]"))))) - ;; 5. query isn't a string, map, or vector. Perhaps a list and set. + ;; 5. query isn't a string, map, or vector + (testing "unsupported query parameter types" + ;; 5a. Try a set + (is (thrown+? [:type :etaoin/argument] (e/query *driver* #{{:tag :div}}))) + ;; 5b. Try a list + (is (thrown+? [:type :etaoin/argument] (e/query *driver* '({:tag :div})))) + ;; 5c. Try a number + (is (thrown+? [:type :etaoin/argument] (e/query *driver* 1)))) ;; 6. unknown :fn/... keywords (testing "unknown :fn/* keywords" ;; ":fn/indx" is probably a typo and the user really wants ":fn/index" From f7340a417a3e7fdc56c5456e1d4fbdf07ef1a43b Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Tue, 24 Sep 2024 22:00:53 -0500 Subject: [PATCH 06/11] Add doc strings for wait-url-change and reload-test-page --- test/etaoin/api_test.clj | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index 367c472..6bcf562 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -130,14 +130,22 @@ test-server) (defn reload-test-page + "Allows a test to reload the test page, helping to provide an + intermediate reset, without having to let the fixture do it." [] (e/go *driver* (test-server-url "test.html")) (e/wait-visible *driver* {:id :document-end})) (defmacro wait-url-change - [re & body] + "Snapshots the URL in the browser that exists before the `trigger` is + executed, then executes `trigger`, and then waits for the URL to + change and for the URL `re-find` of the `re` to match the new + URL. This can be used to synchronize the test with the load of a new + page in the browser, particularly after trigger such as a click or + keypress results in a form submission." + [re & trigger] `(let [old-url# (e/get-url *driver*)] - ~@body + ~@trigger (e/wait-predicate (fn [] (let [new-url# (e/get-url *driver*)] (and (not= old-url# new-url#) (re-find ~re new-url#)))) From eec76cad93999c905ec03a1c1be2c314729484f3 Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Wed, 25 Sep 2024 11:39:27 -0500 Subject: [PATCH 07/11] Revise test-alert to remove Safari-specific delays --- test/etaoin/api_test.clj | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index 6bcf562..31246c2 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -357,21 +357,23 @@ (-> (e/absent? {:id :dunno-foo-bar}) is))) ;; In Safari, alerts work quite slow, so we add some delays. +;;; Sept 25, 2024: removed the delays. If this test starts to fail +;;; with Safari, will use `wait-predicate` to be smarter about waiting +;;; for specific conditions. (deftest test-alert - (doto *driver* - (e/click {:id :button-alert}) - (e/when-safari (e/wait 1)) - (-> e/get-alert-text (= "Hello!") is) - (-> e/has-alert? is) - (e/accept-alert) - (e/when-safari (e/wait 1)) - (-> e/has-alert? not is) - (e/click {:id :button-alert}) - (e/when-safari (e/wait 1)) - (-> e/has-alert? is) - (e/dismiss-alert) - (e/when-safari (e/wait 1)) - (-> e/has-alert? not is))) + (e/click *driver* {:id :button-alert}) + ;;(e/when-safari (e/wait 1)) + (is (= (e/get-alert-text *driver*) "Hello!")) + (is (e/has-alert? *driver*)) + (e/accept-alert *driver*) + ;;(e/when-safari *driver* (e/wait 1)) + (is (not (e/has-alert? *driver*))) + (e/click *driver* {:id :button-alert}) + ;;(e/when-safari *driver* (e/wait 1)) + (is (e/has-alert? *driver*)) + (e/dismiss-alert *driver*) + ;;(e/when-safari *driver* (e/wait 1)) + (is (not (e/has-alert? *driver*)))) (deftest test-properties (e/when-firefox *driver* From 9677fda480059f82a1b7b7495363a5b334ecfee3 Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Wed, 25 Sep 2024 11:51:28 -0500 Subject: [PATCH 08/11] Replaced wait with wait-predicate in test-switch-window Removed 3-second Safari-specific wait --- test/etaoin/api_test.clj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index 31246c2..deddab9 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -642,9 +642,10 @@ init-url (e/get-url *driver*)] ;; press enter on link instead of clicking (safaridriver is not great with the click) (e/fill *driver* :switch-window k/return) - (e/when-safari *driver* - (e/wait 3)) ;;safari seems to need a breather - (is (= 2 (count (e/get-window-handles *driver*))) "2 windows now exist") + (is (e/wait-predicate (fn [] (= 2 (count (e/get-window-handles *driver*)))) + {:timeout 30 + :interval 0.1 + :message "Timeout waiting for second window creation"})) (let [new-handles (e/get-window-handles *driver*) new-handle (first (filter #(not= % init-handle) new-handles)) _ (e/switch-window *driver* new-handle) From 3754699e1fa0ef6c842e1f51eba184e30ec8b2b2 Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Wed, 25 Sep 2024 12:19:30 -0500 Subject: [PATCH 09/11] Replace wait with wait-predicate in test-switch-window-next Removed 3-second Safari-specific wait --- test/etaoin/api_test.clj | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index deddab9..2c82d7d 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -657,16 +657,28 @@ (deftest test-switch-window-next (let [init-handle (e/get-window-handle *driver*)] - (doseq [_ (range 3)] + (dotimes [n 3] ;; press enter on link instead of clicking (safaridriver is not great with click) (e/fill *driver* :switch-window k/return) + ;; Wait for new window to show up + (e/wait-predicate + (fn [] (= (+ 1 (inc n)) (count (e/get-window-handles *driver*)))) + {:timeout 30 + :interval 0.1 + :message (format "Timeout waiting for window #%d to be created" + (+ n 2))}) ;; compensate: safari navigates to target window, others stay at source (e/when-safari *driver* - (e/wait 3) ;; safari seems to need a breather - (e/switch-window *driver* init-handle))) + (e/switch-window *driver* init-handle) + ;; Wait for window switch to "settle" before clicking again + (e/wait-predicate + (fn [] (= init-handle (e/get-window-handle *driver*))) + {:timeout 30 + :interval 0.1 + :message (format "Timeout waiting for window switch")}))) (is (= 4 (count (e/get-window-handles *driver*))) "4 windows now exist") (is (= init-handle (e/get-window-handle *driver*)) "on first window") - (doseq [_ (range 3)] + (dotimes [_ 3] (e/switch-window-next *driver*) (is (not= init-handle (e/get-window-handle *driver*)) "navigating new windows")) (e/switch-window-next *driver*) From 4bf80f03a8a6b499c239e57906cc3c3c9cd8c691 Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Wed, 25 Sep 2024 17:37:26 -0500 Subject: [PATCH 10/11] Replace wait with wait-predicate in test-add-script --- test/etaoin/api_test.clj | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index 2c82d7d..f2a65e7 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -821,7 +821,15 @@ (let [js-url (test-server-url "js/inject.js")] (testing "adding a script" (e/add-script *driver* js-url) - (e/wait 1) + ;; We need to wait for the browser to parse the + ;; script. Running "typeof " will + ;; return "function" if the function is defined (and "undefined" + ;; if not). + (e/wait-predicate + (fn [] (= "function" (e/js-execute *driver* "return typeof injected_func;"))) + {:timeout 30 + :internval 0.1 + :message "Timeout waiting for JavaScript to be parsed"}) (let [result (e/js-execute *driver* "return injected_func();")] (is (= result "I was injected")))))) From 709969bdb000131c4d32d75b5725d83edc65cac0 Mon Sep 17 00:00:00 2001 From: Dave Roberts Date: Wed, 25 Sep 2024 18:46:35 -0500 Subject: [PATCH 11/11] Fix typo in test-add-script (:internval -> :interval) --- test/etaoin/api_test.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index f2a65e7..99c7709 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -828,7 +828,7 @@ (e/wait-predicate (fn [] (= "function" (e/js-execute *driver* "return typeof injected_func;"))) {:timeout 30 - :internval 0.1 + :interval 0.1 :message "Timeout waiting for JavaScript to be parsed"}) (let [result (e/js-execute *driver* "return injected_func();")] (is (= result "I was injected"))))))