Fork me on GitHub
#core-async
<
2020-08-30
>
Kira McLean00:08:23

Hi everyone. I have a question about testing a pub/sub system built on top of core.async (in Clojurescript). I have some code that looks vaguely like

(def my-events (a/chan))

(async/subscribe my-pub :topic-kw my-events)

(def event-happened (go-loop []
                      (when-let [event (async/<! my-events)]
                        (println "Got the event")
                        ... do side effect with event ...)))
                        
-----

(deftest
  (testing "the side effect happened"
    ... click that makes the side effect happen ...
    ... expectation that would be true if the side effect happened ...
    (println "Test over")))
In my case the side effect is updating the URL query params of a single-page app. Several clicks around the UI publish an event whose content is the new state that gets serialised into URL query params by the subscriber. The UI is built with reagent. In my naive first attempt to test this, the test finishes before the subscription processes the event (i.e. in the pseudocode above “Got the event” prints after “Test over”), so of course the expectation fails. If I move the side effect directly into the click handler(s), the test passes. So my question is how (if possible?) to let the go-loop get the event off the channel within the test run. Is this possible?

hiredman01:08:17

It is complicated in cljs, because there is only a single thread, in order for the go loops to run your tests need to yield control of the thread

hiredman01:08:23

I haven't used it but I think the cljs port of clojure test has some kind of macro or something for making threading control around in async tests easier

Kira McLean01:08:37

Yeah.. I was wondering if that’s even possible. I’m pretty new to core.async, I’ve worked with JS quite a bit but always orchestrated stuff like this with promises before, so it’s a bit unfamiliar.

Kira McLean01:08:08

I came across the asynchttps://clojurescript.org/tools/testing#async-testing, but either I’m not using it properly or it doesn’t do what I think it does.