joyride

pez 2023-12-03T16:45:24.657219Z

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?

borkdude 2023-12-03T16:47:23.045959Z

Are you running this test within joyride itself?

borkdude 2023-12-03T16:47:35.760909Z

yes, if I remember correctly

borkdude 2023-12-03T16:48:15.100969Z

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?

borkdude 2023-12-03T16:48:30.134989Z

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

borkdude 2023-12-03T16:49:50.715019Z

yes, it's an async thing it seems after looking into (source *exec-tap-fn*)

pez 2023-12-03T16:52:46.035679Z

Ah, thanks. I’ll try with an atom and async.

pez 2023-12-03T16:59:39.627309Z

Is it async as in a promise?

borkdude 2023-12-03T17:00:58.718929Z

no

borkdude 2023-12-03T17:01:15.179009Z

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))))
nil

borkdude 2023-12-03T17:01:25.090609Z

fire and forget

pez 2023-12-03T17:04:47.493689Z

I see, so I could return fire using the same ammo maybe 😃

borkdude 2023-12-03T17:05:34.137589Z

just set a timeout maybe which is higher than 0 and there you do the test + call done

pez 2023-12-03T17:06:03.216049Z

Yeah, something like that was what I had in mind.

pez 2023-12-03T19:58:06.014299Z

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…

borkdude 2023-12-03T20:03:58.826509Z

Perhaps remove-tap doesn't work correctly?

borkdude 2023-12-03T20:04:43.191689Z

or perhaps remove the tap-call test and see if that has to do with it

👀 1
pez 2023-12-03T20:12:43.749069Z

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.
🎉

djblue 2023-12-03T03:03:22.071159Z

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.

🎉 3
2023-12-06T22:45:11.268559Z

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.

djblue 2023-12-03T03:05:23.870609Z

My goal is that everything feels like it would from a typical clojure project.

djblue 2023-12-03T03:13:18.431979Z

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.