diff --git a/src/reagent/core.cljs b/src/reagent/core.cljs
index b6b8828..215d278 100644
--- a/src/reagent/core.cljs
+++ b/src/reagent/core.cljs
@@ -46,8 +46,8 @@
(defn as-element
"Turns a vector of Hiccup syntax into a React element. Returns form
unchanged if it is not a vector."
- [form]
- (tmpl/as-element form))
+ ([form] (tmpl/as-element form nil))
+ ([form opts] (tmpl/as-element form opts)))
(defn adapt-react-class
"Returns an adapter for a native React class, that may be used
@@ -60,9 +60,10 @@
"Returns an adapter for a Reagent component, that may be used from
React, for example in JSX. A single argument, props, is passed to
the component, converted to a map."
- [c]
- (assert-some c "Component")
- (comp/reactify-component c))
+ ([c] (reactify-component c nil))
+ ([c opts]
+ (assert-some c "Component")
+ (comp/reactify-component c opts)))
(defn render
"Render a Reagent component into the DOM. The first argument may be
diff --git a/src/reagent/dom.cljs b/src/reagent/dom.cljs
index a9ebc27..6827be8 100644
--- a/src/reagent/dom.cljs
+++ b/src/reagent/dom.cljs
@@ -34,10 +34,13 @@
Returns the mounted component instance."
([comp container]
(render comp container nil))
- ([comp container callback]
+ ([comp container callback-or-opts]
(ratom/flush!)
- (let [f (fn []
- (tmpl/as-element (if (fn? comp) (comp) comp)))]
+ (let [[opts callback] (if (fn? callback-or-opts)
+ [nil callback-or-opts]
+ [callback-or-opts (:callback callback-or-opts)])
+ f (fn []
+ (tmpl/as-element (if (fn? comp) (comp) comp) opts))]
(render-comp f container callback))))
(defn unmount-component-at-node
diff --git a/src/reagent/dom/server.cljs b/src/reagent/dom/server.cljs
index f538b53..da877bd 100644
--- a/src/reagent/dom/server.cljs
+++ b/src/reagent/dom/server.cljs
@@ -6,14 +6,18 @@
(defn render-to-string
"Turns a component into an HTML string."
- [component]
- (ratom/flush!)
- (binding [util/*non-reactive* true]
- (dom-server/renderToString (tmpl/as-element component))))
+ ([component]
+ (render-to-string component nil))
+ ([component opts]
+ (ratom/flush!)
+ (binding [util/*non-reactive* true]
+ (dom-server/renderToString (tmpl/as-element component opts)))))
(defn render-to-static-markup
"Turns a component into an HTML string, without data-react-id attributes, etc."
- [component]
- (ratom/flush!)
+ ([component]
+ (render-to-static-markup component nil))
+ ([component opts]
+ (ratom/flush!)
(binding [util/*non-reactive* true]
- (dom-server/renderToStaticMarkup (tmpl/as-element component))))
+ (dom-server/renderToStaticMarkup (tmpl/as-element component opts)))))
diff --git a/src/reagent/impl/component.cljs b/src/reagent/impl/component.cljs
index 77ef97d..915e2ad 100644
--- a/src/reagent/impl/component.cljs
+++ b/src/reagent/impl/component.cljs
@@ -111,10 +111,11 @@
5 (.call f c (nth v 1) (nth v 2) (nth v 3) (nth v 4))
(.apply f c (.slice (into-array v) 1)))))]
(cond
- (vector? res) (as-element res)
+ ;; FIXME: Opts
+ (vector? res) (as-element res nil)
(ifn? res) (let [f (if (reagent-class? res)
(fn [& args]
- (as-element (apply vector res args)))
+ (as-element (apply vector res args) nil))
res)]
(set! (.-reagentRender c) f)
(recur c))
@@ -373,7 +374,7 @@
cmp))
-(defn fn-to-class [f]
+(defn fn-to-class [f opts]
(assert-callable f)
(warn-unless (not (and (react-class? f)
(not (reagent-class? f))))
@@ -389,15 +390,16 @@
res (create-class withrender)]
(cache-react-class f res))))
-(defn as-class [tag]
+(defn as-class [tag opts]
+ ;; TODO: Cache per opts
(if-some [cached-class (cached-react-class tag)]
cached-class
- (fn-to-class tag)))
+ (fn-to-class tag opts)))
-(defn reactify-component [comp]
+(defn reactify-component [comp opts]
(if (react-class? comp)
comp
- (as-class comp)))
+ (as-class comp opts)))
(defn functional-wrap-render
[c]
@@ -406,10 +408,10 @@
argv (.-argv c)
res (apply f argv)]
(cond
- (vector? res) (as-element res)
+ (vector? res) (as-element res (.-opts c))
(ifn? res) (let [f (if (reagent-class? res)
(fn [& args]
- (as-element (apply vector res args)))
+ (as-element (apply vector res args) (.-opts c)))
res)]
(set! (.-reagentRender c) f)
(recur c))
@@ -501,6 +503,7 @@
original Reagent component."
[tag]
;; TODO: Could be disabled for optimized builds?
+ ;; TODO: Need to cache per opts?
(or (gobj/get fun-components tag)
(let [f (fn [jsprops] (functional-render jsprops))
_ (set! (.-displayName f) (util/fun-name tag))
diff --git a/src/reagent/impl/template.cljs b/src/reagent/impl/template.cljs
index 15333b6..db38bee 100644
--- a/src/reagent/impl/template.cljs
+++ b/src/reagent/impl/template.cljs
@@ -246,10 +246,10 @@
:component-did-update input-component-set-value
:component-will-unmount input-unmount
:reagent-render
- (fn [argv component jsprops first-child]
+ (fn [argv component jsprops first-child opts]
(let [this comp/*current-component*]
(input-render-setup this jsprops)
- (make-element argv component jsprops first-child)))})
+ (make-element argv component jsprops first-child opts)))})
(defn reagent-input
[]
@@ -293,13 +293,21 @@
(if (= :> (nth v 0 nil))
(get-key (nth v 2 nil))))))
-(defn reag-element [tag v]
+(defn reag-element [tag v opts]
+ (let [c (comp/as-class tag opts)
+ jsprops #js {}]
+ (set! (.-argv jsprops) v)
+ (when-some [key (key-from-vec v)]
+ (set! (.-key jsprops) key))
+ (react/createElement c jsprops)))
+
+(defn functional-reag-element [tag v opts]
(if (or (comp/react-class? tag)
;; TODO: Should check others for real comptibility, this fixes tests
;; TODO: Drop support for fn + meta for Class component methods?
(:should-component-update (meta tag)))
;; as-class unncessary later as tag is always class
- (let [c (comp/as-class tag)
+ (let [c (comp/as-class tag opts)
jsprops #js {}]
(set! (.-argv jsprops) v)
(when-some [key (key-from-vec v)]
@@ -308,6 +316,7 @@
(let [jsprops #js {}]
(set! (.-reagentRender jsprops) tag)
(set! (.-argv jsprops) (subvec v 1))
+ (set! (.-opts jsprops) opts)
(when-some [key (key-from-vec v)]
(set! (.-key jsprops) key))
(react/createElement (comp/funtional-render-fn tag) jsprops))))
@@ -335,7 +344,7 @@
(gobj/set tag-name-cache x v)
v)))
-(defn native-element [parsed argv first]
+(defn native-element [parsed argv first opts]
(let [component (.-tag parsed)
props (nth argv first nil)
hasprops (or (nil? props) (map? props))
@@ -343,13 +352,13 @@
#js {})
first-child (+ first (if hasprops 1 0))]
(if (input-component? component)
- (-> [(reagent-input) argv component jsprops first-child]
+ (-> [(reagent-input) argv component jsprops first-child opts]
(with-meta (meta argv))
- as-element)
+ (as-element opts))
(do
(when-some [key (-> (meta argv) get-key)]
(set! (.-key jsprops) key))
- (make-element argv component jsprops first-child)))))
+ (make-element argv component jsprops first-child opts)))))
(defn str-coll [coll]
(if (dev?)
@@ -365,7 +374,7 @@
(defn hiccup-err [v & msg]
(str (apply str msg) ": " (str-coll v) "\n" (comp/comp-name)))
-(defn vec-to-elem [v]
+(defn vec-to-elem [v opts]
(assert (pos? (count v)) (hiccup-err v "Hiccup form should not be empty"))
(let [tag (nth v 0 nil)]
(assert (valid-tag? tag) (hiccup-err v "Invalid Hiccup form"))
@@ -377,53 +386,56 @@
(let [n (name tag)
pos (.indexOf n ">")]
(case pos
- -1 (native-element (cached-parse n) v 1)
+ -1 (native-element (cached-parse n) v 1 opts)
0 (let [component (nth v 1 nil)]
;; Support [:> component ...]
(assert (= ">" n) (hiccup-err v "Invalid Hiccup tag"))
- (native-element (->HiccupTag component nil nil nil) v 2))
+ (native-element (->HiccupTag component nil nil nil) v 2 opts))
;; Support extended hiccup syntax, i.e :div.bar>a.foo
;; Apply metadata (e.g. :key) to the outermost element.
;; Metadata is probably used only with sequeneces, and in that case
;; only the key of the outermost element matters.
(recur (with-meta [(subs n 0 pos)
(assoc (with-meta v nil) 0 (subs n (inc pos)))]
- (meta v)))))
+ (meta v))
+ opts)))
(instance? NativeWrapper tag)
- (native-element tag v 1)
+ (native-element tag v 1 opts)
- :else (reag-element tag v))))
+ :else (if (:functional-reag-elements? opts)
+ (functional-reag-element tag v opts)
+ (reag-element tag v opts)))))
(declare expand-seq)
(declare expand-seq-check)
-(defn as-element [x]
+(defn as-element [x opts]
(cond (js-val? x) x
- (vector? x) (vec-to-elem x)
+ (vector? x) (vec-to-elem x opts)
(seq? x) (if (dev?)
- (expand-seq-check x)
- (expand-seq x))
+ (expand-seq-check x opts)
+ (expand-seq x opts))
(named? x) (name x)
(satisfies? IPrintWithWriter x) (pr-str x)
:else x))
(set! comp/as-element as-element)
-(defn expand-seq [s]
+(defn expand-seq [s opts]
(into-array (map as-element s)))
-(defn expand-seq-dev [s ^clj o]
+(defn expand-seq-dev [s ^clj o opts]
(into-array (map (fn [val]
(when (and (vector? val)
(nil? (key-from-vec val)))
(set! (.-no-key o) true))
- (as-element val))
+ (as-element val opts))
s)))
-(defn expand-seq-check [x]
+(defn expand-seq-check [x opts]
(let [ctx #js{}
- [res derefed] (ratom/check-derefs #(expand-seq-dev x ctx))]
+ [res derefed] (ratom/check-derefs #(expand-seq-dev x ctx opts))]
(when derefed
(warn (hiccup-err x "Reactive deref not supported in lazy seq, "
"it should be wrapped in doall")))
@@ -431,17 +443,17 @@
(warn (hiccup-err x "Every element in a seq should have a unique :key")))
res))
-(defn make-element [argv component jsprops first-child]
+(defn make-element [argv component jsprops first-child opts]
(case (- (count argv) first-child)
;; Optimize cases of zero or one child
0 (react/createElement component jsprops)
1 (react/createElement component jsprops
- (as-element (nth argv first-child nil)))
+ (as-element (nth argv first-child nil) opts))
(.apply react/createElement nil
(reduce-kv (fn [a k v]
(when (>= k first-child)
- (.push a (as-element v)))
+ (.push a (as-element v opts)))
a)
#js[component jsprops] argv))))
diff --git a/test/reagenttest/performancetest.cljs b/test/reagenttest/performancetest.cljs
index e129b08..78e8303 100644
--- a/test/reagenttest/performancetest.cljs
+++ b/test/reagenttest/performancetest.cljs
@@ -10,14 +10,14 @@
(js/performance.mark "functional-start")
; (simple-benchmark [x [hello-world-component]] (tmpl/vec-to-elem x) 100000)
(dotimes [i 100000]
- (tmpl/vec-to-elem [hello-world-component]))
+ (tmpl/vec-to-elem [hello-world-component] nil))
(js/performance.mark "functional-end")
(js/performance.measure "functional" "functional-start" "functional-end")
(js/performance.mark "class-start")
; (simple-benchmark [x [^:class-component hello-world-component]] (tmpl/vec-to-elem x) 100000)
(dotimes [i 100000]
- (tmpl/vec-to-elem [^:class-component hello-world-component]))
+ (tmpl/vec-to-elem [^:class-component hello-world-component] nil))
(js/performance.mark "class-end")
(js/performance.measure "class" "class-start" "class-end")
)
diff --git a/test/reagenttest/testreagent.cljs b/test/reagenttest/testreagent.cljs
index 9dc01fc..15827a1 100644
--- a/test/reagenttest/testreagent.cljs
+++ b/test/reagenttest/testreagent.cljs
@@ -19,8 +19,8 @@
:after (fn []
(set! rv/debug false))})
-(defn rstr [react-elem]
- (server/render-to-static-markup react-elem))
+(defn rstr [react-elem opts]
+ (server/render-to-static-markup react-elem opts))
(defn log-error [& f]
(debug/error (apply str f)))
@@ -34,315 +34,342 @@
(finally
(set! js/console.error org))))))
+;; Different set of options to try for most test cases
+
+(def test-options
+ [nil
+ {:functional-reag-elements? true}] )
+
(deftest really-simple-test
(when r/is-client
- (let [ran (r/atom 0)
- really-simple (fn []
- (swap! ran inc)
- [:div "div in really-simple"])]
- (with-mounted-component [really-simple nil nil]
- (fn [c div]
- (swap! ran inc)
- (is (= "div in really-simple" (.-innerText div)))
- (r/flush)
- (is (= 2 @ran))
- (rdom/force-update-all)
- (is (= 3 @ran))))
- (is (= 3 @ran)))))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ really-simple (fn []
+ (swap! ran inc)
+ [:div "div in really-simple"])]
+ (with-mounted-component [really-simple nil nil]
+ opts
+ (fn [c div]
+ (swap! ran inc)
+ (is (= "div in really-simple" (.-innerText div)))
+ (r/flush)
+ (is (= 2 @ran))
+ (rdom/force-update-all)
+ (is (= 3 @ran))))
+ (is (= 3 @ran))))))
(deftest test-simple-callback
(when r/is-client
- (let [ran (r/atom 0)
- comp (r/create-class
- {:component-did-mount #(swap! ran inc)
- :render
- (fn [this]
- (let [props (r/props this)]
- (is (map? props))
- (is (= props ((r/argv this) 1)))
- (is (= 1 (first (r/children this))))
- (is (= 1 (count (r/children this))))
- (swap! ran inc)
- [:div (str "hi " (:foo props) ".")]))})]
- (with-mounted-component [comp {:foo "you"} 1]
- (fn [C div]
- (swap! ran inc)
- (is (= "hi you." (.-innerText div)))))
- (is (= 3 @ran)))))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ comp (r/create-class
+ {:component-did-mount #(swap! ran inc)
+ :render
+ (fn [this]
+ (let [props (r/props this)]
+ (is (map? props))
+ (is (= props ((r/argv this) 1)))
+ (is (= 1 (first (r/children this))))
+ (is (= 1 (count (r/children this))))
+ (swap! ran inc)
+ [:div (str "hi " (:foo props) ".")]))})]
+ (with-mounted-component [comp {:foo "you"} 1]
+ opts
+ (fn [C div]
+ (swap! ran inc)
+ (is (= "hi you." (.-innerText div)))))
+ (is (= 3 @ran))))))
(deftest test-state-change
(when r/is-client
- (let [ran (r/atom 0)
- self (r/atom nil)
- comp (r/create-class
- {:get-initial-state (fn [] {:foo "initial"})
- :reagent-render
- (fn []
- (let [this (r/current-component)]
- (reset! self this)
- (swap! ran inc)
- [:div (str "hi " (:foo (r/state this)))]))})]
- (with-mounted-component [comp]
- (fn [C div]
- (swap! ran inc)
- (is (= "hi initial" (.-innerText div)))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ self (r/atom nil)
+ comp (r/create-class
+ {:get-initial-state (fn [] {:foo "initial"})
+ :reagent-render
+ (fn []
+ (let [this (r/current-component)]
+ (reset! self this)
+ (swap! ran inc)
+ [:div (str "hi " (:foo (r/state this)))]))})]
+ (with-mounted-component [comp]
+ opts
+ (fn [C div]
+ (swap! ran inc)
+ (is (= "hi initial" (.-innerText div)))
- (r/replace-state @self {:foo "there"})
- (r/state @self)
+ (r/replace-state @self {:foo "there"})
+ (r/state @self)
- (r/flush)
- (is (= "hi there" (.-innerText div)))
+ (r/flush)
+ (is (= "hi there" (.-innerText div)))
- (r/set-state @self {:foo "you"})
- (r/flush)
- (is (= "hi you" (.-innerText div)))))
- (is (= 4 @ran)))))
+ (r/set-state @self {:foo "you"})
+ (r/flush)
+ (is (= "hi you" (.-innerText div)))))
+ (is (= 4 @ran))))))
(deftest test-ratom-change
(when r/is-client
- (let [ran (r/atom 0)
- runs (rv/running)
- val (r/atom 0)
- secval (r/atom 0)
- v1-ran (atom 0)
- v1 (reaction (swap! v1-ran inc) @val)
- comp (fn []
- (swap! ran inc)
- [:div (str "val " @v1 " " @val " " @secval)])]
- (with-mounted-component [comp]
- (fn [C div]
- (r/flush)
- (is (not= runs (rv/running)))
- (is (= "val 0 0 0" (.-innerText div)))
- (is (= 1 @ran))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ runs (rv/running)
+ val (r/atom 0)
+ secval (r/atom 0)
+ v1-ran (atom 0)
+ v1 (reaction (swap! v1-ran inc) @val)
+ comp (fn []
+ (swap! ran inc)
+ [:div (str "val " @v1 " " @val " " @secval)])]
+ (with-mounted-component [comp]
+ opts
+ (fn [C div]
+ (r/flush)
+ (is (not= runs (rv/running)))
+ (is (= "val 0 0 0" (.-innerText div)))
+ (is (= 1 @ran))
- (reset! secval 1)
- (reset! secval 0)
- (reset! val 1)
- (reset! val 2)
- (reset! val 1)
- (is (= 1 @ran))
- (is (= 1 @v1-ran))
- (r/flush)
- (is (= "val 1 1 0" (.-innerText div)))
- (is (= 2 @ran) "ran once more")
- (is (= 2 @v1-ran))
+ (reset! secval 1)
+ (reset! secval 0)
+ (reset! val 1)
+ (reset! val 2)
+ (reset! val 1)
+ (is (= 1 @ran))
+ (is (= 1 @v1-ran))
+ (r/flush)
+ (is (= "val 1 1 0" (.-innerText div)))
+ (is (= 2 @ran) "ran once more")
+ (is (= 2 @v1-ran))
- ;; should not be rendered
- (reset! val 1)
- (is (= 2 @v1-ran))
- (r/flush)
- (is (= 2 @v1-ran))
- (is (= "val 1 1 0" (.-innerText div)))
- (is (= 2 @ran) "did not run")))
- (is (= runs (rv/running)))
- (is (= 2 @ran)))))
+ ;; should not be rendered
+ (reset! val 1)
+ (is (= 2 @v1-ran))
+ (r/flush)
+ (is (= 2 @v1-ran))
+ (is (= "val 1 1 0" (.-innerText div)))
+ (is (= 2 @ran) "did not run")))
+ (is (= runs (rv/running)))
+ (is (= 2 @ran))))))
(deftest batched-update-test []
(when r/is-client
- (let [ran (r/atom 0)
- v1 (r/atom 0)
- v2 (r/atom 0)
- c2 (fn [{val :val}]
- (swap! ran inc)
- (is (= val @v1))
- [:div @v2])
- c1 (fn []
- (swap! ran inc)
- [:div @v1
- [c2 {:val @v1}]])]
- (with-mounted-component [c1]
- (fn [c div]
- (r/flush)
- (is (= 2 @ran))
- (swap! v2 inc)
- (is (= 2 @ran))
- (r/flush)
- (is (= 3 @ran))
- (swap! v1 inc)
- (r/flush)
- (is (= 5 @ran))
- ;; TODO: Failing on optimized build
- ; (swap! v2 inc)
- ; (swap! v1 inc)
- ; (r/flush)
- ; (is (= 7 @ran))
- ; (swap! v1 inc)
- ; (swap! v1 inc)
- ; (swap! v2 inc)
- ; (r/flush)
- ; (is (= 9 @ran))
- )))))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ v1 (r/atom 0)
+ v2 (r/atom 0)
+ c2 (fn [{val :val}]
+ (swap! ran inc)
+ (is (= val @v1))
+ [:div @v2])
+ c1 (fn []
+ (swap! ran inc)
+ [:div @v1
+ [c2 {:val @v1}]])]
+ (with-mounted-component [c1]
+ opts
+ (fn [c div]
+ (r/flush)
+ (is (= 2 @ran))
+ (swap! v2 inc)
+ (is (= 2 @ran))
+ (r/flush)
+ (is (= 3 @ran))
+ (swap! v1 inc)
+ (r/flush)
+ (is (= 5 @ran))
+ ;; TODO: Failing on optimized build
+ ; (swap! v2 inc)
+ ; (swap! v1 inc)
+ ; (r/flush)
+ ; (is (= 7 @ran))
+ ; (swap! v1 inc)
+ ; (swap! v1 inc)
+ ; (swap! v2 inc)
+ ; (r/flush)
+ ; (is (= 9 @ran))
+ ))))))
(deftest init-state-test
(when r/is-client
- (let [ran (r/atom 0)
- really-simple (fn []
- (let [this (r/current-component)]
- (swap! ran inc)
- (r/set-state this {:foo "foobar"})
- (fn []
- [:div (str "this is "
- (:foo (r/state this)))])))]
- (with-mounted-component [really-simple nil nil]
- (fn [c div]
- (swap! ran inc)
- (is (= "this is foobar" (.-innerText div)))))
- (is (= 2 @ran)))))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ really-simple (fn []
+ (let [this (r/current-component)]
+ (swap! ran inc)
+ (r/set-state this {:foo "foobar"})
+ (fn []
+ [:div (str "this is "
+ (:foo (r/state this)))])))]
+ (with-mounted-component [really-simple nil nil]
+ opts
+ (fn [c div]
+ (swap! ran inc)
+ (is (= "this is foobar" (.-innerText div)))))
+ (is (= 2 @ran))))))
(deftest should-update-test
(when r/is-client
- (let [parent-ran (r/atom 0)
- child-ran (r/atom 0)
- child-props (r/atom nil)
- f (fn [])
- f1 (fn [])
- child (fn [p]
- (swap! child-ran inc)
- [:div (:val p)])
- parent (fn []
- (swap! parent-ran inc)
- [:div "child-foo" [child @child-props]])]
- (with-mounted-component [parent nil nil]
- (fn [c div]
- (r/flush)
- (is (= 1 @child-ran))
- (is (= "child-foo" (.-innerText div)))
+ (doseq [opts test-options]
+ (let [parent-ran (r/atom 0)
+ child-ran (r/atom 0)
+ child-props (r/atom nil)
+ f (fn [])
+ f1 (fn [])
+ child (fn [p]
+ (swap! child-ran inc)
+ [:div (:val p)])
+ parent (fn []
+ (swap! parent-ran inc)
+ [:div "child-foo" [child @child-props]])]
+ (with-mounted-component [parent nil nil]
+ opts
+ (fn [c div]
+ (r/flush)
+ (is (= 1 @child-ran))
+ (is (= "child-foo" (.-innerText div)))
- (reset! child-props {:style {:display :none}})
- (r/flush)
- (is (= 2 @child-ran))
+ (reset! child-props {:style {:display :none}})
+ (r/flush)
+ (is (= 2 @child-ran))
- (reset! child-props {:style {:display :none}})
- (r/flush)
- (is (= 2 @child-ran) "keyw is equal")
+ (reset! child-props {:style {:display :none}})
+ (r/flush)
+ (is (= 2 @child-ran) "keyw is equal")
- (reset! child-props {:class :foo}) (r/flush)
- (r/flush)
- (is (= 3 @child-ran))
+ (reset! child-props {:class :foo}) (r/flush)
+ (r/flush)
+ (is (= 3 @child-ran))
- (reset! child-props {:class :foo}) (r/flush)
- (r/flush)
- (is (= 3 @child-ran))
+ (reset! child-props {:class :foo}) (r/flush)
+ (r/flush)
+ (is (= 3 @child-ran))
- (reset! child-props {:class 'foo})
- (r/flush)
- (is (= 4 @child-ran) "symbols are different from keyw")
+ (reset! child-props {:class 'foo})
+ (r/flush)
+ (is (= 4 @child-ran) "symbols are different from keyw")
- (reset! child-props {:class 'foo})
- (r/flush)
- (is (= 4 @child-ran) "symbols are equal")
+ (reset! child-props {:class 'foo})
+ (r/flush)
+ (is (= 4 @child-ran) "symbols are equal")
- (reset! child-props {:style {:color 'red}})
- (r/flush)
- (is (= 5 @child-ran))
+ (reset! child-props {:style {:color 'red}})
+ (r/flush)
+ (is (= 5 @child-ran))
- (reset! child-props {:on-change (r/partial f)})
- (r/flush)
- (is (= 6 @child-ran))
+ (reset! child-props {:on-change (r/partial f)})
+ (r/flush)
+ (is (= 6 @child-ran))
- (reset! child-props {:on-change (r/partial f)})
- (r/flush)
- (is (= 6 @child-ran))
+ (reset! child-props {:on-change (r/partial f)})
+ (r/flush)
+ (is (= 6 @child-ran))
- (reset! child-props {:on-change (r/partial f1)})
- (r/flush)
- (is (= 7 @child-ran))
+ (reset! child-props {:on-change (r/partial f1)})
+ (r/flush)
+ (is (= 7 @child-ran))
- (rdom/force-update-all)
- (is (= 8 @child-ran)))))))
+ (rdom/force-update-all)
+ (is (= 8 @child-ran))))))))
(deftest dirty-test
(when r/is-client
- (let [ran (r/atom 0)
- state (r/atom 0)
- really-simple (fn []
- (swap! ran inc)
- (if (= 1 @state)
- (reset! state 3))
- [:div (str "state=" @state)])]
- (with-mounted-component [really-simple nil nil]
- (fn [c div]
- (is (= 1 @ran))
- (is (= "state=0" (.-innerText div)))
- (reset! state 1)
- (r/flush)
- (is (= 2 @ran))
- (is (= "state=3" (.-innerText div)))))
- (is (= 2 @ran)))))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ state (r/atom 0)
+ really-simple (fn []
+ (swap! ran inc)
+ (if (= 1 @state)
+ (reset! state 3))
+ [:div (str "state=" @state)])]
+ (with-mounted-component [really-simple nil nil]
+ opts
+ (fn [c div]
+ (is (= 1 @ran))
+ (is (= "state=0" (.-innerText div)))
+ (reset! state 1)
+ (r/flush)
+ (is (= 2 @ran))
+ (is (= "state=3" (.-innerText div)))))
+ (is (= 2 @ran))))))
-(defn as-string [comp]
- (server/render-to-static-markup comp))
+(defn as-string [comp opts]
+ (server/render-to-static-markup comp opts))
(deftest to-string-test []
- (let [comp (fn [props]
- [:div (str "i am " (:foo props))])]
- (is (= "
i am foobar
" (as-string [comp {:foo "foobar"}])))))
+ (doseq [opts test-options]
+ (let [comp (fn [props]
+ [:div (str "i am " (:foo props))])]
+ (is (= "i am foobar
" (as-string [comp {:foo "foobar"}] opts))))))
(deftest data-aria-test []
- (is (= ""
- (as-string [:div {:data-foo "x"}])))
- (is (= ""
- (as-string [:div {:aria-labelledby "x"}])))
- ;; Skip test: produces warning in new React
- ;; (is (not (re-find #"enctype"
- ;; (as-string [:div {"enc-type" "x"}])))
- ;; "Strings are passed through to React.")
- ;; FIXME: For some reason UMD module returns everything in
- ;; lowercase, and CommonJS with upper T
- (is (re-find #"enc[tT]ype"
- (as-string [:div {"encType" "x"}]))
- "Strings are passed through to React, and have to be camelcase.")
- (is (re-find #"enc[tT]ype"
- (as-string [:div {:enc-type "x"}]))
- "Strings are passed through to React, and have to be camelcase."))
+ (doseq [opts test-options]
+ (is (= ""
+ (as-string [:div {:data-foo "x"}] opts)))
+ (is (= ""
+ (as-string [:div {:aria-labelledby "x"}] opts)))
+ ;; Skip test: produces warning in new React
+ ;; (is (not (re-find #"enctype"
+ ;; (as-string [:div {"enc-type" "x"}])))
+ ;; "Strings are passed through to React.")
+ ;; FIXME: For some reason UMD module returns everything in
+ ;; lowercase, and CommonJS with upper T
+ (is (re-find #"enc[tT]ype"
+ (as-string [:div {"encType" "x"}] opts))
+ "Strings are passed through to React, and have to be camelcase.")
+ (is (re-find #"enc[tT]ype"
+ (as-string [:div {:enc-type "x"}] opts))
+ "Strings are passed through to React, and have to be camelcase.")))
(deftest dynamic-id-class []
- (is (re-find #"id=.foo"
- (as-string [:div#foo {:class "bar"}])))
- (is (= ""
- (as-string [:div.foo {:class "bar"}])))
- (is (= ""
- (as-string [:div.foo.bar])))
- (is (= ""
- (as-string [:div.foo {:className "bar"}])))
- (is (= ""
- (as-string [:div {:className "foo bar"}])))
- (is (re-find #"id=.foo"
- (as-string [:div#foo.foo.bar])))
- (is (re-find #"class=.xxx bar"
- (as-string [:div#foo.xxx.bar])))
- (is (re-find #"id=.foo"
- (as-string [:div.bar {:id "foo"}])))
- (is (re-find #"id=.foo"
- (as-string [:div.bar.xxx {:id "foo"}])))
- (is (= ""
- (as-string [:div#bar {:id "foo"}]))
- "Dynamic id overwrites static"))
+ (doseq [opts test-options]
+ (is (re-find #"id=.foo"
+ (as-string [:div#foo {:class "bar"}] opts)))
+ (is (= ""
+ (as-string [:div.foo {:class "bar"}] opts)))
+ (is (= ""
+ (as-string [:div.foo.bar] opts)))
+ (is (= ""
+ (as-string [:div.foo {:className "bar"}] opts)))
+ (is (= ""
+ (as-string [:div {:className "foo bar"}] opts)))
+ (is (re-find #"id=.foo"
+ (as-string [:div#foo.foo.bar] opts)))
+ (is (re-find #"class=.xxx bar"
+ (as-string [:div#foo.xxx.bar] opts)))
+ (is (re-find #"id=.foo"
+ (as-string [:div.bar {:id "foo"}] opts)))
+ (is (re-find #"id=.foo"
+ (as-string [:div.bar.xxx {:id "foo"}] opts)))
+ (is (= ""
+ (as-string [:div#bar {:id "foo"}] opts))
+ "Dynamic id overwrites static")))
(defmulti my-div :type)
(defmethod my-div :fooish [child] [:div.foo (:content child)])
(defmethod my-div :barish [child] [:div.bar (:content child)])
(deftest ifn-component []
- (let [comp {:foo [:div "foodiv"]
- :bar [:div "bardiv"]}]
- (is (= ""
- (as-string [:div [comp :foo]])))
- (is (= ""
- (as-string [:div [comp :bar]])))
- (is (= "inner
"
- (as-string [my-div {:type :fooish :content "inner"}])))))
+ (doseq [opts test-options]
+ (let [comp {:foo [:div "foodiv"]
+ :bar [:div "bardiv"]}]
+ (is (= ""
+ (as-string [:div [comp :foo]] opts)))
+ (is (= ""
+ (as-string [:div [comp :bar]] opts)))
+ (is (= "inner
"
+ (as-string [my-div {:type :fooish :content "inner"}] opts))))))
(deftest symbol-string-tag []
- (is (= "foobar
" (as-string ['div "foobar"])))
- (is (= "foobar
" (as-string ["div" "foobar"])))
- (is (= "x
" (as-string ['div#foo "x"])))
- (is (= "x
" (as-string ["div#foo" "x"])))
- (is (= "" (as-string ['div.foo {:class "bar"}])))
- (is (= "" (as-string ["div.foo.bar"])))
- (is (re-find #"id=.foo"
- (as-string ['div#foo.foo.bar]))))
+ (doseq [opts test-options]
+ (is (= "foobar
" (as-string ['div "foobar"] opts)))
+ (is (= "foobar
" (as-string ["div" "foobar"] opts)))
+ (is (= "x
" (as-string ['div#foo "x"] opts)))
+ (is (= "x
" (as-string ["div#foo" "x"] opts)))
+ (is (= "" (as-string ['div.foo {:class "bar"}] opts)))
+ (is (= "" (as-string ["div.foo.bar"] opts)))
+ (is (re-find #"id=.foo"
+ (as-string ['div#foo.foo.bar] opts)))))
(deftest partial-test []
(let [p1 (r/partial vector 1 2)]
@@ -354,64 +381,70 @@
(is (= (hash p1) (hash (r/partial vector 1 2))))))
(deftest test-null-component
- (let [null-comp (fn [do-show]
- (when do-show
- [:div "div in test-null-component"]))]
- (is (= ""
- (as-string [null-comp false])))
- (is (= "div in test-null-component
"
- (as-string [null-comp true])))))
+ (doseq [opts test-options]
+ (let [null-comp (fn [do-show]
+ (when do-show
+ [:div "div in test-null-component"]))]
+ (is (= ""
+ (as-string [null-comp false] opts)))
+ (is (= "div in test-null-component
"
+ (as-string [null-comp true] opts))))))
(deftest test-string
- (is (= "foo
"
- (server/render-to-string [:div "foo"])))
+ (doseq [opts test-options]
+ (is (= "foo
"
+ (server/render-to-string [:div "foo"] opts)))
- (is (= ""
- (server/render-to-string [:div [:p "foo"]]))))
+ (is (= ""
+ (server/render-to-string [:div [:p "foo"]] opts)))))
(deftest test-static-markup
- (is (= "foo
"
- (rstr [:div "foo"])))
- (is (= ""
- (rstr [:div.bar [:p "foo"]])))
- (is (= ""
- (rstr [:div.bar {:dangerously-set-inner-HTML
- {:__html "foobar
"}} ]))))
+ (doseq [opts test-options]
+ (is (= "foo
"
+ (rstr [:div "foo"] opts)))
+ (is (= ""
+ (rstr [:div.bar [:p "foo"]] opts)))
+ (is (= ""
+ (rstr [:div.bar {:dangerously-set-inner-HTML
+ {:__html "foobar
"}}] opts)))))
(deftest test-return-class
(when r/is-client
- (let [ran (r/atom 0)
- top-ran (r/atom 0)
- comp (fn []
- (swap! top-ran inc)
- (r/create-class
- {:component-did-mount #(swap! ran inc)
- :render
- (fn [this]
- (let [props (r/props this)]
- (is (map? props))
- (is (= props ((r/argv this) 1)))
- (is (= 1 (first (r/children this))))
- (is (= 1 (count (r/children this))))
- (swap! ran inc)
- [:div (str "hi " (:foo props) ".")]))}))
- prop (r/atom {:foo "you"})
- parent (fn [] [comp @prop 1])]
- (with-mounted-component [parent]
- (fn [C div]
- (swap! ran inc)
- (is (= "hi you." (.-innerText div)))
- (is (= 1 @top-ran))
- (is (= 3 @ran))
+ (doseq [opts test-options]
+ (let [ran (r/atom 0)
+ top-ran (r/atom 0)
+ comp (fn []
+ (swap! top-ran inc)
+ (r/create-class
+ {:component-did-mount #(swap! ran inc)
+ :render
+ (fn [this]
+ (let [props (r/props this)]
+ (is (map? props))
+ (is (= props ((r/argv this) 1)))
+ (is (= 1 (first (r/children this))))
+ (is (= 1 (count (r/children this))))
+ (swap! ran inc)
+ [:div (str "hi " (:foo props) ".")]))}))
+ prop (r/atom {:foo "you"})
+ parent (fn [] [comp @prop 1])]
+ (with-mounted-component [parent]
+ opts
+ (fn [C div]
+ (swap! ran inc)
+ (is (= "hi you." (.-innerText div)))
+ (is (= 1 @top-ran))
+ (is (= 3 @ran))
- (swap! prop assoc :foo "me")
- (r/flush)
- (is (= "hi me." (.-innerText div)))
- (is (= 1 @top-ran))
- (is (= 4 @ran)))))))
+ (swap! prop assoc :foo "me")
+ (r/flush)
+ (is (= "hi me." (.-innerText div)))
+ (is (= 1 @top-ran))
+ (is (= 4 @ran))))))))
(deftest test-return-class-fn
(when r/is-client
+ (doseq [opts test-options]
(let [ran (r/atom 0)
top-ran (r/atom 0)
comp (fn []
@@ -426,6 +459,7 @@
prop (r/atom {:foo "you"})
parent (fn [] [comp @prop 1])]
(with-mounted-component [parent]
+ opts
(fn [C div]
(swap! ran inc)
(is (= "hi you." (.-innerText div)))
@@ -436,31 +470,33 @@
(r/flush)
(is (= "hi me." (.-innerText div)))
(is (= 1 @top-ran))
- (is (= 4 @ran)))))))
+ (is (= 4 @ran))))))))
(deftest test-create-element
- (let [ae r/as-element
- ce r/create-element]
- (is (= (rstr (ce "div"))
- (rstr (ae [:div]))))
- (is (= (rstr (ce "div" nil))
- (rstr (ae [:div]))))
- (is (= (rstr (ce "div" nil "foo"))
- (rstr (ae [:div "foo"]))))
- (is (= (rstr (ce "div" nil "foo" "bar"))
- (rstr (ae [:div "foo" "bar"]))))
- (is (= (rstr (ce "div" nil "foo" "bar" "foobar"))
- (rstr (ae [:div "foo" "bar" "foobar"]))))
+ (doseq [opts test-options]
+ (let [ae r/as-element
+ ce r/create-element
+ rstr #(rstr % opts)]
+ (is (= (rstr (ce "div"))
+ (rstr (ae [:div]))))
+ (is (= (rstr (ce "div" nil))
+ (rstr (ae [:div]))))
+ (is (= (rstr (ce "div" nil "foo"))
+ (rstr (ae [:div "foo"]))))
+ (is (= (rstr (ce "div" nil "foo" "bar"))
+ (rstr (ae [:div "foo" "bar"]))))
+ (is (= (rstr (ce "div" nil "foo" "bar" "foobar"))
+ (rstr (ae [:div "foo" "bar" "foobar"]))))
- (is (= (rstr (ce "div" #js{:className "foo"} "bar"))
- (rstr (ae [:div.foo "bar"]))))
+ (is (= (rstr (ce "div" #js{:className "foo"} "bar"))
+ (rstr (ae [:div.foo "bar"]))))
- (is (= (rstr (ce "div" nil (ce "div" nil "foo")))
- (rstr (ae [:div [:div "foo"]]))))
- (is (= (rstr (ce "div" nil (ae [:div "foo"])))
- (rstr (ae [:div [:div "foo"]]))))
- (is (= (rstr (ae [:div (ce "div" nil "foo")]))
- (rstr (ae [:div [:div "foo"]]))))))
+ (is (= (rstr (ce "div" nil (ce "div" nil "foo")))
+ (rstr (ae [:div [:div "foo"]]))))
+ (is (= (rstr (ce "div" nil (ae [:div "foo"])))
+ (rstr (ae [:div [:div "foo"]]))))
+ (is (= (rstr (ae [:div (ce "div" nil "foo")]))
+ (rstr (ae [:div [:div "foo"]])))))))
(def ndiv (let [cmp (fn [])]
(gobj/extend
@@ -476,54 +512,58 @@
cmp))
(deftest test-adapt-class
- (let [d1 (r/adapt-react-class ndiv)
- d2 (r/adapt-react-class "div")]
- (is (= (rstr [:div])
- (rstr [d1])))
- (is (= (rstr [:div "a"])
- (rstr [d1 "a"])))
- (is (= (rstr [:div "a" "b"])
- (rstr [d1 "a" "b"])))
- (is (= (rstr [:div.foo "a"])
- (rstr [d1 {:class "foo"} "a"])))
- (is (= (rstr [:div "a" "b" [:div "c"]])
- (rstr [d1 "a" "b" [:div "c"]])))
+ (doseq [opts test-options]
+ (let [d1 (r/adapt-react-class ndiv)
+ d2 (r/adapt-react-class "div")
+ rstr #(rstr % opts)]
+ (is (= (rstr [:div])
+ (rstr [d1])))
+ (is (= (rstr [:div "a"])
+ (rstr [d1 "a"])))
+ (is (= (rstr [:div "a" "b"])
+ (rstr [d1 "a" "b"])))
+ (is (= (rstr [:div.foo "a"])
+ (rstr [d1 {:class "foo"} "a"])))
+ (is (= (rstr [:div "a" "b" [:div "c"]])
+ (rstr [d1 "a" "b" [:div "c"]])))
- (is (= (rstr [:div])
- (rstr [d2])))
- (is (= (rstr [:div "a"])
- (rstr [d2 "a"])))
- (is (= (rstr [:div "a" "b"])
- (rstr [d2 "a" "b"])))
- (is (= (rstr [:div.foo "a"])
- (rstr [d2 {:class "foo"} "a"])))
- (is (= (rstr [:div "a" "b" [:div "c"]])
- (rstr [d2 "a" "b" [:div "c"]])))))
+ (is (= (rstr [:div])
+ (rstr [d2])))
+ (is (= (rstr [:div "a"])
+ (rstr [d2 "a"])))
+ (is (= (rstr [:div "a" "b"])
+ (rstr [d2 "a" "b"])))
+ (is (= (rstr [:div.foo "a"])
+ (rstr [d2 {:class "foo"} "a"])))
+ (is (= (rstr [:div "a" "b" [:div "c"]])
+ (rstr [d2 "a" "b" [:div "c"]]))))))
(deftest test-adapt-class-2
- (let [d1 ndiv
- d2 "div"]
- (is (= (rstr [:div])
- (rstr [:> d1])))
- (is (= (rstr [:div "a"])
- (rstr [:> d1 "a"])))
- (is (= (rstr [:div "a" "b"])
- (rstr [:> d1 "a" "b"])))
- (is (= (rstr [:div.foo "a"])
- (rstr [:> d1 {:class "foo"} "a"])))
- (is (= (rstr [:div "a" "b" [:div "c"]])
- (rstr [:> d1 "a" "b" [:div "c"]])))
+ (doseq [opts test-options]
+ (let [d1 ndiv
+ d2 "div"
+ rstr #(rstr % opts)]
+ (is (= (rstr [:div])
+ (rstr [:> d1])))
+ (is (= (rstr [:div "a"])
+ (rstr [:> d1 "a"])))
+ (is (= (rstr [:div "a" "b"])
+ (rstr [:> d1 "a" "b"])))
+ (is (= (rstr [:div.foo "a"])
+ (rstr [:> d1 {:class "foo"} "a"])))
+ (is (= (rstr [:div "a" "b" [:div "c"]])
+ (rstr [:> d1 "a" "b" [:div "c"]])))
- (is (= (rstr [:div])
- (rstr [:> d2])))
- (is (= (rstr [:div "a"])
- (rstr [:> d2 "a"])))
- (is (= (rstr [:div "a" "b"])
- (rstr [:> d2 "a" "b"])))
- (is (= (rstr [:div.foo "a"])
- (rstr [:> d2 {:class "foo"} "a"])))
- (is (= (rstr [:div "a" "b" [:div "c"]])
- (rstr [:> d2 "a" "b" [:div "c"]])))))
+ (is (= (rstr [:div])
+ (rstr [:> d2])))
+ (is (= (rstr [:div "a"])
+ (rstr [:> d2 "a"])))
+ (is (= (rstr [:div "a" "b"])
+ (rstr [:> d2 "a" "b"])))
+ (is (= (rstr [:div.foo "a"])
+ (rstr [:> d2 {:class "foo"} "a"])))
+ (is (= (rstr [:div "a" "b" [:div "c"]])
+ (rstr [:> d2 "a" "b" [:div "c"]]))))))
(deftest adapt-react-class-shortcut-key-warning
(let [w (debug/track-warnings
@@ -535,70 +575,77 @@
(is (empty? (:warn w)))))
(deftest test-reactize-component
- (let [ae r/as-element
- ce r/create-element
- a (atom nil)
- c1r (fn reactize [p & args]
- (reset! a args)
- [:p "p:" (:a p) (:children p)])
- c1 (r/reactify-component c1r)]
- (is (= (rstr (ce c1 #js{:a "a"}))
- (rstr [:p "p:a"])))
- (is (= nil @a))
- (is (= (rstr (ce c1 #js{:a nil}))
- (rstr [:p "p:"])))
- (is (= (rstr (ce c1 nil))
- (rstr [:p "p:"])))
+ (doseq [opts test-options]
+ (let [ae r/as-element
+ ce r/create-element
+ rstr #(rstr % opts)
+ a (atom nil)
+ c1r (fn reactize [p & args]
+ (reset! a args)
+ [:p "p:" (:a p) (:children p)])
+ c1 (r/reactify-component c1r)]
+ (is (= (rstr (ce c1 #js{:a "a"}))
+ (rstr [:p "p:a"])))
+ (is (= nil @a))
+ (is (= (rstr (ce c1 #js{:a nil}))
+ (rstr [:p "p:"])))
+ (is (= (rstr (ce c1 nil))
+ (rstr [:p "p:"])))
- (is (= (rstr (ce c1 #js{:a "a"}
- (ae [:b "b"])))
- (rstr [:p "p:a" [:b "b"]])))
- (is (= nil @a))
- (is (= (rstr (ce c1 #js{:a "a"}
- (ae [:b "b"])
- (ae [:i "i"])))
- (rstr [:p "p:a" [:b "b"] [:i "i"]])))
- (is (= nil @a))))
+ (is (= (rstr (ce c1 #js{:a "a"}
+ (ae [:b "b"])))
+ (rstr [:p "p:a" [:b "b"]])))
+ (is (= nil @a))
+ (is (= (rstr (ce c1 #js{:a "a"}
+ (ae [:b "b"])
+ (ae [:i "i"])))
+ (rstr [:p "p:a" [:b "b"] [:i "i"]])))
+ (is (= nil @a)))))
(deftest test-keys
- (let [a nil ;; (r/atom "a")
- c (fn key-tester []
- [:div
- (for [i (range 3)]
- ^{:key i} [:p i (some-> a deref)])
- (for [i (range 3)]
- [:p {:key i} i (some-> a deref)])])
- w (debug/track-warnings
- #(with-mounted-component [c]
- (fn [c div])))]
- (is (empty? (:warn w))))
+ (doseq [opts test-options]
+ (let [a nil ;; (r/atom "a")
+ c (fn key-tester []
+ [:div
+ (for [i (range 3)]
+ ^{:key i} [:p i (some-> a deref)])
+ (for [i (range 3)]
+ [:p {:key i} i (some-> a deref)])])
+ w (debug/track-warnings
+ #(with-mounted-component [c]
+ opts
+ (fn [c div])))]
+ (is (empty? (:warn w))))
- (when r/is-client
- (testing "Check warning text can be produced even if hiccup contains function literals"
- (let [c (fn key-tester []
- [:div
- (for [i (range 3)]
- ^{:key nil}
- [:button {:on-click #(js/console.log %)}])])
- w (debug/track-warnings
- (wrap-capture-console-error
- #(with-mounted-component [c]
- (fn [c div]))))]
- (if (dev?)
- (is (re-find #"Warning: Every element in a seq should have a unique :key: \(\[:button \{:on-click #object\[Function\]\}\] \[:button \{:on-click #object\[Function\]\}\] \[:button \{:on-click #object\[Function\]\}\]\)\n \(in reagenttest.testreagent.key_tester\)"
- (first (:warn w)))))))))
+ (when r/is-client
+ (testing "Check warning text can be produced even if hiccup contains function literals"
+ (let [c (fn key-tester []
+ [:div
+ (for [i (range 3)]
+ ^{:key nil}
+ [:button {:on-click #(js/console.log %)}])])
+ w (debug/track-warnings
+ (wrap-capture-console-error
+ #(with-mounted-component [c]
+ opts
+ (fn [c div]))))]
+ (if (dev?)
+ (is (re-find #"Warning: Every element in a seq should have a unique :key: \(\[:button \{:on-click #object\[Function\]\}\] \[:button \{:on-click #object\[Function\]\}\] \[:button \{:on-click #object\[Function\]\}\]\)\n \(in reagenttest.testreagent.key_tester\)"
+ (first (:warn w))))))))))
(deftest test-extended-syntax
- (is (= "foo
"
- (rstr [:p>b "foo"])))
- (is (= (rstr [:p.foo [:b "x"]])
- (rstr [:p.foo>b "x"])))
- (is (= (rstr [:div.foo [:p.bar.foo [:b.foobar "xy"]]])
- (rstr [:div.foo>p.bar.foo>b.foobar "xy"])))
- (is (= (rstr [:div.foo [:p.bar.foo [:b.foobar "xy"]]])
- (rstr [:div.foo>p.bar.foo>b.foobar {} "xy"])))
- (is (= (rstr [:div [:p.bar.foo [:a.foobar {:href "href"} "xy"]]])
- (rstr [:div>p.bar.foo>a.foobar {:href "href"} "xy"]))))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (= "foo
"
+ (rstr [:p>b "foo"])))
+ (is (= (rstr [:p.foo [:b "x"]])
+ (rstr [:p.foo>b "x"])))
+ (is (= (rstr [:div.foo [:p.bar.foo [:b.foobar "xy"]]])
+ (rstr [:div.foo>p.bar.foo>b.foobar "xy"])))
+ (is (= (rstr [:div.foo [:p.bar.foo [:b.foobar "xy"]]])
+ (rstr [:div.foo>p.bar.foo>b.foobar {} "xy"])))
+ (is (= (rstr [:div [:p.bar.foo [:a.foobar {:href "href"} "xy"]]])
+ (rstr [:div>p.bar.foo>a.foobar {:href "href"} "xy"])))))
(deftest extended-syntax-metadata
(when r/is-client
@@ -612,35 +659,39 @@
)))))
(deftest test-class-from-collection
- (is (= (rstr [:p {:class "a b c d"}])
- (rstr [:p {:class ["a" "b" "c" "d"]}])))
- (is (= (rstr [:p {:class "a b c"}])
- (rstr [:p {:class ["a" nil "b" false "c" nil]}])))
- (is (= (rstr [:p {:class "a b c"}])
- (rstr [:p {:class '("a" "b" "c")}])))
- (is (= (rstr [:p {:class "a b c"}])
- (rstr [:p {:class #{"a" "b" "c"}}]))))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (= (rstr [:p {:class "a b c d"}])
+ (rstr [:p {:class ["a" "b" "c" "d"]}])))
+ (is (= (rstr [:p {:class "a b c"}])
+ (rstr [:p {:class ["a" nil "b" false "c" nil]}])))
+ (is (= (rstr [:p {:class "a b c"}])
+ (rstr [:p {:class '("a" "b" "c")}])))
+ (is (= (rstr [:p {:class "a b c"}])
+ (rstr [:p {:class #{"a" "b" "c"}}])))))
(deftest class-different-types
- (testing "named values are supported"
- (is (= (rstr [:p {:class "a"}])
- (rstr [:p {:class :a}])))
- (is (= (rstr [:p {:class "a b"}])
- (rstr [:p.a {:class :b}])))
- (is (= (rstr [:p {:class "a b"}])
- (rstr [:p.a {:class 'b}])))
- (is (= (rstr [:p {:class "a b"}])
- (rstr [:p {:class [:a :b]}])))
- (is (= (rstr [:p {:class "a b"}])
- (rstr [:p {:class ['a :b]}]))))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (testing "named values are supported"
+ (is (= (rstr [:p {:class "a"}])
+ (rstr [:p {:class :a}])))
+ (is (= (rstr [:p {:class "a b"}])
+ (rstr [:p.a {:class :b}])))
+ (is (= (rstr [:p {:class "a b"}])
+ (rstr [:p.a {:class 'b}])))
+ (is (= (rstr [:p {:class "a b"}])
+ (rstr [:p {:class [:a :b]}])))
+ (is (= (rstr [:p {:class "a b"}])
+ (rstr [:p {:class ['a :b]}]))))
- (testing "non-named values like numbers"
- (is (= (rstr [:p {:class "1 b"}])
- (rstr [:p {:class [1 :b]}]))))
+ (testing "non-named values like numbers"
+ (is (= (rstr [:p {:class "1 b"}])
+ (rstr [:p {:class [1 :b]}]))))
- (testing "falsey values are filtered from collections"
- (is (= (rstr [:p {:class "a b"}])
- (rstr [:p {:class [:a :b false nil]}])))) )
+ (testing "falsey values are filtered from collections"
+ (is (= (rstr [:p {:class "a b"}])
+ (rstr [:p {:class [:a :b false nil]}]))))))
(deftest test-force-update
(let [v (atom {:v1 0
@@ -693,274 +744,286 @@
(is (re-find #"atestcomponent" @a) "component-path should work")))))
(deftest test-sorted-map-key
- (let [c1 (fn [map]
- [:div (map 1)])
- c2 (fn []
- [c1 (sorted-map 1 "foo" 2 "bar")])]
- (is (= "foo
" (rstr [c2])))))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (let [c1 (fn [map]
+ [:div (map 1)])
+ c2 (fn []
+ [c1 (sorted-map 1 "foo" 2 "bar")])]
+ (is (= "foo
" (rstr [c2]))))))
(deftest basic-with-let
- (when r/is-client
- (let [n1 (atom 0)
- n2 (atom 0)
- n3 (atom 0)
- val (r/atom 0)
- c (fn []
- (r/with-let [v (swap! n1 inc)]
- (swap! n2 inc)
- [:div @val]
- (finally
- (swap! n3 inc))))]
- (with-mounted-component [c]
- (fn [_ div]
- (is (= [1 1 0] [@n1 @n2 @n3]))
- (swap! val inc)
- (is (= [1 1 0] [@n1 @n2 @n3]))
- (r/flush)
- (is (= [1 2 0] [@n1 @n2 @n3]))))
- (is (= [1 2 1] [@n1 @n2 @n3])))))
+ (doseq [opts test-options]
+ (when r/is-client
+ (let [n1 (atom 0)
+ n2 (atom 0)
+ n3 (atom 0)
+ val (r/atom 0)
+ c (fn []
+ (r/with-let [v (swap! n1 inc)]
+ (swap! n2 inc)
+ [:div @val]
+ (finally
+ (swap! n3 inc))))]
+ (with-mounted-component [c]
+ opts
+ (fn [_ div]
+ (is (= [1 1 0] [@n1 @n2 @n3]))
+ (swap! val inc)
+ (is (= [1 1 0] [@n1 @n2 @n3]))
+ (r/flush)
+ (is (= [1 2 0] [@n1 @n2 @n3]))))
+ (is (= [1 2 1] [@n1 @n2 @n3]))))))
(deftest with-let-destroy-only
(when r/is-client
- (let [n1 (atom 0)
- n2 (atom 0)
- c (fn []
- (r/with-let []
- (swap! n1 inc)
- [:div]
- (finally
- (swap! n2 inc))))]
- (with-mounted-component [c]
- (fn [_ div]
- (is (= [1 0] [@n1 @n2]))))
- (is (= [1 1] [@n1 @n2])))))
+ (doseq [opts test-options]
+ (let [n1 (atom 0)
+ n2 (atom 0)
+ c (fn []
+ (r/with-let []
+ (swap! n1 inc)
+ [:div]
+ (finally
+ (swap! n2 inc))))]
+ (with-mounted-component [c]
+ opts
+ (fn [_ div]
+ (is (= [1 0] [@n1 @n2]))))
+ (is (= [1 1] [@n1 @n2]))))))
(deftest with-let-arg
(when r/is-client
- (let [a (atom 0)
- s (r/atom "foo")
- f (fn [x]
- (r/with-let []
- (reset! a x)
- [:div x]))
- c (fn []
- (r/with-let []
- [f @s]))]
- (with-mounted-component [c]
- (fn [_ div]
- (is (= "foo" @a))
- (reset! s "bar")
- (r/flush)
- (is (= "bar" @a)))))))
+ (doseq [opts test-options]
+ (let [a (atom 0)
+ s (r/atom "foo")
+ f (fn [x]
+ (r/with-let []
+ (reset! a x)
+ [:div x]))
+ c (fn []
+ (r/with-let []
+ [f @s]))]
+ (with-mounted-component [c]
+ opts
+ (fn [_ div]
+ (is (= "foo" @a))
+ (reset! s "bar")
+ (r/flush)
+ (is (= "bar" @a))))))))
(deftest with-let-non-reactive
- (let [n1 (atom 0)
- n2 (atom 0)
- n3 (atom 0)
- c (fn []
- (r/with-let [a (swap! n1 inc)]
- (swap! n2 inc)
- [:div a]
- (finally
- (swap! n3 inc))))]
- (is (= (rstr [c]) (rstr [:div 1])))
- (is (= [1 1 1] [@n1 @n2 @n3]))))
+ (doseq [opts test-options]
+ (let [n1 (atom 0)
+ n2 (atom 0)
+ n3 (atom 0)
+ rstr #(rstr % opts)
+ c (fn []
+ (r/with-let [a (swap! n1 inc)]
+ (swap! n2 inc)
+ [:div a]
+ (finally
+ (swap! n3 inc))))]
+ (is (= (rstr [c]) (rstr [:div 1])))
+ (is (= [1 1 1] [@n1 @n2 @n3])))))
(deftest lifecycle
- (let [n1 (atom 0)
- t (atom 0)
- res (atom {})
- add-args (fn [key args]
- (swap! res assoc key
- {:at (swap! n1 inc)
- :args (vec args)}))
- render (fn [& args]
- (this-as c (is (= c (r/current-component))))
- (add-args :render args)
- [:div "" (first args)])
- render2 (fn [& args]
- (add-args :render args)
- [:div "" (first args)])
- ls {:get-initial-state
- (fn [& args]
- (reset! t (first args))
- (add-args :initial-state args)
- {:foo "bar"})
- :UNSAFE_component-will-mount
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :will-mount args))
- :component-did-mount
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :did-mount args))
- :should-component-update
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :should-update args) true)
- :UNSAFE_component-will-receive-props
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :will-receive args))
- :UNSAFE_component-will-update
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :will-update args))
- :component-did-update
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :did-update args))
- :component-will-unmount
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :will-unmount args))}
- c1 (r/create-class
- (assoc ls :reagent-render render))
- defarg ["a" "b"]
- arg (r/atom defarg)
- comp (atom c1)
- c2 (fn []
- (apply vector @comp @arg))
- cnative (fn []
- (into [:> @comp] @arg))
- check (fn []
- (is (= {:at 1 :args [@t]}
- (:initial-state @res)))
- (is (= {:at 2 :args [@t]}
- (:will-mount @res)))
- (is (= {:at 3 :args ["a" "b"]}
- (:render @res)))
- (is (= {:at 4 :args [@t]}
- (:did-mount @res)))
+ (doseq [opts test-options]
+ (let [n1 (atom 0)
+ t (atom 0)
+ res (atom {})
+ add-args (fn [key args]
+ (swap! res assoc key
+ {:at (swap! n1 inc)
+ :args (vec args)}))
+ render (fn [& args]
+ (this-as c (is (= c (r/current-component))))
+ (add-args :render args)
+ [:div "" (first args)])
+ render2 (fn [& args]
+ (add-args :render args)
+ [:div "" (first args)])
+ ls {:get-initial-state
+ (fn [& args]
+ (reset! t (first args))
+ (add-args :initial-state args)
+ {:foo "bar"})
+ :UNSAFE_component-will-mount
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :will-mount args))
+ :component-did-mount
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :did-mount args))
+ :should-component-update
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :should-update args) true)
+ :UNSAFE_component-will-receive-props
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :will-receive args))
+ :UNSAFE_component-will-update
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :will-update args))
+ :component-did-update
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :did-update args))
+ :component-will-unmount
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :will-unmount args))}
+ c1 (r/create-class
+ (assoc ls :reagent-render render))
+ defarg ["a" "b"]
+ arg (r/atom defarg)
+ comp (atom c1)
+ c2 (fn []
+ (apply vector @comp @arg))
+ cnative (fn []
+ (into [:> @comp] @arg))
+ check (fn []
+ (is (= {:at 1 :args [@t]}
+ (:initial-state @res)))
+ (is (= {:at 2 :args [@t]}
+ (:will-mount @res)))
+ (is (= {:at 3 :args ["a" "b"]}
+ (:render @res)))
+ (is (= {:at 4 :args [@t]}
+ (:did-mount @res)))
- (reset! arg ["a" "c"])
- (r/flush)
- (is (= {:at 5 :args [@t [@comp "a" "c"]]}
- (:will-receive @res)))
- (is (= {:at 6 :args [@t [@comp "a" "b"] [@comp "a" "c"]]}
- (:should-update @res)))
- (is (= {:at 7 :args [@t [@comp "a" "c"] {:foo "bar"}]}
- (:will-update @res)))
- (is (= {:at 8 :args ["a" "c"]}
- (:render @res)))
- (is (= {:at 9 :args [@t [@comp "a" "b"] {:foo "bar"} nil]}
- (:did-update @res))))]
- (when r/is-client
- (with-mounted-component [c2] check)
- (is (= {:at 10 :args [@t]}
- (:will-unmount @res)))
+ (reset! arg ["a" "c"])
+ (r/flush)
+ (is (= {:at 5 :args [@t [@comp "a" "c"]]}
+ (:will-receive @res)))
+ (is (= {:at 6 :args [@t [@comp "a" "b"] [@comp "a" "c"]]}
+ (:should-update @res)))
+ (is (= {:at 7 :args [@t [@comp "a" "c"] {:foo "bar"}]}
+ (:will-update @res)))
+ (is (= {:at 8 :args ["a" "c"]}
+ (:render @res)))
+ (is (= {:at 9 :args [@t [@comp "a" "b"] {:foo "bar"} nil]}
+ (:did-update @res))))]
+ (when r/is-client
+ (with-mounted-component [c2] opts check)
+ (is (= {:at 10 :args [@t]}
+ (:will-unmount @res)))
- (reset! comp (with-meta render2 ls))
- (reset! arg defarg)
- (reset! n1 0)
- (with-mounted-component [c2] check)
- (is (= {:at 10 :args [@t]}
- (:will-unmount @res))))))
+ (reset! comp (with-meta render2 ls))
+ (reset! arg defarg)
+ (reset! n1 0)
+ (with-mounted-component [c2] check)
+ (is (= {:at 10 :args [@t]}
+ (:will-unmount @res)))))))
(deftest lifecycle-native
- (let [n1 (atom 0)
- t (atom 0)
- res (atom {})
- oldprops (atom nil)
- newprops (atom nil)
- add-args (fn [key args]
- (swap! res assoc key
- {:at (swap! n1 inc)
- :args (vec args)}))
- render (fn [& args]
- (this-as
- c
- (when @newprops
- (is (= (first args) @newprops))
- (is (= (r/props c) @newprops)))
- (is (= c (r/current-component)))
- (is (= (first args) (r/props c)))
- (add-args :render
- {:children (r/children c)})
- [:div "" (first args)]))
- ls {:get-initial-state
- (fn [& args]
- (reset! t (first args))
- (reset! oldprops (-> args first r/props))
- (add-args :initial-state args)
- {:foo "bar"})
- :UNSAFE_component-will-mount
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :will-mount args))
- :component-did-mount
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :did-mount args))
- :should-component-update
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :should-update args) true)
- :UNSAFE_component-will-receive-props
- (fn [& args]
- (reset! newprops (-> args second second))
- (this-as c
- (is (= c (first args)))
- (add-args :will-receive (into [(dissoc (r/props c) :children)]
- (:children (r/props c))))))
- :UNSAFE_component-will-update
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :will-update args))
- :component-did-update
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :did-update args))
- :component-will-unmount
- (fn [& args]
- (this-as c (is (= c (first args))))
- (add-args :will-unmount args))}
- c1 (r/create-class
- (assoc ls :reagent-render render))
- defarg [{:foo "bar"} "a" "b"]
- arg (r/atom defarg)
- comp (atom c1)
- cnative (fn []
- (into [:> @comp] @arg))
- check (fn []
- (is (= {:at 1 :args [@t]}
- (:initial-state @res)))
- (is (= {:at 2 :args [@t]}
- (:will-mount @res)))
- (is (= {:at 3 :args [[:children ["a" "b"]]]}
- (:render @res)))
- (is (= {:at 4 :args [@t]}
- (:did-mount @res)))
+ (doseq [opts test-options]
+ (let [n1 (atom 0)
+ t (atom 0)
+ res (atom {})
+ oldprops (atom nil)
+ newprops (atom nil)
+ add-args (fn [key args]
+ (swap! res assoc key
+ {:at (swap! n1 inc)
+ :args (vec args)}))
+ render (fn [& args]
+ (this-as
+ c
+ (when @newprops
+ (is (= (first args) @newprops))
+ (is (= (r/props c) @newprops)))
+ (is (= c (r/current-component)))
+ (is (= (first args) (r/props c)))
+ (add-args :render
+ {:children (r/children c)})
+ [:div "" (first args)]))
+ ls {:get-initial-state
+ (fn [& args]
+ (reset! t (first args))
+ (reset! oldprops (-> args first r/props))
+ (add-args :initial-state args)
+ {:foo "bar"})
+ :UNSAFE_component-will-mount
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :will-mount args))
+ :component-did-mount
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :did-mount args))
+ :should-component-update
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :should-update args) true)
+ :UNSAFE_component-will-receive-props
+ (fn [& args]
+ (reset! newprops (-> args second second))
+ (this-as c
+ (is (= c (first args)))
+ (add-args :will-receive (into [(dissoc (r/props c) :children)]
+ (:children (r/props c))))))
+ :UNSAFE_component-will-update
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :will-update args))
+ :component-did-update
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :did-update args))
+ :component-will-unmount
+ (fn [& args]
+ (this-as c (is (= c (first args))))
+ (add-args :will-unmount args))}
+ c1 (r/create-class
+ (assoc ls :reagent-render render))
+ defarg [{:foo "bar"} "a" "b"]
+ arg (r/atom defarg)
+ comp (atom c1)
+ cnative (fn []
+ (into [:> @comp] @arg))
+ check (fn []
+ (is (= {:at 1 :args [@t]}
+ (:initial-state @res)))
+ (is (= {:at 2 :args [@t]}
+ (:will-mount @res)))
+ (is (= {:at 3 :args [[:children ["a" "b"]]]}
+ (:render @res)))
+ (is (= {:at 4 :args [@t]}
+ (:did-mount @res)))
- (reset! arg [{:f "oo"} "a" "c"])
- (r/flush)
+ (reset! arg [{:f "oo"} "a" "c"])
+ (r/flush)
- (is (= {:at 5 :args [{:foo "bar"} "a" "b"]}
- (:will-receive @res)))
- (let [a (:should-update @res)
- {at :at
- [this oldv newv] :args} a]
- (is (= 6 at))
- (is (= 3 (count (:args a))))
- (is (= (js->clj [@comp @oldprops]) (js->clj oldv)))
- (is (= [@comp @newprops] newv)))
- (let [a (:will-update @res)
- {at :at
- [this newv] :args} a]
- (is (= 7 at))
- (is (= [@comp @newprops] newv)))
- (is (= {:at 8 :args [[:children ["a" "c"]]]}
- (:render @res)))
- (let [a (:did-update @res)
- {at :at
- [this oldv] :args} a]
- (is (= 9 at))
- (is (= [@comp @oldprops] oldv))))]
- (when r/is-client
- (with-mounted-component [cnative] check)
- (is (= {:at 10 :args [@t]}
- (:will-unmount @res))))))
+ (is (= {:at 5 :args [{:foo "bar"} "a" "b"]}
+ (:will-receive @res)))
+ (let [a (:should-update @res)
+ {at :at
+ [this oldv newv] :args} a]
+ (is (= 6 at))
+ (is (= 3 (count (:args a))))
+ (is (= (js->clj [@comp @oldprops]) (js->clj oldv)))
+ (is (= [@comp @newprops] newv)))
+ (let [a (:will-update @res)
+ {at :at
+ [this newv] :args} a]
+ (is (= 7 at))
+ (is (= [@comp @newprops] newv)))
+ (is (= {:at 8 :args [[:children ["a" "c"]]]}
+ (:render @res)))
+ (let [a (:did-update @res)
+ {at :at
+ [this oldv] :args} a]
+ (is (= 9 at))
+ (is (= [@comp @oldprops] oldv))))]
+ (when r/is-client
+ (with-mounted-component [cnative] opts check)
+ (is (= {:at 10 :args [@t]}
+ (:will-unmount @res)))))))
(defn foo []
[:div])
@@ -988,203 +1051,221 @@
(deftest test-err-messages
(when (dev?)
- (is (thrown-with-msg?
- :default #"Hiccup form should not be empty: \[]"
- (rstr [])))
- (is (thrown-with-msg?
- :default #"Invalid Hiccup tag: \[:>div \[reagenttest.testreagent.foo]]"
- (rstr [:>div [foo]])))
- (is (thrown-with-msg?
- :default #"Invalid Hiccup form: \[23]"
- (rstr [23])))
- ;; This used to be asserted by Reagent, but because it is hard to validate
- ;; components, now we just trust React will validate elements.
- ; (is (thrown-with-msg?
- ; :default #"Expected React component in: \[:> \[:div]]"
- ; (rstr [:> [:div]])))
- ;; This is from React.createElement
- ;; NOTE: browser-npm uses production cjs bundle for now which only shows
- ;; the minified error
- (debug/track-warnings
- (wrap-capture-console-error
- #(is (thrown-with-msg?
- :default #"(Element type is invalid:|Minified React error)"
- (rstr [:> [:div]])))))
- (is (thrown-with-msg?
- :default #"Invalid tag: 'p.'"
- (rstr [:p.])))
- (when r/is-client
- (let [comp1 (fn comp1 [x]
- x)
- comp2 (fn comp2 [x]
- [comp1 x])
- comp3 (fn comp3 []
- (r/with-let [a (r/atom "foo")]
- [:div (for [i (range 0 1)]
- ^{:key i} [:p @a])]))
- comp4 (fn comp4 []
- (for [i (range 0 1)]
- [:p "foo"]))
- nat (let [cmp (fn [])]
- (gobj/extend
- (.-prototype cmp)
- (.-prototype react/Component)
- #js {:render (fn [])})
- (gobj/extend cmp react/Component)
- cmp)
- pkg "reagenttest.testreagent."
- stack1 (str "in " pkg "comp1")
- rend (fn [x]
- (with-mounted-component x identity))]
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (thrown-with-msg?
+ :default #"Hiccup form should not be empty: \[]"
+ (rstr [])))
+ (is (thrown-with-msg?
+ :default #"Invalid Hiccup tag: \[:>div \[reagenttest.testreagent.foo]]"
+ (rstr [:>div [foo]])))
+ (is (thrown-with-msg?
+ :default #"Invalid Hiccup form: \[23]"
+ (rstr [23])))
+ ;; This used to be asserted by Reagent, but because it is hard to validate
+ ;; components, now we just trust React will validate elements.
+ ; (is (thrown-with-msg?
+ ; :default #"Expected React component in: \[:> \[:div]]"
+ ; (rstr [:> [:div]])))
+ ;; This is from React.createElement
+ ;; NOTE: browser-npm uses production cjs bundle for now which only shows
+ ;; the minified error
+ (debug/track-warnings
+ (wrap-capture-console-error
+ #(is (thrown-with-msg?
+ :default #"(Element type is invalid:|Minified React error)"
+ (rstr [:> [:div]])))))
+ (is (thrown-with-msg?
+ :default #"Invalid tag: 'p.'"
+ (rstr [:p.])))
+ (when r/is-client
+ (let [comp1 (fn comp1 [x]
+ x)
+ comp2 (fn comp2 [x]
+ [comp1 x])
+ comp3 (fn comp3 []
+ (r/with-let [a (r/atom "foo")]
+ [:div (for [i (range 0 1)]
+ ^{:key i} [:p @a])]))
+ comp4 (fn comp4 []
+ (for [i (range 0 1)]
+ [:p "foo"]))
+ nat (let [cmp (fn [])]
+ (gobj/extend
+ (.-prototype cmp)
+ (.-prototype react/Component)
+ #js {:render (fn [])})
+ (gobj/extend cmp react/Component)
+ cmp)
+ pkg "reagenttest.testreagent."
+ stack1 (str "in " pkg "comp1")
+ rend (fn [x]
+ (with-mounted-component x opts identity))]
- ;; Error is orginally caused by comp1, so only that is shown in the error
- (let [e (debug/track-warnings
- (wrap-capture-window-error
- (wrap-capture-console-error
- #(is (thrown-with-msg?
- :default #"Invalid tag: 'div.' \(in reagenttest.testreagent.comp1\)"
- (rend [comp2 [:div. "foo"]]))))))]
- (is (re-find #"Error rendering component \(in reagenttest.testreagent.comp1\)"
- (last (:error e)))))
+ ;; Error is orginally caused by comp1, so only that is shown in the error
+ (let [e (debug/track-warnings
+ (wrap-capture-window-error
+ (wrap-capture-console-error
+ #(is (thrown-with-msg?
+ :default #"Invalid tag: 'div.' \(in reagenttest.testreagent.comp1\)"
+ (rend [comp2 [:div. "foo"]]))))))]
+ (is (re-find #"Error rendering component \(in reagenttest.testreagent.comp1\)"
+ (last (:error e)))))
- (let [e (debug/track-warnings
- (wrap-capture-window-error
- (wrap-capture-console-error
- #(is (thrown-with-msg?
- :default #"Invalid tag: 'div.' \(in reagenttest.testreagent.comp1\)"
- (rend [comp1 [:div. "foo"]]))))))]
- (is (re-find #"Error rendering component \(in reagenttest.testreagent.comp1\)"
- (last (:error e)))))
+ (let [e (debug/track-warnings
+ (wrap-capture-window-error
+ (wrap-capture-console-error
+ #(is (thrown-with-msg?
+ :default #"Invalid tag: 'div.' \(in reagenttest.testreagent.comp1\)"
+ (rend [comp1 [:div. "foo"]]))))))]
+ (is (re-find #"Error rendering component \(in reagenttest.testreagent.comp1\)"
+ (last (:error e)))))
- (let [e (debug/track-warnings #(r/as-element [nat]))]
- (is (re-find #"Using native React classes directly"
- (-> e :warn first))))
+ (let [e (debug/track-warnings #(r/as-element [nat] opts))]
+ (is (re-find #"Using native React classes directly"
+ (-> e :warn first))))
- (let [e (debug/track-warnings
- #(rend [comp3]))]
- (is (re-find #"Reactive deref not supported"
- (-> e :warn first))))
+ (let [e (debug/track-warnings
+ #(rend [comp3]))]
+ (is (re-find #"Reactive deref not supported"
+ (-> e :warn first))))
- (let [e (debug/track-warnings
- #(r/as-element (comp4)))]
- (is (re-find #"Every element in a seq should have a unique :key"
- (-> e :warn first))))))))
+ (let [e (debug/track-warnings
+ #(r/as-element (comp4) opts))]
+ (is (re-find #"Every element in a seq should have a unique :key"
+ (-> e :warn first)))))))))
(deftest test-error-boundary
- (let [error (r/atom nil)
- info (r/atom nil)
- error-boundary (fn error-boundary [comp]
- (r/create-class
- {:component-did-catch (fn [this e i]
- (reset! info i))
- :get-derived-state-from-error (fn [e]
- (reset! error e)
- #js {})
- :reagent-render (fn [comp]
- (if @error
- [:div "Something went wrong."]
- comp))}))
- comp1 (fn comp1 []
- (throw (js/Error. "Test error")))
- comp2 (fn comp2 []
- [comp1])]
- (debug/track-warnings
- (wrap-capture-window-error
- (wrap-capture-console-error
- #(with-mounted-component [error-boundary [comp2]]
- (fn [c div]
- (r/flush)
- (is (= "Test error" (.-message @error)))
- (is (re-find #"Something went wrong\." (.-innerHTML div)))
- ;; FIXME: React.memo messes this up
- #_
- (if (dev?)
- (is (re-find #"\n in reagenttest.testreagent.comp1 \(created by reagenttest.testreagent.comp2\)\n in reagenttest.testreagent.comp2 \(created by reagent[0-9]+\)\n in reagent[0-9]+ \(created by reagenttest.testreagent.error_boundary\)\n in reagenttest.testreagent.error_boundary"
- (.-componentStack ^js @info)))
- (is (re-find #"\n in .+\n in .+\n in reagent[0-9]+\n in .+"
- (.-componentStack ^js @info))) ))))))))
+ (doseq [opts test-options]
+ (let [error (r/atom nil)
+ info (r/atom nil)
+ error-boundary (fn error-boundary [comp]
+ (r/create-class
+ {:component-did-catch (fn [this e i]
+ (reset! info i))
+ :get-derived-state-from-error (fn [e]
+ (reset! error e)
+ #js {})
+ :reagent-render (fn [comp]
+ (if @error
+ [:div "Something went wrong."]
+ comp))}))
+ comp1 (fn comp1 []
+ (throw (js/Error. "Test error")))
+ comp2 (fn comp2 []
+ [comp1])]
+ (debug/track-warnings
+ (wrap-capture-window-error
+ (wrap-capture-console-error
+ #(with-mounted-component [error-boundary [comp2]]
+ opts
+ (fn [c div]
+ (r/flush)
+ (is (= "Test error" (.-message @error)))
+ (is (re-find #"Something went wrong\." (.-innerHTML div)))
+ ;; FIXME: React.memo messes this up
+ #_
+ (if (dev?)
+ (is (re-find #"\n in reagenttest.testreagent.comp1 \(created by reagenttest.testreagent.comp2\)\n in reagenttest.testreagent.comp2 \(created by reagent[0-9]+\)\n in reagent[0-9]+ \(created by reagenttest.testreagent.error_boundary\)\n in reagenttest.testreagent.error_boundary"
+ (.-componentStack ^js @info)))
+ (is (re-find #"\n in .+\n in .+\n in reagent[0-9]+\n in .+"
+ (.-componentStack ^js @info))))))))))))
(deftest test-dom-node
- (let [node (atom nil)
- ref (atom nil)
- comp (r/create-class
- {:reagent-render (fn test-dom []
- [:div {:ref #(reset! ref %)} "foobar"])
- :component-did-mount
- (fn [this]
- (reset! node (rdom/dom-node this)))})]
- (with-mounted-component [comp]
- (fn [c div]
- (is (= "foobar" (.-innerHTML @ref)))
- (is (= "foobar" (.-innerHTML @node)))
- (is (identical? @ref @node))))))
+ (doseq [opts test-options]
+ (let [node (atom nil)
+ ref (atom nil)
+ comp (r/create-class
+ {:reagent-render (fn test-dom []
+ [:div {:ref #(reset! ref %)} "foobar"])
+ :component-did-mount
+ (fn [this]
+ (reset! node (rdom/dom-node this)))})]
+ (with-mounted-component [comp]
+ opts
+ (fn [c div]
+ (is (= "foobar" (.-innerHTML @ref)))
+ (is (= "foobar" (.-innerHTML @node)))
+ (is (identical? @ref @node)))))))
(deftest test-empty-input
- (is (= ""
- (rstr [:div [:input]]))))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (= ""
+ (rstr [:div [:input]])))))
(deftest test-object-children
- (is (= "foo bar1
"
- (rstr [:p 'foo " " :bar nil 1])))
- (is (= "#object[reagent.ratom.RAtom {:val 1}]
"
- (rstr [:p (r/atom 1)]))))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (= "foo bar1
"
+ (rstr [:p 'foo " " :bar nil 1])))
+ (is (= "#object[reagent.ratom.RAtom {:val 1}]
"
+ (rstr [:p (r/atom 1)])))))
(deftest test-after-render
- (let [spy (atom 0)
- val (atom 0)
- exp (atom 0)
- node (atom nil)
- state (r/atom 0)
- comp (fn []
- (let [old @spy]
- (r/after-render
- (fn []
- (is (= "DIV" (.-tagName @node)))
- (swap! spy inc)))
- (is (= @spy old))
- (is (= @exp @val))
- [:div {:ref #(reset! node %)} @state]))]
- (with-mounted-component [comp]
- (fn [c div]
- (is (= 1 @spy))
- (swap! state inc)
- (is (= 1 @spy))
- (r/next-tick #(swap! val inc))
- (reset! exp 1)
- (is (= 0 @val))
- (r/flush)
- (is (= 1 @val))
- (is (= 2 @spy))
- ;; FIXME: c is nil because render call doesn't return anything
- ; (r/force-update c)
- ; (is (= 3 @spy))
- ; (r/next-tick #(reset! spy 0))
- ; (is (= 3 @spy))
- ; (r/flush)
- ; (is (= 0 @spy))
- ))
- (is (= nil @node))))
+ (doseq [opts test-options]
+ (let [spy (atom 0)
+ val (atom 0)
+ exp (atom 0)
+ node (atom nil)
+ state (r/atom 0)
+ comp (fn []
+ (let [old @spy]
+ (r/after-render
+ (fn []
+ (is (= "DIV" (.-tagName @node)))
+ (swap! spy inc)))
+ (is (= @spy old))
+ (is (= @exp @val))
+ [:div {:ref #(reset! node %)} @state]))]
+ (with-mounted-component [comp]
+ opts
+ (fn [c div]
+ (is (= 1 @spy))
+ (swap! state inc)
+ (is (= 1 @spy))
+ (r/next-tick #(swap! val inc))
+ (reset! exp 1)
+ (is (= 0 @val))
+ (r/flush)
+ (is (= 1 @val))
+ (is (= 2 @spy))
+ ;; FIXME: c is nil because render call doesn't return anything
+ ; (r/force-update c)
+ ; (is (= 3 @spy))
+ ; (r/next-tick #(reset! spy 0))
+ ; (is (= 3 @spy))
+ ; (r/flush)
+ ; (is (= 0 @spy))
+ ))
+ (is (= nil @node)))))
(deftest style-property-names-are-camel-cased
- (is (= "foo
"
- (rstr [:div {:style {:text-align "center"}} "foo"]))))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (= "foo
"
+ (rstr [:div {:style {:text-align "center"}} "foo"])))))
(deftest custom-element-class-prop
- (is (= "foo"
- (rstr [:custom-element {:class "foobar"} "foo"])))
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (= "foo"
+ (rstr [:custom-element {:class "foobar"} "foo"])))
- (is (= "foo"
- (rstr [:custom-element.foobar "foo"]))))
+ (is (= "foo"
+ (rstr [:custom-element.foobar "foo"])))))
(deftest html-entities
- (testing "entity numbers can be unescaped always"
- (is (= " "
- (rstr [:i (gstr/unescapeEntities " ")]))))
-
- (when r/is-client
- (testing "When DOM is available, all named entities can be unescaped"
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (testing "entity numbers can be unescaped always"
(is (= " "
- (rstr [:i (gstr/unescapeEntities " ")]))))))
+ (rstr [:i (gstr/unescapeEntities " ")]))))
+
+ (when r/is-client
+ (testing "When DOM is available, all named entities can be unescaped"
+ (is (= " "
+ (rstr [:i (gstr/unescapeEntities " ")])))))))
(defn context-wrapper []
(r/create-class
@@ -1214,43 +1295,44 @@
(deftest test-fragments
- (testing "Fragment as array"
- (let [comp (fn comp1 []
- #js [(r/as-element [:div "hello"])
- (r/as-element [:div "world"])])]
- (is (= "hello
world
"
- (as-string [comp])))))
+ (doseq [opts test-options]
+ (testing "Fragment as array"
+ (let [comp (fn comp1 []
+ #js [(r/as-element [:div "hello"] opts)
+ (r/as-element [:div "world"] opts)])]
+ (is (= "hello
world
"
+ (as-string [comp] opts)))))
- (testing "Fragment element, :<>"
- (let [comp (fn comp2 []
- [:<>
- [:div "hello"]
- [:div "world"]
- [:div "foo"] ])]
- (is (= "hello
world
foo
"
- (as-string [comp])))))
+ (testing "Fragment element, :<>"
+ (let [comp (fn comp2 []
+ [:<>
+ [:div "hello"]
+ [:div "world"]
+ [:div "foo"] ])]
+ (is (= "hello
world
foo
"
+ (as-string [comp] opts)))))
- (testing "Fragment key"
- ;; This would cause React warning if both fragements didn't have key set
- ;; But wont fail the test
- (let [children (fn comp4 []
- [:<>
- [:div "foo"]])
- comp (fn comp3 []
- [:div
- (list
- [:<>
- {:key 1}
- [:div "hello"]
- [:div "world"]]
- ^{:key 2}
- [children]
- ^{:key 3}
- [:<>
- [:div "1"]
- [:div "2"]])])]
- (is (= ""
- (as-string [comp]))))))
+ (testing "Fragment key"
+ ;; This would cause React warning if both fragements didn't have key set
+ ;; But wont fail the test
+ (let [children (fn comp4 []
+ [:<>
+ [:div "foo"]])
+ comp (fn comp3 []
+ [:div
+ (list
+ [:<>
+ {:key 1}
+ [:div "hello"]
+ [:div "world"]]
+ ^{:key 2}
+ [children]
+ ^{:key 3}
+ [:<>
+ [:div "1"]
+ [:div "2"]])])]
+ (is (= ""
+ (as-string [comp] opts)))))))
;; In bundle version, the names aren't optimized.
;; In node module processed versions, names probably are optimized.
@@ -1260,179 +1342,192 @@
(def Consumer (.-Consumer my-context))
(deftest new-context-test
- (is (= "Context: foo
"
- (rstr (r/create-element
- Provider #js {:value "foo"}
- (r/create-element
- Consumer #js {}
- (fn [v]
- (r/as-element [:div "Context: " v])))))))
-
- (testing "context default value works"
- (is (= "Context: default
"
+ (doseq [opts test-options
+ :let [rstr #(rstr % opts)]]
+ (is (= "Context: foo
"
(rstr (r/create-element
- Consumer #js {}
- (fn [v]
- (r/as-element [:div "Context: " v])))))))
-
- (testing "context works with adapt-react-class"
- (let [provider (r/adapt-react-class Provider)
- consumer (r/adapt-react-class Consumer)]
- (is (= "Context: bar
"
- (rstr [provider {:value "bar"}
- [consumer {}
+ Provider #js {:value "foo"}
+ (r/create-element
+ Consumer #js {}
(fn [v]
- (r/as-element [:div "Context: " v]))]])))))
+ (r/as-element [:div "Context: " v])))))))
- (testing "context works with :>"
- (is (= "Context: bar
"
- (rstr [:> Provider {:value "bar"}
- [:> Consumer {}
- (fn [v]
- (r/as-element [:div "Context: " v]))]]))))
-
- (testing "static contextType"
- (let [comp (r/create-class
- {:context-type my-context
- :reagent-render (fn []
- (this-as this
- (r/as-element [:div "Context: " (.-context this)])))})]
+ (testing "context default value works"
(is (= "Context: default
"
- (rstr [comp]))))))
+ (rstr (r/create-element
+ Consumer #js {}
+ (fn [v]
+ (r/as-element [:div "Context: " v])))))))
+
+ (testing "context works with adapt-react-class"
+ (let [provider (r/adapt-react-class Provider)
+ consumer (r/adapt-react-class Consumer)]
+ (is (= "Context: bar
"
+ (rstr [provider {:value "bar"}
+ [consumer {}
+ (fn [v]
+ (r/as-element [:div "Context: " v]))]])))))
+
+ (testing "context works with :>"
+ (is (= "Context: bar
"
+ (rstr [:> Provider {:value "bar"}
+ [:> Consumer {}
+ (fn [v]
+ (r/as-element [:div "Context: " v]))]]))))
+
+ (testing "static contextType"
+ (let [comp (r/create-class
+ {:context-type my-context
+ :reagent-render (fn []
+ (this-as this
+ (r/as-element [:div "Context: " (.-context this)])))})]
+ (is (= "Context: default
"
+ (rstr [comp])))))))
(deftest on-failed-prop-comparison-in-should-update-swallow-exception-and-do-not-update-component
- (let [prop (r/atom {:todos 1})
- component-was-updated (atom false)
- error-thrown-after-updating-props (atom false)
- component-class (r/create-class {:reagent-render (fn [& args]
- [:div (str (first args))])
- :component-did-update (fn [& args]
- (reset! component-was-updated true))})
- component (fn []
- [component-class @prop])]
+ (doseq [opts test-options]
+ (let [prop (r/atom {:todos 1})
+ component-was-updated (atom false)
+ error-thrown-after-updating-props (atom false)
+ component-class (r/create-class {:reagent-render (fn [& args]
+ [:div (str (first args))])
+ :component-did-update (fn [& args]
+ (reset! component-was-updated true))})
+ component (fn []
+ [component-class @prop])]
- (when (and r/is-client (dev?))
- (let [e (debug/track-warnings
- #(with-mounted-component [component]
- (fn [c div]
- (reset! prop (sorted-map 1 2))
- (try
- (r/flush)
- (catch :default e
- (reset! error-thrown-after-updating-props true)))
+ (when (and r/is-client (dev?))
+ (let [e (debug/track-warnings
+ #(with-mounted-component [component]
+ opts
+ (fn [c div]
+ (reset! prop (sorted-map 1 2))
+ (try
+ (r/flush)
+ (catch :default e
+ (reset! error-thrown-after-updating-props true)))
- (is (not @component-was-updated))
- (is (not @error-thrown-after-updating-props)))))]
- (is (re-find #"Warning: Exception thrown while comparing argv's in shouldComponentUpdate:"
- (first (:warn e))))))))
+ (is (not @component-was-updated))
+ (is (not @error-thrown-after-updating-props)))))]
+ (is (re-find #"Warning: Exception thrown while comparing argv's in shouldComponentUpdate:"
+ (first (:warn e)))))))))
(deftest get-derived-state-from-props-test
(when r/is-client
- (let [prop (r/atom 0)
- ;; Usually one can use Cljs object as React state. However,
- ;; getDerivedStateFromProps implementation in React uses
- ;; Object.assign to merge current state and partial state returned
- ;; from the method, so the state has to be plain old object.
- pure-component (r/create-class
- {:constructor (fn [this]
- (set! (.-state this) #js {}))
- :get-derived-state-from-props (fn [props state]
- ;; "Expensive" calculation based on the props
- #js {:v (string/join " " (repeat (inc (:value props)) "foo"))})
- :render (fn [this]
- (r/as-element [:p "Value " (gobj/get (.-state this) "v")]))})
- component (fn []
- [pure-component {:value @prop}])]
- (with-mounted-component [component]
- (fn [c div]
- (is (= "Value foo" (.-innerText div)))
- (swap! prop inc)
- (r/flush)
- (is (= "Value foo foo" (.-innerText div))))))))
+ (doseq [opts test-options]
+ (let [prop (r/atom 0)
+ ;; Usually one can use Cljs object as React state. However,
+ ;; getDerivedStateFromProps implementation in React uses
+ ;; Object.assign to merge current state and partial state returned
+ ;; from the method, so the state has to be plain old object.
+ pure-component (r/create-class
+ {:constructor (fn [this]
+ (set! (.-state this) #js {}))
+ :get-derived-state-from-props (fn [props state]
+ ;; "Expensive" calculation based on the props
+ #js {:v (string/join " " (repeat (inc (:value props)) "foo"))})
+ :render (fn [this]
+ (r/as-element [:p "Value " (gobj/get (.-state this) "v")]))})
+ component (fn []
+ [pure-component {:value @prop}])]
+ (with-mounted-component [component]
+ opts
+ (fn [c div]
+ (is (= "Value foo" (.-innerText div)))
+ (swap! prop inc)
+ (r/flush)
+ (is (= "Value foo foo" (.-innerText div)))))))))
(deftest get-derived-state-from-error-test
(when r/is-client
- (let [prop (r/atom 0)
- component (r/create-class
- {:constructor (fn [this props]
- (set! (.-state this) #js {:hasError false}))
- :get-derived-state-from-error (fn [error]
- #js {:hasError true})
- :component-did-catch (fn [this e info])
- :render (fn [^js/React.Component this]
- (r/as-element (if (.-hasError (.-state this))
- [:p "Error"]
- (into [:<>] (r/children this)))))})
- bad-component (fn []
- (if (= 0 @prop)
- [:div "Ok"]
- (throw (js/Error. "foo"))))]
- (wrap-capture-window-error
- (wrap-capture-console-error
+ (doseq [opts test-options]
+ (let [prop (r/atom 0)
+ component (r/create-class
+ {:constructor (fn [this props]
+ (set! (.-state this) #js {:hasError false}))
+ :get-derived-state-from-error (fn [error]
+ #js {:hasError true})
+ :component-did-catch (fn [this e info])
+ :render (fn [^js/React.Component this]
+ (r/as-element (if (.-hasError (.-state this))
+ [:p "Error"]
+ (into [:<>] (r/children this)))))})
+ bad-component (fn []
+ (if (= 0 @prop)
+ [:div "Ok"]
+ (throw (js/Error. "foo"))))]
+ (wrap-capture-window-error
+ (wrap-capture-console-error
#(with-mounted-component [component [bad-component]]
+ opts
(fn [c div]
(is (= "Ok" (.-innerText div)))
(swap! prop inc)
(r/flush)
- (is (= "Error" (.-innerText div))))))))))
+ (is (= "Error" (.-innerText div)))))))))))
(deftest get-snapshot-before-update-test
(when r/is-client
- (let [ref (react/createRef)
- prop (r/atom 0)
- did-update (atom nil)
- component (r/create-class
- {:get-snapshot-before-update (fn [this [_ prev-props] prev-state]
- {:height (.. ref -current -scrollHeight)})
- :component-did-update (fn [this [_ prev-props] prev-state snapshot]
- (reset! did-update snapshot))
- :render (fn [this]
- (r/as-element
- [:div
- {:ref ref
- :style {:height "20px"}}
- "foo"]))})
- component-2 (fn []
- [component {:value @prop}])]
- (with-mounted-component [component-2]
- (fn [c div]
- ;; Attach to DOM to get real height value
- (.appendChild js/document.body div)
- (is (= "foo" (.-innerText div)))
- (swap! prop inc)
- (r/flush)
- (is (= {:height 20} @did-update))
- (.removeChild js/document.body div))))))
+ (doseq [opts test-options]
+ (let [ref (react/createRef)
+ prop (r/atom 0)
+ did-update (atom nil)
+ component (r/create-class
+ {:get-snapshot-before-update (fn [this [_ prev-props] prev-state]
+ {:height (.. ref -current -scrollHeight)})
+ :component-did-update (fn [this [_ prev-props] prev-state snapshot]
+ (reset! did-update snapshot))
+ :render (fn [this]
+ (r/as-element
+ [:div
+ {:ref ref
+ :style {:height "20px"}}
+ "foo"]))})
+ component-2 (fn []
+ [component {:value @prop}])]
+ (with-mounted-component [component-2]
+ opts
+ (fn [c div]
+ ;; Attach to DOM to get real height value
+ (.appendChild js/document.body div)
+ (is (= "foo" (.-innerText div)))
+ (swap! prop inc)
+ (r/flush)
+ (is (= {:height 20} @did-update))
+ (.removeChild js/document.body div)))))))
(deftest issue-462-test
(when r/is-client
- (let [val (r/atom 0)
- render (atom 0)
- a (fn issue-462-a [nr]
- (swap! render inc)
- [:h1 "Value " nr])
- b (fn issue-462-b []
- [:div
- ^{:key @val}
- [a @val]])
- c (fn issue-462-c []
- ^{:key @val}
- [b])]
- (with-mounted-component [c]
- (fn [c div]
- (is (= 1 @render))
- (reset! val 1)
- (r/flush)
- (is (= 2 @render))
- (reset! val 0)
- (r/flush)
- (is (= 3 @render)))))))
+ (doseq [opts test-options]
+ (let [val (r/atom 0)
+ render (atom 0)
+ a (fn issue-462-a [nr]
+ (swap! render inc)
+ [:h1 "Value " nr])
+ b (fn issue-462-b []
+ [:div
+ ^{:key @val}
+ [a @val]])
+ c (fn issue-462-c []
+ ^{:key @val}
+ [b])]
+ (with-mounted-component [c]
+ opts
+ (fn [c div]
+ (is (= 1 @render))
+ (reset! val 1)
+ (r/flush)
+ (is (= 2 @render))
+ (reset! val 0)
+ (r/flush)
+ (is (= 3 @render))))))))
(deftest functional-component-poc-simple
(when r/is-client
(let [c (fn [x]
[:span "Hello " x])]
(with-mounted-component [c "foo"]
+ {:functional-reag-elements? true}
(fn [c div]
(is (nil? c) "Render returns nil for stateless components")
(is (= "Hello foo" (.-innerText div))))))))
@@ -1448,6 +1543,7 @@
(reset! set-count! set-count)
[:span "Count " c]))]
(with-mounted-component [c 5]
+ {:functional-reag-elements? true}
(fn [c div]
(is (nil? c) "Render returns nil for stateless components")
(is (= "Count 5" (.-innerText div)))
@@ -1460,6 +1556,7 @@
c (fn [x]
[:span "Count " @count])]
(with-mounted-component [c 5]
+ {:functional-reag-elements? true}
(fn [c div]
(is (nil? c) "Render returns nil for stateless components")
(is (= "Count 5" (.-innerText div)))
@@ -1479,6 +1576,7 @@
(reset! set-count! set-count)
[:span "Counts " @r-count " " c]))]
(with-mounted-component [c 15]
+ {:functional-reag-elements? true}
(fn [c div]
(is (nil? c) "Render returns nil for stateless components")
(is (= "Counts 3 15" (.-innerText div)))
diff --git a/test/reagenttest/utils.cljs b/test/reagenttest/utils.cljs
index 205cb3b..e1b5867 100644
--- a/test/reagenttest/utils.cljs
+++ b/test/reagenttest/utils.cljs
@@ -2,15 +2,18 @@
(:require [reagent.core :as r]
[reagent.dom :as rdom]))
-(defn with-mounted-component [comp f]
- (when r/is-client
- (let [div (.createElement js/document "div")]
- (try
- (let [c (rdom/render comp div)]
- (f c div))
- (finally
- (rdom/unmount-component-at-node div)
- (r/flush))))))
+(defn with-mounted-component
+ ([comp f]
+ (with-mounted-component comp nil f))
+ ([comp opts f]
+ (when r/is-client
+ (let [div (.createElement js/document "div")]
+ (try
+ (let [c (rdom/render comp div opts)]
+ (f c div))
+ (finally
+ (rdom/unmount-component-at-node div)
+ (r/flush)))))))
(defn with-mounted-component-async [comp done f]
(when r/is-client