2015-02-10 13:18:56 +00:00
(ns reagenttest.testcursor
2019-12-17 12:32:45 +00:00
(:require [clojure.test :as t :refer-macros [is deftest testing]]
2015-01-31 22:09:42 +00:00
[reagent.ratom :as rv :refer-macros [run! reaction]]
2015-07-31 13:13:27 +00:00
[reagent.core :as r]))
2014-09-09 02:31:05 +00:00
;; this repeats all the atom tests but using cursors instead
2015-09-30 06:56:06 +00:00
(defn fixture [f]
2015-09-30 07:40:57 +00:00
(r/flush)
2015-02-11 18:06:38 +00:00
(set! rv/debug true)
2015-09-30 06:56:06 +00:00
(f)
(set! rv/debug false))
(t/use-fixtures :once fixture)
(defn running []
2015-02-11 18:06:38 +00:00
(rv/running))
2015-09-30 06:56:06 +00:00
2014-09-09 02:31:05 +00:00
(defn dispose [v] (rv/dispose! v))
2015-08-31 08:39:17 +00:00
(def testite 10)
2015-08-31 08:05:53 +00:00
2014-09-09 02:31:05 +00:00
(deftest basic-cursor
(let [runs (running)
start-base (rv/atom {:a {:b {:c 0}}})
2015-01-31 13:29:01 +00:00
start (r/cursor start-base [:a :b :c])
2014-09-09 02:31:05 +00:00
sv (reaction @start)
comp (reaction @sv (+ 2 @sv))
c2 (reaction (inc @comp))
count (rv/atom 0)
out (rv/atom 0)
res (reaction
(swap! count inc)
@sv @c2 @comp)
const (run!
(reset! out @res))]
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
(is (= @count 1) "constrain ran")
(is (= @out 2))
(reset! start 1)
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
(is (= @out 3))
2015-10-07 09:32:42 +00:00
(is (<= 2 @count 3))
2014-09-09 02:31:05 +00:00
(dispose const)
(is (= @start-base {:a {:b {:c 1}}}))
(is (= (running) runs))))
(deftest double-dependency
(let [runs (running)
start-base (rv/atom {:a {:b {:c 0}}})
2015-01-31 13:29:01 +00:00
start (r/cursor start-base [:a :b :c])
2014-09-09 02:31:05 +00:00
c3-count (rv/atom 0)
c1 (reaction @start 1)
c2 (reaction @start)
c3 (rv/make-reaction
(fn []
(swap! c3-count inc)
(+ @c1 @c2))
:auto-run true)]
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
(is (= @c3-count 0))
(is (= @c3 1))
(is (= @c3-count 1) "t1")
(swap! start inc)
2015-09-30 07:40:57 +00:00
(r/flush)
2015-02-04 21:14:04 +00:00
(is (= @c3-count 2) "t2")
2014-09-09 02:31:05 +00:00
(is (= @c3 2))
2015-02-04 21:14:04 +00:00
(is (= @c3-count 2) "t3")
2014-09-09 02:31:05 +00:00
(is (= @start-base {:a {:b {:c 1}}}))
(dispose c3)
(is (= (running) runs))))
(deftest test-from-reflex
(let [runs (running)]
(let [!ctr-base (rv/atom {:x {:y 0 :z 0}})
2015-01-31 13:29:01 +00:00
!counter (r/cursor !ctr-base [:x :y])
2014-09-09 02:31:05 +00:00
!signal (rv/atom "All I do is change")
co (run!
;;when I change...
@!signal
;;update the counter
(swap! !counter inc))]
(is (= 1 @!counter) "Constraint run on init")
(reset! !signal "foo")
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
(is (= 2 @!counter)
"Counter auto updated")
(is (= @!ctr-base {:x {:y 2 :z 0}}))
(dispose co))
(let [!x-base (rv/atom {:a {:b 0 :c {:d 0}}})
2015-01-31 13:29:01 +00:00
!x (r/cursor !x-base [:a :c :d])
2014-09-09 02:31:05 +00:00
!co (rv/make-reaction #(inc @!x) :auto-run true)]
2014-11-22 09:45:36 +00:00
(is (= 1 @!co) "CO has correct value on first deref")
(swap! !x inc)
2014-09-09 02:31:05 +00:00
(is (= 2 @!co) "CO auto-updates")
(is (= {:a {:b 0 :c {:d 1}}} @!x-base))
(dispose !co))
(is (= runs (running)))))
(deftest test-unsubscribe
2015-08-31 08:05:53 +00:00
(dotimes [x testite]
2014-09-09 02:31:05 +00:00
(let [runs (running)
a-base (rv/atom {:test {:unsubscribe 0 :value 42}})
2015-01-31 13:29:01 +00:00
a (r/cursor a-base [:test :unsubscribe])
2014-09-09 02:31:05 +00:00
a1 (reaction (inc @a))
a2 (reaction @a)
b-changed (rv/atom 0)
c-changed (rv/atom 0)
b (reaction
(swap! b-changed inc)
(inc @a1))
c (reaction
(swap! c-changed inc)
(+ 10 @a2))
res (run!
(if (< @a2 1) @b @c))]
(is (= @res (+ 2 @a)))
(is (= @b-changed 1))
(is (= @c-changed 0))
2014-11-22 09:45:36 +00:00
2014-09-09 02:31:05 +00:00
(reset! a -1)
(is (= @res (+ 2 @a)))
(is (= @b-changed 2))
(is (= @c-changed 0))
(is (= @a-base {:test {:unsubscribe -1 :value 42}}))
2014-11-22 09:45:36 +00:00
2014-09-09 02:31:05 +00:00
(reset! a 2)
(is (= @res (+ 10 @a)))
(is (<= 2 @b-changed 3))
(is (= @c-changed 1))
(is (= @a-base {:test {:unsubscribe 2 :value 42}}))
2014-11-22 09:45:36 +00:00
2014-09-09 02:31:05 +00:00
(reset! a 3)
(is (= @res (+ 10 @a)))
(is (<= 2 @b-changed 3))
2015-02-04 21:14:04 +00:00
(is (= @c-changed 2))
2014-09-09 02:31:05 +00:00
(is (= @a-base {:test {:unsubscribe 3 :value 42}}))
2014-11-22 09:45:36 +00:00
2014-09-09 02:31:05 +00:00
(reset! a 3)
(is (= @res (+ 10 @a)))
(is (<= 2 @b-changed 3))
2015-02-04 21:14:04 +00:00
(is (= @c-changed 2))
2014-09-09 02:31:05 +00:00
(is (= @a-base {:test {:unsubscribe 3 :value 42}}))
2014-11-22 09:45:36 +00:00
2014-09-09 02:31:05 +00:00
(reset! a -1)
(is (= @res (+ 2 @a)))
(is (= @a-base {:test {:unsubscribe -1 :value 42}}))
(dispose res)
(is (= runs (running))))))
(deftest maybe-broken
(let [runs (running)]
(let [runs (running)
a-base (rv/atom {:a {:b 0 :c {:d 42}}})
2015-01-31 13:29:01 +00:00
a (r/cursor a-base [:a :b])
2014-09-09 02:31:05 +00:00
b (reaction (inc @a))
c (reaction (dec @a))
d (reaction (str @b))
res (rv/atom 0)
cs (run!
(reset! res @d))]
(is (= @res "1"))
(dispose cs))
;; should be broken according to https://github.com/lynaghk/reflex/issues/1
;; but isnt
(let [a-base (rv/atom {:a 0})
2015-01-31 13:29:01 +00:00
a (r/cursor a-base [:a])
2014-09-09 02:31:05 +00:00
b (reaction (inc @a))
c (reaction (dec @a))
d (run! [@b @c])]
(is (= @d [1 -1]))
(dispose d))
(let [a-base (rv/atom 0)
2015-01-31 13:29:01 +00:00
a (r/cursor a-base [])
2014-09-09 02:31:05 +00:00
b (reaction (inc @a))
c (reaction (dec @a))
d (run! [@b @c])
res (rv/atom 0)]
(is (= @d [1 -1]))
(let [e (run! (reset! res @d))]
(is (= @res [1 -1]))
(dispose e))
(dispose d))
(is (= runs (running)))))
(deftest test-dispose
2015-08-31 08:05:53 +00:00
(dotimes [x testite]
2014-09-09 02:31:05 +00:00
(let [runs (running)
a-base (rv/atom {:a 0 :b 0})
2015-01-31 13:29:01 +00:00
a (r/cursor a-base [:a])
2014-09-09 02:31:05 +00:00
disposed (rv/atom nil)
disposed-c (rv/atom nil)
disposed-cns (rv/atom nil)
count-b (rv/atom 0)
b (rv/make-reaction (fn []
(swap! count-b inc)
(inc @a))
:on-dispose #(reset! disposed true))
c (rv/make-reaction #(if (< @a 1) (inc @b) (dec @a))
:on-dispose #(reset! disposed-c true))
res (rv/atom nil)
cns (rv/make-reaction #(reset! res @c)
:auto-run true
:on-dispose #(reset! disposed-cns true))]
@cns
(is (= @res 2))
2015-09-30 07:40:57 +00:00
(is (= (+ 6 runs) (running)))
2014-09-09 02:31:05 +00:00
(is (= @count-b 1))
(is (= {:a 0 :b 0} @a-base))
(reset! a -1)
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
(is (= @res 1))
(is (= @disposed nil))
(is (= @count-b 2))
2015-09-30 07:40:57 +00:00
(is (= (+ 6 runs) (running)) "still running")
2014-09-09 02:31:05 +00:00
(is (= {:a -1 :b 0} @a-base))
(reset! a 2)
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
(is (= @res 1))
(is (= @disposed true))
2015-09-30 07:40:57 +00:00
(is (= (+ 4 runs) (running)) "less running count")
2014-09-09 02:31:05 +00:00
(is (= {:a 2 :b 0} @a-base))
(reset! disposed nil)
(reset! a -1)
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
;; This fails sometimes on node. I have no idea why.
(is (= 1 @res) "should be one again")
(is (= @disposed nil))
(is (= {:a -1 :b 0} @a-base))
(reset! a 2)
2015-09-30 07:40:57 +00:00
(r/flush)
2014-09-09 02:31:05 +00:00
(is (= @res 1))
(is (= @disposed true))
(dispose cns)
(is (= @disposed-c true))
(is (= @disposed-cns true))
(is (= {:a 2 :b 0} @a-base))
(is (= runs (running))))))
(deftest test-on-set
(let [runs (running)
a-base (rv/atom {:set 0})
2015-01-31 13:29:01 +00:00
a (r/cursor a-base [:set])
2014-09-09 02:31:05 +00:00
b (rv/make-reaction #(+ 5 @a)
:auto-run true
:on-set (fn [oldv newv]
(reset! a (+ 10 newv))))]
@b
(is (= 5 @b))
(is (= {:set 0} @a-base))
(reset! a 1)
(is (= 6 @b))
(is (= {:set 1} @a-base))
(reset! b 1)
(is (= 11 @a))
(is (= 16 @b))
(dispose b)
(is (= {:set 11} @a-base))
(is (= runs (running)))))
2014-11-22 09:45:36 +00:00
(deftest test-equality
2015-07-31 13:13:27 +00:00
(let [a (r/atom {:foo "bar"})
a1 (r/atom {:foo "bar"})
2015-01-31 13:29:01 +00:00
c (r/cursor a [:foo])
2015-01-31 12:32:48 +00:00
foo (fn
([path] (get-in @a path))
([path v] (swap! a assoc-in path v)))
foobar (fn
([path] (get-in @a path))
([path v] (swap! a assoc :foobar v)))
2015-01-31 13:08:19 +00:00
c2 (r/cursor foo [:foo])
c3 (r/cursor foobar [:foo])]
2015-01-31 12:32:48 +00:00
2014-11-22 09:45:36 +00:00
(is (= @c "bar"))
(is (= @c2 "bar"))
(is (= @c3 "bar"))
2015-01-31 13:29:01 +00:00
(is (= c (r/cursor a [:foo])))
(is (not= c (r/cursor a1 [:foo])))
(is (not= c (r/cursor a [:foobar])))
2015-01-31 13:08:19 +00:00
(is (= c2 (r/cursor foo [:foo])))
(is (= c3 (r/cursor foobar [:foo])))
2015-01-31 12:32:48 +00:00
(is (= c2 c2))
2015-01-31 13:08:19 +00:00
(is (not= c2 (r/cursor foobar [:foo])))
(is (not= c3 (r/cursor foo [:foo])))
(is (not= c2 (r/cursor foo [:foobar])))
2014-11-22 09:45:36 +00:00
(reset! c2 "foobar")
(is (= @c2 "foobar"))
(is (= @c "foobar"))
(is (= @a {:foo "foobar"}))
(reset! c "bar")
(is (= @c2 "bar"))
(is (= @c "bar"))
(is (= @a {:foo "bar"}))
2015-01-31 13:29:01 +00:00
(is (= c (r/cursor a [:foo])))
2015-01-31 13:08:19 +00:00
(is (= c2 (r/cursor foo [:foo])))
2014-11-22 09:45:36 +00:00
(reset! c3 "foo")
(is (= @a {:foo "bar" :foobar "foo"}))))
2014-11-22 10:08:17 +00:00
(deftest test-wrap
2015-07-31 13:13:27 +00:00
(let [a (r/atom {:foo "bar"})
2014-11-22 10:08:17 +00:00
w (r/wrap (:foo @a) swap! a assoc :foo)]
(is (= @w "bar"))
(is (= w (r/wrap "bar" swap! a assoc :foo)))
(is (not= w (r/wrap "foobar" swap! a assoc :foo)))
(is (not= w (r/wrap "bar" swap! a assoc :foobar)))
(is (not= w (r/wrap "bar" reset! a assoc :foo)))
(reset! w "foobar")
(is (= @w "foobar"))
(is (= @a {:foo "foobar"}))
(is (not= w (r/wrap "bar" swap! a assoc :foo)))
(is (not= w (r/wrap "foobar" swap! a assoc :foo)))))
2015-01-31 10:01:35 +00:00
(deftest cursor-values
2015-07-31 13:13:27 +00:00
(let [test-atom (r/atom {:a {:b {:c {:d 1}}}})
2015-01-31 13:29:01 +00:00
test-cursor (r/cursor test-atom [:a :b :c :d])
test-cursor2 (r/cursor test-atom [])
2015-01-31 11:22:53 +00:00
runs (running)] ;; nasty edge case
2015-01-31 10:01:35 +00:00
;; get the initial values
(is (= (get-in @test-atom [:a :b :c :d])
@test-cursor))
(is (= (get-in @test-atom [])
@test-cursor2))
;; now we update the cursor with a reset
(reset! test-cursor 2)
(is (= @test-cursor 2))
(is (= (get-in @test-atom [:a :b :c :d]) 2))
(reset! test-cursor2 3)
(is (= @test-cursor2 3))
(is (= @test-atom 3))
(reset! test-atom {:a {:b {:c {:d 1}}}}) ;; restore test-atom
;; swap
(reset! test-cursor {}) ;; empty map
(swap! test-cursor assoc :z 3)
(is (= @test-cursor {:z 3}))
(is (= (get-in @test-atom [:a :b :c :d])
{:z 3}))
(reset! test-cursor2 {}) ;; empty map
(swap! test-cursor2 assoc :z 3)
(is (= @test-cursor2 {:z 3}))
(is (= (get-in @test-atom [])
2015-01-31 11:22:53 +00:00
{:z 3}))
2015-07-23 13:10:35 +00:00
(reset! test-cursor {}) ;; empty map
(swap! test-cursor assoc :x 1 :y 2 :z 3 :w)
(is (= @test-cursor {:x 1 :y 2 :z 3 :w nil}))
(is (= (get-in @test-atom [:a :b :c :d])
{:x 1 :y 2 :z 3 :w nil}))
2015-01-31 11:22:53 +00:00
(is (= runs (running)))))
2015-01-31 10:01:35 +00:00
2015-02-01 18:43:26 +00:00
(deftest cursor-atom-behaviors
2015-07-31 13:13:27 +00:00
(let [test-atom (r/atom {:a {:b {:c {:d 1}}}})
2015-01-31 13:29:01 +00:00
test-cursor (r/cursor test-atom [:a :b :c :d])
2015-07-31 13:13:27 +00:00
witness (r/atom nil)
2015-01-31 11:22:53 +00:00
runs (running)]
2015-01-31 10:01:35 +00:00
;; per the description, reset! should return the new values
(is (= {}
(reset! test-cursor {})))
;; per the description, swap! should return the new values
(is (= {:z [1 2 3]}
(swap! test-cursor assoc :z [1 2 3])))
;; watches should behave like with a normal atom
(reset! test-cursor "old")
(add-watch test-cursor :w #(reset! witness
{:key %1 :ref %2 :old %3 :new %4}))
(reset! test-cursor "new") ;; this should trigger the watch function
(is (= (:key @witness) :w))
;; cursor reports that the reaction is the current atom,
;; but I guess that's ok
(is (= (:old @witness) "old"))
(is (= (:new @witness) "new"))
2015-01-31 23:41:59 +00:00
(is (= @(:ref @witness) @test-cursor))
(is (= (:new @witness) "new"))
(reset! test-atom {:a {:b {:c {:d "newer"}}}})
;; watch doesn't run until the value is realized
(is (= (:new @witness) "new"))
(is (= @test-cursor "newer"))
@test-cursor
(is (= (:old @witness) "new"))
(is (= (:new @witness) "newer"))
@test-cursor
(is (= (:old @witness) "new"))
(is (= (:new @witness) "newer"))
2015-01-31 11:22:53 +00:00
2015-01-31 10:01:35 +00:00
;; can we remove the watch?
(remove-watch test-cursor :w)
(reset! test-cursor "removed")
2015-01-31 23:41:59 +00:00
(is (= (:new @witness) "newer")) ;; shouldn't have changed
2015-01-31 11:22:53 +00:00
(is (= (running) runs))
2015-01-31 10:01:35 +00:00
))
2015-02-01 18:43:26 +00:00
(deftest wrap-atom-behaviors
2015-07-31 13:13:27 +00:00
(let [test-atom (r/atom "foo")
2015-02-01 18:43:26 +00:00
test-wrap (r/wrap @test-atom reset! test-atom)
2015-07-31 13:13:27 +00:00
witness (r/atom nil)]
2015-02-01 18:43:26 +00:00
;; per the description, reset! should return the new values
(is (= {}
(reset! test-wrap {})))
(is (= @test-wrap @test-atom))
;; per the description, swap! should return the new values
(is (= {:z [1 2 3]}
(swap! test-wrap assoc :z [1 2 3])))
(is (= @test-wrap @test-atom))
;; watches should behave like with a normal atom
(reset! test-wrap "old")
(add-watch test-wrap :w #(reset! witness
{:key %1 :ref %2 :old %3 :new %4}))
(reset! test-wrap "new") ;; this should trigger the watch function
(is (= (:key @witness) :w))
;; cursor reports that the reaction is the current atom,
;; but I guess that's ok
(is (= (:old @witness) "old"))
(is (= (:new @witness) "new"))
(is (= (:ref @witness) test-wrap))
(is (= (:new @witness) "new"))
;; can we remove the watch?
(remove-watch test-wrap :w)
(reset! test-wrap "removed")
(is (= (:new @witness) "new")) ;; shouldn't have changed
(is (= @test-wrap @test-atom))
))
2015-02-11 05:38:57 +00:00
(deftest test-cursor-swap
2015-07-31 13:13:27 +00:00
(let [a (r/atom {:b 1})
2015-02-11 05:38:57 +00:00
b (r/cursor a [:b])]
(is (= 1 @b))
(is (= 2 (swap! b inc)))
(swap! a update-in [:b] inc)
(is (= 4 (swap! b inc)))
(is (= 4 @b))))
2015-05-25 19:31:43 +00:00
(deftest test-double-reset
(let [a (r/atom {:foo {:active? false}})
c (r/cursor a [:foo])
f (fn []
(swap! c assoc :not-pristine true)
2015-09-30 07:40:57 +00:00
(swap! a update-in [:foo :active?] not)
(r/flush))
2015-07-31 13:13:27 +00:00
spy (r/atom nil)
2015-05-25 19:31:43 +00:00
r (run!
(reset! spy (:active? @c)))]
(is (= @spy false))
(f)
(is (= @spy true))
(f)
(is (= @spy false))
(dispose r)))
2020-01-15 08:30:23 +00:00
2020-01-15 08:57:36 +00:00
(def assert-enabled? (try (assert false)
false
(catch :default _ true)))
2020-01-15 08:30:23 +00:00
(deftest cursor-assert-test
2020-01-15 08:57:36 +00:00
(when assert-enabled?
(is (thrown-with-msg? :default #"src must be a reactive atom or a function, not nil while attempting to get path: \[:foo :bar\]" (r/cursor nil [:foo :bar])))))