Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 23 additions & 21 deletions examples/node-test-example/src/app/reagent_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,37 @@
"Testing Reagent components: render!, fire-event, screen, within, and mocks."
(:require
[app.components :refer [counter]]
[cljs.test :refer [deftest is testing]]
[cljs.test :refer [deftest is]]
[react-testing-library-cljs.mocks :as mocks]
[react-testing-library-cljs.reagent.fire-event :as fire-event]
[react-testing-library-cljs.reagent.render :refer [act render!]]
[react-testing-library-cljs.screen :as screen]
[react-testing-library-cljs.within :as within]))

(deftest counter-increments
(testing "clicking the button updates the rendered state"
(render! [counter])
(is (= "0" (.-textContent (screen/get-by-test-id "count"))))
;; Wrap interactions that cause re-renders in `act` so React flushes them.
(act #(fire-event/click (screen/get-by-role "button" {:name "Increment"})))
(is (= "1" (.-textContent (screen/get-by-test-id "count"))))))
(render! [counter])
(is (= "0" (.-textContent (screen/get-by-test-id "count")))
"renders the initial state")
;; Wrap interactions that cause re-renders in `act` so React flushes them.
(act #(fire-event/click (screen/get-by-role "button" {:name "Increment"})))
(is (= "1" (.-textContent (screen/get-by-test-id "count")))
"clicking the button updates the rendered state"))

(deftest scoped-queries-with-within
(testing "within scopes a query to a subtree"
(render! [:div
[:section {:aria-label "sidebar"}
[:button "Save"]]
[:button "Save"]])
(let [sidebar (screen/get-by-role "region" {:name "sidebar"})]
(is (some? (within/get-by-role sidebar "button" {:name "Save"})))
;; Two "Save" buttons exist overall; within disambiguates.
(is (= 2 (count (screen/get-all-by-role "button" {:name "Save"})))))))
(render! [:div
[:section {:aria-label "sidebar"}
[:button "Save"]]
[:button "Save"]])
(let [sidebar (screen/get-by-role "region" {:name "sidebar"})]
(is (some? (within/get-by-role sidebar "button" {:name "Save"}))
"within scopes a query to a subtree")
;; Two "Save" buttons exist overall; within disambiguates.
(is (= 2 (count (screen/get-all-by-role "button" {:name "Save"})))
"both buttons are found without scoping")))

(deftest mock-handler-records-calls
(testing "mocks/create returns [handler calls reset!]"
(let [[on-click calls] (mocks/create)]
(render! [:button {:on-click on-click} "Submit"])
(act #(fire-event/click (screen/get-by-text "Submit")))
(is (= 1 (count @calls))))))
(let [[on-click calls] (mocks/create)]
(render! [:button {:on-click on-click} "Submit"])
(act #(fire-event/click (screen/get-by-text "Submit")))
(is (= 1 (count @calls))
"the mock records the click")))
14 changes: 7 additions & 7 deletions examples/re-frame-example/src/app/events_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
(:require
[app.events :as events]
[app.subs :as subs]
[cljs.test :refer [deftest is testing]]))
[cljs.test :refer [deftest is]]))

(deftest event-handlers
(testing "initialize sets the starting count"
(is (= {:count 0} (events/initialize nil nil))))
(testing "increment bumps the count"
(is (= {:count 1} (events/increment {:count 0} nil)))))
(is (= {:count 0} (events/initialize nil nil))
"initialize sets the starting count")
(is (= {:count 1} (events/increment {:count 0} nil))
"increment bumps the count"))

(deftest subscription-handlers
(testing "count-value reads :count from the db"
(is (= 5 (subs/count-value {:count 5} nil)))))
(is (= 5 (subs/count-value {:count 5} nil))
"count-value reads :count from the db"))
34 changes: 18 additions & 16 deletions examples/re-frame-example/src/app/views_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
(:require
[app.events :as events]
[app.views :as views]
[cljs.test :refer [deftest is testing]]
[cljs.test :refer [deftest is]]
[re-frame.core :as rf]
[react-testing-library-cljs.reagent.fire-event :as fire-event]
[react-testing-library-cljs.reagent.render :refer [act render!]]
Expand All @@ -14,20 +14,22 @@
(.-textContent (screen/get-by-test-id "count")))

