Fork me on GitHub
#core-async
<
2022-07-14
>
B Treebeard22:07:11

Hi, I've written an async CLJS test with the promise interop <p! macro, and (abstracting away the specifics) the test below unexpectedly fails:

(deftest some-test
  (async done
         (some-sync-setup-fn)
         (go
           (<p! (some-js-async-fn))
           (some-assertion)
           (done))))
However, if I move the (some-sync-setup-fn) inside the go block as below, then the test passes:
(deftest some-test
  (async done
         (go
           (some-sync-setup-fn)
           (<p! (some-js-async-fn))
           (some-assertion)
           (done))))
Could someone help me understand why this might be happening? In my mind, as (some-sync-setup-fn) is synchronous, it will always complete before (some-js-async-fn) is called, and so it shouldn't matter whether this is inside the go block or not. Is my understanding incorrect?

hiredman22:07:30

I would double check if some-sync-setup-fn is synchronous or not

B Treebeard22:07:36

More concretely, I'm using React Testing Library in my test. So some-sync-setup-fn involves an RTL render() call, and some-js-async-fn involves user-event calls (which return promises). The user-event functions all come pre-wrapped with React act(), so render() should definitely behave synchronous.

hiredman22:07:32

I am not familiar with all that, but I suspect what you are seeing is a timing difference

B Treebeard22:07:58

@U0NCTKEV8 Thanks for your response. I was just typing out some follow-up info. If some-sync-setup-fn is not synchronous, why would the test always pass when inside the go block?

hiredman22:07:08

yeah, it must be an event loop thing

hiredman22:07:28

for the outside the go block case: 1. some-sync-setup-fn queues on something to run on the event loop

hiredman22:07:32

2. the go block runs, then some-js-async-fn runs, then the rest of the go block is queued up to run

hiredman22:07:55

3. then whatever some-sync-setup-fn queued runs

hiredman22:07:03

4. then the rest of the go block

hiredman22:07:22

hmmm, seems like the same order of stuff running in both cases

B Treebeard22:07:45

Yeah, exactly where I landed up. :thinking_face:

hiredman22:07:16

try scheduling the go block to run 1 second later

hiredman22:07:43

with the "sync" setup function outside the block

B Treebeard22:07:16

Yeah, I just tried this, and still fails:

(deftest some-test
  (async done
         (some-sync-setup-fn)
         (go
           (timeout 1000)
           (<p! (some-js-async-fn))
           (some-assertion)
           (done))))

hiredman22:07:36

timeout like that doesn't do anything

B Treebeard22:07:43

Might be doing this wrong though. I'm not a CLJS expert.

hiredman22:07:48

you have to <! on the channel returned by timeout

B Treebeard22:07:56

Yup, makes sense.

B Treebeard22:07:04

And that indeed makes the test pass. Might have jumped the gun on this, not sure yet if it always passes.

hiredman22:07:35

try with a timeout of 0 or 1

B Treebeard22:07:14

Right, with a timeout >300 or so, it appears to always pass. Less than that, and it fails.

B Treebeard22:07:08

It's late here - I'm going to sleep on this and try and figure it out tomorrow. 😅

B Treebeard22:07:31

Really appreciate the pointers, @U0NCTKEV8. Thanks much!

B Treebeard16:07:55

[Deleted my query as the issue was caused not by CLJS async, but with a JS library I was using.]