diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index f7aa2fb0..ef5091f0 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -7,6 +7,8 @@ A release with an intentional breaking changes is marked with: == Unreleased +* https://github.com/clj-commons/etaoin/pull/552[#552]: Add support for wide characters to input fill functions +(https://github.com/tupini07[@tupini07]) * bump all deps to current versions * docs ** https://github.com/clj-commons/etaoin/issues/534[#534]: better describe `etaoin.api/select` and its alternatives diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aa1c416b..1f831a81 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ - include changes unrelated to the purpose of the PR. This includes changing the project version number, adding lines to the `.gitignore` file, or changing the indentation or formatting. - open a new PR if changes are requested. Just push to the same branch and the PR will be updated. -- ever force push on a PR, it makes it too hard to review. +- never force push on a PR, it makes it too hard to review. - overuse vertical whitespace; avoid multiple sequential blank lines. [1]: https://chris.beams.io/posts/git-commit/#seven-rules diff --git a/README.adoc b/README.adoc index a31bb0cc..47ce353d 100644 --- a/README.adoc +++ b/README.adoc @@ -101,6 +101,7 @@ Can be `alpha`, `beta`, `rc1`, etc. * https://github.com/kidd[Raimon Grau] * https://github.com/verma[Uday Verma] * https://github.com/mjmeintjes[Matt Meintjes] +* https://github.com/tupini07[Andrea Tupini] === Current Maintainers diff --git a/doc/01-user-guide.adoc b/doc/01-user-guide.adoc index 6da09884..15a1895d 100644 --- a/doc/01-user-guide.adoc +++ b/doc/01-user-guide.adoc @@ -838,6 +838,27 @@ You can collect elements into a vector and arbitrarily interact with them at any Some basic interactions are covered under <>, here we go into other types of interactions and more detail. +=== UNICODE and Emojis +As of this writing, Chrome and Edge https://bugs.chromium.org/p/chromedriver/issues/detail?id=2269[only support] filling inputs with UNICODE in the https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane[Basic Multilingual Plane]. +This includes many characters, but not many emojis 😢. + +Firefox and Safari seem to support UNICODE more generally 🙂. + +[source,clojure] +---- +(e/with-chrome driver + (e/go driver sample-page) + (e/fill driver :uname "ⱾⱺⱮⱸ ᢹⓂ Ᵽ") + (e/get-element-value driver :uname)) +;; => "ⱾⱺⱮⱸ ᢹⓂ Ᵽ" + +(e/with-firefox driver + (e/go driver sample-page) + (e/fill driver :uname "ⱾⱺⱮⱸ ᢹⓂ Ᵽ plus 👍🔥🙂") + (e/get-element-value driver :uname)) +;; => "ⱾⱺⱮⱸ ᢹⓂ Ᵽ plus 👍🔥🙂" +---- + === Emulate how a Real Person Might Type Real people type slowly and make mistakes. @@ -861,6 +882,9 @@ which you can choose to override if you wish: ;; or just use default options by omitting them (e/fill-human driver :uname " typing human defaults") + +(e/get-element-value driver :uname) +;; => "soslowsobad typing human defaults" ---- For multiple inputs, use `fill-human-multi` @@ -2132,7 +2156,7 @@ Example: `:log-level :err` | `:all` -a| `driver-log-level` *WebDriver* minimal log level. +a| `:driver-log-level` *WebDriver* minimal log level. values vary by browser driver vendor: * chrome `"OFF"` `"SEVERE"` `"WARNING"` `"INFO"` or `"DEBUG"` diff --git a/src/etaoin/api.clj b/src/etaoin/api.clj index 14f76ba6..cfb5c2c9 100644 --- a/src/etaoin/api.clj +++ b/src/etaoin/api.clj @@ -2809,8 +2809,19 @@ ;; input ;; +(defn- codepoints + "Clojure returns a seq of chars for a string. + This does not handle wide (unicode) characters. + Here we return a seq of codepoint strings for string `s`." + [s] + (->> s + .codePoints + .iterator + iterator-seq + (map #(Character/toString %)))) + (defn- make-input* [text & more] - (mapv str (apply str text more))) + (codepoints (apply str text more))) (defmulti fill-el "Have `driver` fill input element `el` with `text` (and optionally `more` text)." @@ -2908,13 +2919,13 @@ wait-key (fn [] (wait (min (rand) pause-max)))] (click-el driver el) (wait-key) - (doseq [key text] + (doseq [c (codepoints text)] (when (< (rand) mistake-prob) (fill-el driver el (rand-char)) (wait-key) (fill-el driver el k/backspace) (wait-key)) - (fill-el driver el key) + (fill-el driver el c) (wait-key)))) (defn fill-human diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index d91b3218..9aa269cd 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -106,11 +106,11 @@ (-> e/get-url (str/ends-with? "?login=1&password=2&message=3") is))) - (testing "fill human multiple imputs" + (testing "fill human multiple inputs" (doto *driver* (e/fill-human-multi {:simple-input "login" - :simple-password "123" - :simple-textarea "text"}) + :simple-password "123" + :simple-textarea "text"}) (e/click :simple-submit) (e/when-safari (e/wait 3)) (-> e/get-url @@ -125,6 +125,37 @@ (str/ends-with? "?login=1test2+A&password=&message=") is)))) +(deftest test-unicode-bmp-input + (let [data {:simple-input "ĩṋṗṵţ" + :simple-password "ǷḁṡṢẅỏṟƉ" + :simple-textarea "т️ẹẍṱảṙẸẚ"}] + (testing "fill-multi" + (e/fill-multi *driver* data) + (doseq [f [:simple-input :simple-password :simple-textarea]] + (is (= (f data) (e/get-element-value *driver* f))))) + (testing "fill-human-multi" + (e/refresh *driver*) + (e/fill-human-multi *driver* data) + (doseq [f [:simple-input :simple-password :simple-textarea]] + (is (= (f data) (e/get-element-value *driver* f))))))) + +(deftest test-unicode-above-bmp-input + ;; as of 2023-04-29 not supported on chrome and edge + ;; https://bugs.chromium.org/p/chromedriver/issues/detail?id=2269 + (when-not (#{:chrome :edge} (e/dispatch-driver *driver*)) + (let [data {:simple-input "😊🍂input🍃" + :simple-password "🔆password☠️ " + :simple-textarea "🎉🚀textarea👀☀️"}] + (testing "fill-multi" + (e/fill-multi *driver* data) + (doseq [f [:simple-input :simple-password :simple-textarea]] + (is (= (f data) (e/get-element-value *driver* f))))) + (testing "fill-human-multi" + (e/refresh *driver*) + (e/fill-human-multi *driver* data) + (doseq [f [:simple-input :simple-password :simple-textarea]] + (is (= (f data) (e/get-element-value *driver* f)))))))) + (deftest test-clear (testing "simple clear" (doto *driver*