(deftest view-reflects-state
(testing "the view renders the current count and reacts to state changes"
(rf/dispatch-sync [::events/initialize])
(render! [views/counter])
(is (= "0" (count-text)))
;; dispatch-sync updates the db synchronously; act flushes the re-render.
(act #(rf/dispatch-sync [::events/increment]))
(is (= "1" (count-text)))))
(rf/dispatch-sync [::events/initialize])
(render! [views/counter])
(is (= "0" (count-text))
"renders the current count")
;; dispatch-sync updates the db synchronously; act flushes the re-render.
(act #(rf/dispatch-sync [::events/increment]))
(is (= "1" (count-text))
"reacts to state changes"))

(deftest ^:async clicking-button-increments
(testing "clicking the button dispatches an event and updates the view"
(rf/dispatch-sync [::events/initialize])
(render! [views/counter])
(is (= "0" (count-text)))
(fire-event/click (screen/get-by-role "button" {:name "Increment"}))
;; re-frame `dispatch` is asynchronous, so wait for the DOM to reflect the
;; new count rather than asserting immediately.
(is (some? (await (screen/find-by-text "1"))))))
(rf/dispatch-sync [::events/initialize])
(render! [views/counter])
(is (= "0" (count-text))
"renders the initial count")
(fire-event/click (screen/get-by-role "button" {:name "Increment"}))
;; re-frame `dispatch` is asynchronous, so wait for the DOM to reflect the
;; new count rather than asserting immediately.
(is (some? (await (screen/find-by-text "1")))
"clicking the button dispatches an event and updates the view"))
64 changes: 32 additions & 32 deletions src/test/react_testing_library_cljs/fire_event_test.cljs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ns react-testing-library-cljs.fire-event-test
(:require
["react" :as react]
[cljs.test :refer [deftest is testing]]
[cljs.test :refer [deftest is]]
[react-testing-library-cljs.fire-event :as fire-event]
[react-testing-library-cljs.render :as rtl]
[react-testing-library-cljs.screen :as screen]))
Expand All @@ -17,41 +17,41 @@
"Increment"))))

(deftest click-test
(testing "click fires and updates state"
(rtl/cleanup)
(rtl/render (react/createElement counter-component))
(let [btn (screen/get-by-text "Increment")]
(fire-event/click btn)
(is (= "1" (.-textContent (screen/get-by-test-id "count")))))))
(rtl/cleanup)
(rtl/render (react/createElement counter-component))
(let [btn (screen/get-by-text "Increment")]
(fire-event/click btn)
(is (= "1" (.-textContent (screen/get-by-test-id "count")))
"click fires and updates state")))

(deftest change-test
(testing "change updates input value"
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "type here"
:defaultValue ""}))
(let [input-el (screen/get-by-placeholder-text "type here")]
(fire-event/change input-el {:target {:value "new value"}})
(is (= "new value" (.-value input-el))))))
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "type here"
:defaultValue ""}))
(let [input-el (screen/get-by-placeholder-text "type here")]
(fire-event/change input-el {:target {:value "new value"}})
(is (= "new value" (.-value input-el))
"change updates input value")))

(deftest key-down-returns-default-prevented-boolean
(testing "returns true when nothing calls preventDefault (single arity)"
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "plain"}))
(is (true? (fire-event/key-down (screen/get-by-placeholder-text "plain")))))
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "plain"}))
(is (true? (fire-event/key-down (screen/get-by-placeholder-text "plain")))
"returns true when nothing calls preventDefault (single arity)")

(testing "returns true when nothing calls preventDefault (options arity)"
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "plain"}))
(is (true? (fire-event/key-down (screen/get-by-placeholder-text "plain") {:key " "}))))
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "plain"}))
(is (true? (fire-event/key-down (screen/get-by-placeholder-text "plain") {:key " "}))
"returns true when nothing calls preventDefault (options arity)")

