diff --git a/src/main/react_testing_library_cljs/async.clj b/src/main/react_testing_library_cljs/async.clj index 1f87f3c..b1e42e6 100644 --- a/src/main/react_testing_library_cljs/async.clj +++ b/src/main/react_testing_library_cljs/async.clj @@ -1,9 +1,13 @@ (ns react-testing-library-cljs.async) (defmacro deftest-async - "Like `cljs.test/deftest` but for async tests that return a Promise. + "Defines a `cljs.test/deftest` for an async test whose body returns a Promise. Wraps the body in `promesa.core/do`, so each top-level form is awaited - before the next runs. Automatically calls `done` when the Promise resolves. + before the next runs, then calls `done` when the Promise resolves. + + This is the compatibility path for toolchains without native ClojureScript + async functions. On shadow-cljs 3.4+ (ClojureScript 1.12.145+) prefer a + native `^:async` deftest with `await` instead. Requires `promesa` on the classpath. diff --git a/src/test/react_testing_library_cljs/deftest_async_macro_test.cljs b/src/test/react_testing_library_cljs/deftest_async_macro_test.cljs new file mode 100644 index 0000000..e278773 --- /dev/null +++ b/src/test/react_testing_library_cljs/deftest_async_macro_test.cljs @@ -0,0 +1,29 @@ +(ns react-testing-library-cljs.deftest-async-macro-test + "Smoke-tests the `deftest-async` macro, the pre-3.4 compatibility path. + Requires `promesa`; native `^:async` tests need shadow-cljs 3.4+ instead." + (:require + ["@testing-library/react" :as rtl] + ["react" :as react] + [cljs.test :refer [is]] + [promesa.core :as p] + [react-testing-library-cljs.async :refer-macros [deftest-async]] + [react-testing-library-cljs.screen :as screen])) + +(defn- render-el [element] + (rtl/render element)) + +(deftest-async find-by-text-test + (rtl/cleanup) + (render-el (react/createElement "div" nil "Macro Hello")) + (p/let [el (screen/find-by-text "Macro Hello")] + (is (some? el)) + (is (= "Macro Hello" (.-textContent el))))) + +(deftest-async find-all-by-text-test + (rtl/cleanup) + (render-el (react/createElement "div" nil + (react/createElement "span" nil "Item") + (react/createElement "span" nil "Item"))) + (p/let [els (screen/find-all-by-text "Item")] + (is (vector? els)) + (is (= 2 (count els))))) diff --git a/src/test/react_testing_library_cljs/native_async_test.cljs b/src/test/react_testing_library_cljs/native_async_test.cljs deleted file mode 100644 index ed2d431..0000000 --- a/src/test/react_testing_library_cljs/native_async_test.cljs +++ /dev/null @@ -1,27 +0,0 @@ -(ns react-testing-library-cljs.native-async-test - "Native ClojureScript async tests (`^:async` / `await`). - Requires shadow-cljs >= 3.4.x (ClojureScript >= 1.12.145)." - (:require - ["@testing-library/react" :as rtl] - ["react" :as react] - [cljs.test :refer [deftest is]] - [react-testing-library-cljs.screen :as screen])) - -(defn- render-el [element] - (rtl/render element)) - -(deftest ^:async find-by-text-native-test - (rtl/cleanup) - (render-el (react/createElement "div" nil "Native Hello")) - (let [el (await (screen/find-by-text "Native Hello"))] - (is (some? el)) - (is (= "Native Hello" (.-textContent el))))) - -(deftest ^:async find-all-by-text-native-test - (rtl/cleanup) - (render-el (react/createElement "div" nil - (react/createElement "span" nil "Row") - (react/createElement "span" nil "Row"))) - (let [els (await (screen/find-all-by-text "Row"))] - (is (vector? els)) - (is (= 2 (count els))))) diff --git a/src/test/react_testing_library_cljs/screen_async_test.cljs b/src/test/react_testing_library_cljs/screen_async_test.cljs index 624f515..5019512 100644 --- a/src/test/react_testing_library_cljs/screen_async_test.cljs +++ b/src/test/react_testing_library_cljs/screen_async_test.cljs @@ -1,28 +1,28 @@ (ns react-testing-library-cljs.screen-async-test + "Exercises `screen`'s async queries with native async (`^:async` / `await`). + Requires shadow-cljs 3.4+ (ClojureScript 1.12.145+)." (:require ["@testing-library/react" :as rtl] ["react" :as react] - [cljs.test :refer [is]] - [promesa.core :as p] - [react-testing-library-cljs.async :refer-macros [deftest-async]] + [cljs.test :refer [deftest is]] [react-testing-library-cljs.screen :as screen])) (defn- render-el [element] (rtl/render element)) -(deftest-async find-by-text-test +(deftest ^:async find-by-text-test (rtl/cleanup) (render-el (react/createElement "div" nil "Async Hello")) - (p/let [el (screen/find-by-text "Async Hello")] + (let [el (await (screen/find-by-text "Async Hello"))] (is (some? el)) (is (= "Async Hello" (.-textContent el))))) -(deftest-async find-all-by-text-test +(deftest ^:async find-all-by-text-test (rtl/cleanup) (render-el (react/createElement "div" nil (react/createElement "span" nil "Item") (react/createElement "span" nil "Item"))) - (p/let [els (screen/find-all-by-text "Item")] + (let [els (await (screen/find-all-by-text "Item"))] (is (vector? els)) (is (= 2 (count els))) (is (= "Item" (.-textContent (first els)))))) diff --git a/src/test/react_testing_library_cljs/user_event_async_test.cljs b/src/test/react_testing_library_cljs/user_event_async_test.cljs new file mode 100644 index 0000000..4a83566 --- /dev/null +++ b/src/test/react_testing_library_cljs/user_event_async_test.cljs @@ -0,0 +1,67 @@ +(ns react-testing-library-cljs.user-event-async-test + "Exercises user-event interactions with native async (`^:async` / `await`). + Requires shadow-cljs 3.4+ (ClojureScript 1.12.145+)." + (:require + ["@testing-library/react" :as rtl] + ["react" :as react] + [cljs.test :refer [deftest is]] + [react-testing-library-cljs.screen :as screen] + [react-testing-library-cljs.user-event :as user-event])) + +(defn- render-el [element] + (rtl/render element)) + +(deftest ^:async click-test + (rtl/cleanup) + (let [clicks (atom 0)] + (render-el (react/createElement "button" + #js {:onClick #(swap! clicks inc)} + "Click me")) + (await (user-event/click (user-event/setup) (screen/get-by-role "button"))) + (is (= 1 @clicks)))) + +(deftest ^:async type-test + (rtl/cleanup) + (render-el (react/createElement "input" + #js {:placeholder "type here" + :defaultValue ""})) + (await (user-event/type (user-event/setup) (screen/get-by-placeholder-text "type here") "hello")) + (is (= "hello" (.-value (screen/get-by-placeholder-text "type here"))))) + +(deftest ^:async clear-test + (rtl/cleanup) + (render-el (react/createElement "input" + #js {:placeholder "to clear" + :defaultValue "existing text"})) + (await (user-event/clear (user-event/setup) (screen/get-by-placeholder-text "to clear"))) + (is (= "" (.-value (screen/get-by-placeholder-text "to clear"))))) + +(deftest ^:async tab-test + (rtl/cleanup) + (render-el (react/createElement "div" nil + (react/createElement "input" #js {:placeholder "first"}) + (react/createElement "input" #js {:placeholder "second"}))) + (.focus (screen/get-by-placeholder-text "first")) + (await (user-event/tab (user-event/setup))) + (is (= (screen/get-by-placeholder-text "second") (.-activeElement js/document)))) + +(deftest ^:async keyboard-test + (rtl/cleanup) + (let [submitted (atom false)] + (render-el (react/createElement "form" + #js {:onSubmit (fn [e] + (.preventDefault e) + (reset! submitted true))} + (react/createElement "input" #js {:placeholder "press enter"}))) + (.focus (screen/get-by-placeholder-text "press enter")) + (await (user-event/keyboard (user-event/setup) "{Enter}")) + (is (true? @submitted)))) + +(deftest ^:async select-options-test + (rtl/cleanup) + (render-el (react/createElement "select" + #js {:defaultValue ""} + (react/createElement "option" #js {:value "a"} "Option A") + (react/createElement "option" #js {:value "b"} "Option B"))) + (await (user-event/select-options (user-event/setup) (screen/get-by-role "combobox") "Option A")) + (is (= "a" (.-value (screen/get-by-role "combobox"))))) diff --git a/src/test/react_testing_library_cljs/user_event_promesa_test.cljs b/src/test/react_testing_library_cljs/user_event_promesa_test.cljs index 023dc0d..c20f4b8 100644 --- a/src/test/react_testing_library_cljs/user_event_promesa_test.cljs +++ b/src/test/react_testing_library_cljs/user_event_promesa_test.cljs @@ -1,4 +1,7 @@ (ns react-testing-library-cljs.user-event-promesa-test + "Exercises user-event interactions with the `deftest-async` macro + `promesa`. + This is the pre-3.4 compatibility path; the native equivalents live in + `user-event-async-test`." (:require ["@testing-library/react" :as rtl] ["react" :as react] diff --git a/src/test/react_testing_library_cljs/within_native_async_test.cljs b/src/test/react_testing_library_cljs/within_async_test.cljs similarity index 86% rename from src/test/react_testing_library_cljs/within_native_async_test.cljs rename to src/test/react_testing_library_cljs/within_async_test.cljs index 44f7cda..e1493a7 100644 --- a/src/test/react_testing_library_cljs/within_native_async_test.cljs +++ b/src/test/react_testing_library_cljs/within_async_test.cljs @@ -1,6 +1,6 @@ -(ns react-testing-library-cljs.within-native-async-test - "Native ClojureScript async tests (`^:async` / `await`) for `within`. - Requires shadow-cljs >= 3.4.x (ClojureScript >= 1.12.145)." +(ns react-testing-library-cljs.within-async-test + "Exercises `within`'s async queries with native async (`^:async` / `await`). + Requires shadow-cljs 3.4+ (ClojureScript 1.12.145+)." (:require ["@testing-library/react" :as rtl] ["react" :as react]