So, @djblue woke up @eveningsky’s old PR about adding tap>. https://github.com/BetterThanTomorrow/joyride/pull/113 It was a rather obvious copy/paste error where add-tap was copied from remove-tap. Haha. So easy to fix and I now have it working in my dev Joyride. However, I’d like to add a test for it and don’t know how to. This does not work:
(ns integration-test.tap-test
(:require [cljs.test :refer [deftest testing is]]))
(deftest tap
(testing "Taps to added tap"
(let [tap-fn #(println "tap tap:" %)]
(add-tap tap-fn)
(is (= "tap tap: tapped"
(with-out-str (tap> "tapped"))))
(remove-tap tap-fn))))
(I didn’t think it would work, but anyway) Any ideas anyone?Are you running this test within joyride itself?
yes, if I remember correctly
I don't know if tap works with callbacks in CLJS, if so, the binding may already be gone by the time the tapped thing is printed?
another way to do this is with an atom which gets conj-ed on to, this way you don't have to deal with i/o
yes, it's an async thing it seems after looking into (source *exec-tap-fn*)
Ah, thanks. I’ll try with an atom and async.
Is it async as in a promise?
no
cljs.user=> (source *exec-tap-fn*)
(defn ^{:doc "Arranges to have tap functions executed via the supplied f, a
function of no arguments. Returns true if successful, false otherwise." :dynamic true}
*exec-tap-fn*
[f]
(and
(exists? js/setTimeout)
;; See CLJS-3274 - workaround for recent WebKit releases
(boolean (js/setTimeout f 0))))
nilfire and forget
I see, so I could return fire using the same ammo maybe 😃
just set a timeout maybe which is higher than 0 and there you do the test + call done
Yeah, something like that was what I had in mind.
These tests pass:
(def !tap (atom []))
(defn tap-fn! [x]
(swap! !tap conj x))
(defn tap>+ [x]
(p/create (fn [resolve _reject]
(tap> x)
(js/setTimeout (fn [] (resolve)) 10))))
(deftest tap-call
(testing "`tap>` returns a boolean"
(is (boolean? (tap> "tapped")))))
(deftest tap
(testing "taps to our atom"
(async done
(p/do!
(add-tap tap-fn!)
(reset! !tap [])
(tap>+ "tapped")
(is (= "tapped"
(first @!tap)))
(remove-tap tap-fn!)
(println "!tap:" (pr-str @!tap))
(reset! !tap [])
(done)))))
However, it prints this:
!tap: ["tapped" "tapped"]
Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
I don’t understand why there are two "tapped" in the atom…Perhaps remove-tap doesn't work correctly?
or perhaps remove the tap-call test and see if that has to do with it
Thanks! Indeed, it was the tap-call. Now we have
(defn tap>+ [x]
(p/create (fn [resolve _reject]
(let [result (tap> x)]
(js/setTimeout (fn [] (resolve result)) 10)))))
(deftest tap
(testing "taps to our atom"
(async done
(p/do!
(add-tap tap-fn!)
(reset! !tap [])
(p/let [result+ (tap>+ "tapped")]
(is (boolean? result+)))
(is (= ["tapped"] @!tap))
(remove-tap tap-fn!)
(reset! !tap [])
(done)))))
Output:
Ran 1 tests containing 2 assertions.
0 failures, 0 errors.
🎉Since I've been doing more with joyride recently, I started missing having portal for debugging. https://github.com/djblue/portal/pull/204/files#diff-0a2bc224348485b5f2d0f815b9aabd389f1881f5eb2f208720294942f82101c0 is my initial implementation for what consuming portal via joyride would look like. Feedback is welcome. Also, having clojure's tap> facility would be awesome.
Oh, that would be so helpful. Joyride is lovely, but some of the things I've tried to do were very hard due to visibility.
My goal is that everything feels like it would from a typical clojure project.
I'm still working on seamlessly getting clojure values from the joyride cljs build into the portal cljs build. Since both are part of different cljs builds, the underlying types will differ.