(testing "returns false when a handler calls preventDefault (single arity)"
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "prevents"
:onKeyDown (fn [e] (.preventDefault e))}))
(is (false? (fire-event/key-down (screen/get-by-placeholder-text "prevents")))))
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "prevents"
:onKeyDown (fn [e] (.preventDefault e))}))
(is (false? (fire-event/key-down (screen/get-by-placeholder-text "prevents")))
"returns false when a handler calls preventDefault (single arity)")

(testing "returns false when a handler calls preventDefault (options arity)"
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "prevents"
:onKeyDown (fn [e] (.preventDefault e))}))
(is (false? (fire-event/key-down (screen/get-by-placeholder-text "prevents") {:key " "})))))
(rtl/cleanup)
(rtl/render (react/createElement "input" #js {:placeholder "prevents"
:onKeyDown (fn [e] (.preventDefault e))}))
(is (false? (fire-event/key-down (screen/get-by-placeholder-text "prevents") {:key " "}))
"returns false when a handler calls preventDefault (options arity)"))
48 changes: 26 additions & 22 deletions src/test/react_testing_library_cljs/mocks_test.cljs
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
(ns react-testing-library-cljs.mocks-test
(:require
[cljs.test :refer [deftest is testing]]
[cljs.test :refer [deftest is]]
[react-testing-library-cljs.fire-event :as fire-event]
[react-testing-library-cljs.mocks :as mocks]
[react-testing-library-cljs.reagent.render :as render]
[react-testing-library-cljs.screen :as screen]))

(deftest create-test
(testing "create returns a [calls handler reset!] triple"
(let [[handler calls reset!] (mocks/create)]
(is (= [] @calls))
(let [[handler calls reset!] (mocks/create)]
(is (= [] @calls)
"starts with no recorded calls")

(handler "arg1")
(is (= ["arg1"] @calls))
(handler "arg1")
(is (= ["arg1"] @calls)
"records the first call's args")

(handler "arg2")
(is (= ["arg1" "arg2"] @calls))
(handler "arg2")
(is (= ["arg1" "arg2"] @calls)
"appends subsequent calls")

(reset!)
(is (= [] @calls)))))
(reset!)
(is (= [] @calls)
"reset! clears the recorded calls")))

(deftest multiple-mocks-are-independent
(testing "separate mocks do not share state"
(let [[handler-a calls-a _] (mocks/create)
[handler-b calls-b _] (mocks/create)]
(handler-a "a")
(handler-b "b")
(is (= ["a"] @calls-a))
(is (= ["b"] @calls-b)))))
(let [[handler-a calls-a _] (mocks/create)
[handler-b calls-b _] (mocks/create)]
(handler-a "a")
(handler-b "b")
(is (= ["a"] @calls-a)
"separate mocks do not share state")
(is (= ["b"] @calls-b)
"separate mocks do not share state")))

(deftest tracks-button-click
(testing "a mock handler wired to a rendered button records clicks"
(let [[on-click calls] (mocks/create)]
(render/render! [:button {:on-click on-click} "Submit"])
(fire-event/click (screen/get-by-text "Submit"))
(is (= 1 (count @calls))))))
(let [[on-click calls] (mocks/create)]
(render/render! [:button {:on-click on-click} "Submit"])
(fire-event/click (screen/get-by-text "Submit"))
(is (= 1 (count @calls))
"a mock handler wired to a rendered button records clicks")))
80 changes: 41 additions & 39 deletions src/test/react_testing_library_cljs/reagent/fire_event_test.cljs
Original file line number Diff line number Diff line change
@@ -1,54 +1,56 @@
(ns react-testing-library-cljs.reagent.fire-event-test
(:require
[cljs.test :refer [deftest is testing]]
[cljs.test :refer [deftest is]]
[react-testing-library-cljs.reagent.fire-event :as fire-event]
[react-testing-library-cljs.reagent.render :refer [render! act]]
[react-testing-library-cljs.screen :as screen]
[reagent.core :as r]))

