reagent/test/reagenttest/testreagent.cljs
Dan Holmsand 253cb999ba Call component functions with this set to current component
This makes us more consistent with React classes, and gives more
informative stack traces sometimes.

Also stop wrapping unknown methods - let React deal with them directly.
2015-10-11 15:04:50 +02:00

848 lines
27 KiB
Clojure

(ns reagenttest.testreagent
(:require [cljs.test :as t :refer-macros [is deftest testing]]
[reagent.ratom :as rv :refer-macros [reaction]]
[reagent.debug :as debug :refer-macros [dbg println log dev?]]
[reagent.interop :refer-macros [.' .!]]
[reagent.core :as r]
[reagent.impl.util :as util]))
(defn fixture [f]
(set! rv/debug true)
(f)
(set! rv/debug false))
(t/use-fixtures :once fixture)
(defn running [] (rv/running))
(def isClient r/is-client)
(def rflush r/flush)
(defn add-test-div [name]
(let [doc js/document
body (.-body js/document)
div (.createElement doc "div")]
(.appendChild body div)
div))
(defn with-mounted-component [comp f]
(when isClient
(let [div (add-test-div "_testreagent")]
(let [comp (r/render-component comp div #(f comp div))]
(r/unmount-component-at-node div)
(r/flush)
(.removeChild (.-body js/document) div)))))
(defn found-in [re div]
(let [res (.-innerHTML div)]
(if (re-find re res)
true
(do (println "Not found: " res)
false))))
(deftest really-simple-test
(when isClient
(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 (found-in #"div in really-simple" div))
(r/flush)
(is (= 2 @ran))
(r/force-update-all)
(is (= 3 @ran))))
(is (= 3 @ran)))))
(deftest test-simple-callback
(when isClient
(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 (found-in #"hi you" div))))
(is (= 3 @ran)))))
(deftest test-state-change
(when isClient
(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 (found-in #"hi initial" div))
(r/replace-state @self {:foo "there"})
(r/state @self)
(rflush)
(is (found-in #"hi there" div))
(r/set-state @self {:foo "you"})
(rflush)
(is (found-in #"hi you" div))))
(is (= 4 @ran)))))
(deftest test-ratom-change
(when isClient
(let [ran (r/atom 0)
runs (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 (running)))
(is (found-in #"val 0" 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 (found-in #"val 1" 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 (found-in #"val 1" div))
(is (= 2 @ran) "did not run")))
(is (= runs (running)))
(is (= 2 @ran)))))
(deftest batched-update-test []
(when isClient
(let [ran (r/atom 0)
v1 (r/atom 0)
v2 (r/atom 0)
c2 (fn [{val :val}]
(swap! ran inc)
(is (= @v1 val))
[:div @v2])
c1 (fn []
(swap! ran inc)
[:div @v1
[c2 {:val @v1}]])]
(with-mounted-component [c1]
(fn [c div]
(rflush)
(is (= @ran 2))
(swap! v2 inc)
(is (= @ran 2))
(rflush)
(is (= @ran 3))
(swap! v1 inc)
(rflush)
(is (= @ran 5))
(swap! v2 inc)
(swap! v1 inc)
(rflush)
(is (= @ran 7))
(swap! v1 inc)
(swap! v1 inc)
(swap! v2 inc)
(rflush)
(is (= @ran 9)))))))
(deftest init-state-test
(when isClient
(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 (found-in #"this is foobar" div))))
(is (= 2 @ran)))))
(deftest shoud-update-test
(when isClient
(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]
(rflush)
(is (= @child-ran 1))
(is (found-in #"child-foo" div))
(do (reset! child-props {:style {:display :none}})
(rflush))
(is (= @child-ran 2))
(do (reset! child-props {:style {:display :none}})
(rflush))
(is (= @child-ran 2) "keyw is equal")
(do (reset! child-props {:class :foo}) (rflush))
(is (= @child-ran 3))
(do (reset! child-props {:class :foo}) (rflush))
(is (= @child-ran 3))
(do (reset! child-props {:class 'foo}) (rflush))
(is (= @child-ran 4) "symbols are different from keyw")
(do (reset! child-props {:class 'foo}) (rflush))
(is (= @child-ran 4) "symbols are equal")
(do (reset! child-props {:style {:color 'red}}) (rflush))
(is (= @child-ran 5))
(do (reset! child-props {:on-change (r/partial f)})
(rflush))
(is (= @child-ran 6))
(do (reset! child-props {:on-change (r/partial f)})
(rflush))
(is (= @child-ran 6))
(do (reset! child-props {:on-change (r/partial f1)})
(rflush))
(is (= @child-ran 7))
(r/force-update-all)
(is (= @child-ran 8)))))))
(deftest dirty-test
(when isClient
(let [ran (r/atom 0)
state (r/atom 0)
really-simple (fn []
(swap! ran inc)
(if (= @state 1)
(reset! state 3))
[:div (str "state=" @state)])]
(with-mounted-component [really-simple nil nil]
(fn [c div]
(is (= 1 @ran))
(is (found-in #"state=0" div))
(reset! state 1)
(rflush)
(is (= 2 @ran))
(is (found-in #"state=3" div))))
(is (= 2 @ran)))))
(defn as-string [comp]
(r/render-component-to-string comp))
(deftest to-string-test []
(let [comp (fn [props]
[:div (str "i am " (:foo props))])]
(is (re-find #"i am foobar"
(as-string [comp {:foo "foobar"}])))))
(deftest data-aria-test []
(is (re-find #"data-foo"
(as-string [:div {:data-foo "x"}])))
(is (re-find #"aria-foo"
(as-string [:div {:aria-foo "x"}])))
(is (not (re-find #"enctype"
(as-string [:div {"enc-type" "x"}])))
"Strings are passed through to React.")
(is (re-find #"enctype"
(as-string [:div {"encType" "x"}]))
"Strings are passed through to React, and have to be camelcase.")
(is (re-find #"enctype"
(as-string [:div {:enc-type "x"}]))
"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 (re-find #"class=.foo bar"
(as-string [:div.foo {:class "bar"}])))
(is (re-find #"class=.foo bar"
(as-string [:div.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 (re-find #"id=.foo"
(as-string [:div#bar {:id "foo"}]))
"Dynamic id overwrites static"))
(deftest ifn-component []
(defmulti my-div :type)
(defmethod my-div :fooish [child] [:div.foo (:content child)])
(defmethod my-div :barish [child] [:div.bar (:content child)])
(let [comp {:foo [:div "foodiv"]
:bar [:div "bardiv"]}]
(is (re-find #"foodiv"
(as-string [:div [comp :foo]])))
(is (re-find #"bardiv"
(as-string [:div [comp :bar]])))
(is (re-find #"class=.foo"
(as-string [my-div {:type :fooish :content "inner"}])))))
(deftest symbol-string-tag []
(is (re-find #"foobar"
(as-string ['div "foobar"])))
(is (re-find #"foobar"
(as-string ["div" "foobar"])))
(is (re-find #"id=.foo"
(as-string ['div#foo "x"])))
(is (re-find #"id=.foo"
(as-string ["div#foo" "x"])))
(is (re-find #"class=.foo bar"
(as-string ['div.foo {:class "bar"}])))
(is (re-find #"class=.foo bar"
(as-string ["div.foo.bar"])))
(is (re-find #"id=.foo"
(as-string ['div#foo.foo.bar]))))
(deftest partial-test []
(let [p1 (r/partial vector 1 2)]
(is (= (p1 3) [1 2 3]))
(is (= p1 (r/partial vector 1 2)))
(is (ifn? p1))
(is (= (r/partial vector 1 2) p1))
(is (not= p1 (r/partial vector 1 3)))))
(deftest test-null-component
(let [null-comp (fn [do-show]
(when do-show
[:div "div in test-null-component"]))]
(is (not (re-find #"test-null-component"
(as-string [null-comp false]))))
(is (re-find #"test-null-component"
(as-string [null-comp true])))))
(deftest test-static-markup
(is (= "<div>foo</div>"
(r/render-to-static-markup
[:div "foo"])))
(is (= "<div class=\"bar\"><p>foo</p></div>"
(r/render-to-static-markup
[:div.bar [:p "foo"]])))
(is (= "<div class=\"bar\"><p>foobar</p></div>"
(r/render-to-static-markup
[:div.bar {:dangerously-set-inner-HTML
{:__html "<p>foobar</p>"}} ]))))
(deftest test-return-class
(when isClient
(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 (found-in #"hi you" div))
(is (= 1 @top-ran))
(is (= 3 @ran))
(swap! prop assoc :foo "me")
(r/flush)
(is (found-in #"hi me" div))
(is (= 1 @top-ran))
(is (= 4 @ran)))))))
(deftest test-return-class-fn
(when isClient
(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)
:component-function
(fn [p a]
(is (= 1 a))
(swap! ran inc)
[:div (str "hi " (:foo p) ".")])}))
prop (r/atom {:foo "you"})
parent (fn [] [comp @prop 1])]
(with-mounted-component [parent]
(fn [C div]
(swap! ran inc)
(is (found-in #"hi you" div))
(is (= 1 @top-ran))
(is (= 3 @ran))
(swap! prop assoc :foo "me")
(r/flush)
(is (found-in #"hi me" div))
(is (= 1 @top-ran))
(is (= 4 @ran)))))))
(defn rstr [react-elem]
(r/render-to-static-markup react-elem))
(deftest test-create-element
(let [ae r/as-element
ce r/create-element]
(is (= (rstr (ae [:div]))
(rstr (ce "div"))))
(is (= (rstr (ae [:div]))
(rstr (ce "div" nil))))
(is (= (rstr (ae [:div "foo"]))
(rstr (ce "div" nil "foo"))))
(is (= (rstr (ae [:div "foo" "bar"]))
(rstr (ce "div" nil "foo" "bar"))))
(is (= (rstr (ae [:div "foo" "bar" "foobar"]))
(rstr (ce "div" nil "foo" "bar" "foobar"))))
(is (= (rstr (ae [:div.foo "bar"]))
(rstr (ce "div" #js{:className "foo"} "bar"))))
(is (= (rstr (ae [:div [:div "foo"]]))
(rstr (ce "div" nil (ce "div" nil "foo")))))
(is (= (rstr (ae [:div [:div "foo"]]))
(rstr (ce "div" nil (ae [:div "foo"])))))
(is (= (rstr (ae [:div [:div "foo"]]))
(rstr (ae [:div (ce "div" nil "foo")]))))))
(def ndiv (.' util/react
createClass
#js{:displayName "ndiv"
:render
(fn []
(this-as
this
(r/create-element
"div" #js{:className (.' this :props.className)}
(.' this :props.children))))}))
(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"]])))
(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"]])))
(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-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 [:p "p:a"])
(rstr (ce c1 #js{:a "a"}))))
(is (= @a nil))
(is (= (rstr [:p "p:"])
(rstr (ce c1 #js{:a nil}))))
(is (= (rstr [:p "p:"])
(rstr (ce c1 nil))))
(is (= (rstr [:p "p:a" [:b "b"]])
(rstr (ce c1 #js{:a "a"}
(ae [:b "b"])))))
(is (= @a nil))
(is (= (rstr [:p "p:a" [:b "b"] [:i "i"]])
(rstr (ce c1 #js{:a "a"}
(ae [:b "b"])
(ae [:i "i"])))))
(is (= @a nil))))
(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)])])]
(with-mounted-component [c]
(fn [c div]
;; Just make sure this doesn't print a debug message
))))
(deftest test-extended-syntax
(is (= (rstr [:p>b "foo"])
"<p><b>foo</b></p>"))
(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 test-force-update
(let [v (atom {:v1 0
:v2 0})
comps (atom {})
c1 (fn []
(swap! comps assoc :c1 (r/current-component))
[:p (swap! v update-in [:v1] inc)])
c2 (fn []
(swap! comps assoc :c2 (r/current-component))
[:div (swap! v update-in [:v2] inc)
[c1]])]
(with-mounted-component [c2]
(fn [c div]
(is (= @v {:v1 1 :v2 1}))
(r/force-update (:c2 @comps))
(is (= @v {:v1 1 :v2 2}))
(r/force-update (:c1 @comps))
(is (= @v {:v1 2 :v2 2}))
(r/force-update (:c2 @comps) true)
(is (= @v {:v1 3 :v2 3}))))))
(deftest test-component-path
(let [a (atom nil)
tc (r/create-class {:display-name "atestcomponent"
:render (fn []
(let [c (r/current-component)]
(reset! a (r/component-path c))
[:div]))})]
(with-mounted-component [tc]
(fn [c]
(is (seq @a))
(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 (= (rstr [c2]) "<div>foo</div>"))))
(deftest basic-with-let
(when isClient
(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])))))
(deftest with-let-destroy-only
(when isClient
(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])))))
(deftest with-let-arg
(when isClient
(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 (= @a "foo"))
(reset! s "bar")
(r/flush)
(is (= @a "bar")))))))
(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]))))
(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"})
: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)
:component-will-receive-props
(fn [& args]
(this-as c (is (= c (first args))))
(add-args :will-receive args))
: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))
check (fn []
(is (= (:initial-state @res)
{:at 1 :args [@t]}))
(is (= (:will-mount @res)
{:at 2 :args [@t]}))
(is (= (:render @res)
{:at 3 :args ["a" "b"]}))
(is (= (:did-mount @res)
{:at 4 :args [@t]}))
(reset! arg ["a" "c"])
(r/flush)
(is (= (:will-receive @res)
{:at 5 :args [@t [@comp "a" "b"]]}))
(is (= (:should-update @res)
{:at 6 :args [@t [@comp "a" "b"] [@comp "a" "c"]]}))
(is (= (:will-update @res)
{:at 7 :args [@t [@comp "a" "c"]]}))
(is (= (:render @res)
{:at 8 :args ["a" "c"]}))
(is (= (:did-update @res)
{:at 9 :args [@t [@comp "a" "b"]]})))]
(when isClient
(with-mounted-component [c2] check)
(is (= (:will-unmount @res)
{:at 10 :args [@t]}))
(reset! comp (with-meta render2 ls))
(reset! arg defarg)
(reset! n1 0)
(with-mounted-component [c2] check)
(is (= (:will-unmount @res)
{:at 10 :args [@t]})))))
(defn foo []
[:div])
(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])))
(is (thrown-with-msg?
:default #"Expected React component in: \[:> \[:div]]"
(rstr [:> [:div]])))
(is (thrown-with-msg?
:default #"Invalid tag: 'p.'"
(rstr [:p.])))
(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 (.' util/react createClass #js{:render (fn [])})
pkg "reagenttest.testreagent."
stack1 (str "in " pkg "comp1")
stack2 (str "in " pkg "comp2 > " pkg "comp1")
lstr (fn [& s] (list (apply str s)))
re (fn [& s]
(re-pattern (apply str s)))
rend (fn [x]
(with-mounted-component x identity))]
(let [e (debug/track-warnings
#(is (thrown-with-msg?
:default (re "Invalid tag: 'div.' \\(" stack2 "\\)")
(rend [comp2 [:div. "foo"]]))))]
(is (= e
{:error (lstr "Error rendering component (" stack2 ")")})))
(let [e (debug/track-warnings
#(is (thrown-with-msg?
:default (re "Invalid tag: 'div.' \\(" stack1 "\\)")
(rend [comp1 [:div. "foo"]]))))]
(is (= e
{:error (lstr "Error rendering component (" stack1 ")")})))
(let [e (debug/track-warnings #(r/reactify-component nat))]
(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
#(r/as-element (comp4)))]
(is (re-find #"Every element in a seq should have a unique :key"
(-> e :warn first)))))))
(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 (r/dom-node this)))})]
(with-mounted-component [comp]
(fn [c div]
(is (= (.-innerHTML @ref) "foobar"))
(is (= (.-innerHTML @node) "foobar"))
(is (identical? @ref @node))))))