(deftest click-triggers-re-render
(testing "clicking a button updates state visibly"
(let [counter (r/atom 0)
component (fn [] [:div
[:span {:data-testid "count"} (str @counter)]
[:button {:on-click #(swap! counter inc)} "Inc"]])]
(render! [component])
(is (= "0" (.-textContent (screen/get-by-test-id "count"))))
(act #(fire-event/click (screen/get-by-text "Inc")))
(is (= "1" (.-textContent (screen/get-by-test-id "count")))))))
(let [counter (r/atom 0)
component (fn [] [:div
[:span {:data-testid "count"} (str @counter)]
[:button {:on-click #(swap! counter inc)} "Inc"]])]
(render! [component])
(is (= "0" (.-textContent (screen/get-by-test-id "count")))
"renders the initial count")
(act #(fire-event/click (screen/get-by-text "Inc")))
(is (= "1" (.-textContent (screen/get-by-test-id "count")))
"clicking a button updates state visibly")))

(deftest change-triggers-re-render
(testing "changing an input updates state visibly"
(let [value (r/atom "")
component (fn [] [:div
[:input {:data-testid "input"
:value @value
:on-change #(reset! value (.. % -target -value))}]
[:span {:data-testid "display"} @value]])]
(render! [component])
(is (= "" (.-textContent (screen/get-by-test-id "display"))))
(act #(fire-event/change (screen/get-by-test-id "input") {:target {:value "hello"}}))
(is (= "hello" (.-textContent (screen/get-by-test-id "display")))))))
(let [value (r/atom "")
component (fn [] [:div
[:input {:data-testid "input"
:value @value
:on-change #(reset! value (.. % -target -value))}]
[:span {:data-testid "display"} @value]])]
(render! [component])
(is (= "" (.-textContent (screen/get-by-test-id "display")))
"renders the initial empty value")
(act #(fire-event/change (screen/get-by-test-id "input") {:target {:value "hello"}}))
(is (= "hello" (.-textContent (screen/get-by-test-id "display")))
"changing an input updates state visibly")))

(deftest key-down-returns-default-prevented-boolean
(testing "returns true when nothing calls preventDefault (single arity)"
(let [component (fn [] [:input {:data-testid "plain"}])]
(render! [component])
(is (true? (fire-event/key-down (screen/get-by-test-id "plain"))))))
(let [component (fn [] [:input {:data-testid "plain"}])]
(render! [component])
(is (true? (fire-event/key-down (screen/get-by-test-id "plain")))
"returns true when nothing calls preventDefault (single arity)"))

(testing "returns true when nothing calls preventDefault (options arity)"
(let [component (fn [] [:input {:data-testid "plain"}])]
(render! [component])
(is (true? (fire-event/key-down (screen/get-by-test-id "plain") {:key " "})))))
(let [component (fn [] [:input {:data-testid "plain"}])]
(render! [component])
(is (true? (fire-event/key-down (screen/get-by-test-id "plain") {:key " "}))
"returns true when nothing calls preventDefault (options arity)"))

(testing "returns false when a handler calls preventDefault (single arity)"
(let [component (fn [] [:input {:data-testid "prevents"
:on-key-down #(.preventDefault %)}])]
(render! [component])
(is (false? (fire-event/key-down (screen/get-by-test-id "prevents"))))))
(let [component (fn [] [:input {:data-testid "prevents"
:on-key-down #(.preventDefault %)}])]
(render! [component])
(is (false? (fire-event/key-down (screen/get-by-test-id "prevents")))
"returns false when a handler calls preventDefault (single arity)"))

(testing "returns false when a handler calls preventDefault (options arity)"
(let [component (fn [] [:input {:data-testid "prevents"
:on-key-down #(.preventDefault %)}])]
(render! [component])
(is (false? (fire-event/key-down (screen/get-by-test-id "prevents") {:key " "}))))))
(let [component (fn [] [:input {:data-testid "prevents"
:on-key-down #(.preventDefault %)}])]
(render! [component])
(is (false? (fire-event/key-down (screen/get-by-test-id "prevents") {:key " "}))
"returns false when a handler calls preventDefault (options arity)")))
Loading
Loading