Fork me on GitHub

To test my app's routes, I'm using the reitit frontend, push-state function like so:

(rfe/push-state :home)
And my routes are:
(def router
   [["/" {:name        :home
          :view        #'home
          :controllers [{:start (fn [_] (rf/dispatch [:page/init-home]))}]}]
But I get the error:
No protocol method Router.match-by-name defined for type null: 
Why is that and what am I doing wrong?

Raziyeh Mohajer06:04:51

Hello everyone, I have a backend app with Clojure and a frontend app with re-frame. And from my front, I want to request my backend for an excel file. I use http-xhrio for sending requests. The request Accept should be application/octet-stream but I didn't find any suitable response-format in ajax.core. Is there a good way of receiving files in re-frame?

Doni Rubiagatra07:04:56

hello raziyeh you can use this kind of response format

Doni Rubiagatra07:04:12

:response-format {:content-type "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                                    :description "excel"
                                    :read protocol/-body
                                    :type :arraybuffer}

Doni Rubiagatra07:04:55

and on success you can create dialog window for download

Doni Rubiagatra07:04:41

but don't forget make it blob first

Raziyeh Mohajer07:04:14

Thanks Doni Rubiagatra, what is protocol/-body ? and from what namespace I should require it?

Doni Rubiagatra07:04:15

yes you should require it

Doni Rubiagatra07:04:17

[ajax.protocols :as protocol]

Raziyeh Mohajer07:04:50

And I should implement the protocol record myself or Is there an implementation for it?

Doni Rubiagatra07:04:36

no just call it by protocol/-body

Raziyeh Mohajer07:04:30

by making it blob, you mean on-success of event handler I should change it?

Doni Rubiagatra07:04:28

maybe this will get you the idea

Raziyeh Mohajer07:04:06

Aha Thank you very much 🙂

Doni Rubiagatra07:04:01

you are welcome 🙂


So I believe is broken with the :bundle target. It expects to be able to use the :output-to file, but that file lacks a webpack build step. What would be a proper solution, except waiting for a new release of the runner? Have webpack do some renaming trickery to get the right file at the right spot?


@ingesol I would say this is just fundamentally a bug


well sorry not a bug


but a very important missing feature


not being able to choose the file that the test runner should use


seems like a very simple thing to fix though


I wouldn't hack around it myself


git deps make it easy to "fork and continue"

👍 1

while you wait for the PR to get merged


anyone have experience setting up testing of a CLJS lib w/ github actions? example repos appreciated


if your tests run in node then its easy


if you need a browser then no clue 😛


thanks, this helps


I think they should run in in Node.js


I have tests in both CLJ and CLJS, I'm not sure if that complicates things further


How do I make sure that all the functions in a test are run sequentially?

(deftest mytest
These functions cause side effects so I want them to run sequentially, but how do I do that? I tried go block as follows:
(deftest mytest
    (let [f1- (<p! (f1))
          f2- (<p! (f2))
        (prn "done")
But this doesn't seem to work because done isn't printed on running the test. Also, (f1) returns nil so I'm not sure I can even use <p! in that case. How do I run these functions sequentially?


f1 will have to return a promise which will mean all of the stuff it started has finished - even if you don't care about it's value in the test.


does that mean for all f1, f2 ... I have to wrap them with (.Promise)? Is there an elegant way to do this in bulk for each function in the sequence? I am using the re-frame test library though that doesn't really seem to handle checking using f2 if a component has been mounted using f1.


Basically what I'm trying to mount a component using f1 and then checking whether it was mounted using f2, using the react-testing-library and getByText method.


I don't know if there's anything more elegant. The testing lib surely has examples in js


The Async waitFor in the library seems broken.


.then(f2) after. fyi I wrote a helper around the Clojurescript async testing to deal with timeout and exception


Is there a genuine equivalent to alter-var-root? set!is often mentioned but it works on a var symbol, not a var


no, CLJS doesn’t actually use vars. you can get a Var type but changing it at runtime does not actually effect the global environment, it’s used just to get some compile-time metadata


@lilactown My CLJ code accepts a Var and adds metadata to the root (knowing it is always an IMeta). I am not quite sure how to do it from CLJS, if that is possible because of advanced compilation


not possible in CLJS


var stuff in Clojure is not portable


Thanks! Unfortunately the more I dive into CLJS, the more I hear "not possible". Maybe the stuff I do is too esoteric...


what are you trying to do? there might be a way to split the difference with some compile-time macros and runtime code


Yes I can solve my problem using a macro but then I would need to define my own defnand I find it always ugly to do so, whereas my current CLJ solution is barely a few lines and just works


there are people here who would listen to your high-level problem and might be able to guide you toward a better solution 🙂


just inferring here, it sounds like you’re doing something like:

(defn foo ,,,)

(set-some-meta! foo)
you might be able to do something similar by having set-some-meta! operate at macrotime. then you can pull out this info using another macro like:
(get-some-meta foo)
or at runtime like (meta #'foo)


I am gearing towards something like this indeed. But no need for a macro for pulling out, is there?


depends, constructing a var has a runtime cost - it’s faster to find the specific meta on the symbol at macrotime and emit it


either way, the name of the “var” that you’re trying to get the meta from must be statically knowable

👍 1

@dnolen Sounds reasonable, should be easy enough to work around this by patching the lib.


@adam678 it's not that what you're doing is esoteric


it's that you're doing things that ClojureScript intentionally hasn't supported since day one


none of the runtime var metaprogramming stuff in Clojure works - if you want to write portable stuff - you have to do it a different way


Whats the best approach to test ClojureScript view functions in a web app. I tried looking online but couldnt find any good resources.


Checkout figwheel cards and #workspaces


("figwheel cards" are probably devcards)

👍 1

I am going to try playing wth devcards


thank you guys!


some of the var meta programming things can be accomplished by other means


cljs.test and cljs.spec.alpha demonstrate that non-trivial things can be done with reasonably similar APIs


without any var meta programming at all


or extremely restricted variant of it


@vishal.gautam This one is specific to re-frame, but pretty good in general


Yeah I went through that article. It talks about testing subscription layers and event handler functions. But talks very little about testing view functions


@dnolen Fair enough, thanks, one simply has to be more creative!


I have enjoyed using react-testing-library if you’re using a react wrapper (e.g. reagent)


not really, but it’s fairly straight forward using JS interop


(@dnolen Thanks for everything you've done for CLJS by the way, I don't mean to sound like I'm complaining about it 😉 )


@adam678 didn't take it that way, just wanted to clarify. The var thing is intentional because of advanced compilation & there's nothing wrong w/ var-meta programming in Clojure. Just that if you're going to port that stuff you must do something quite different for ClojureScript.


I do generally think twice about var meta-programming if I'm doing library work that's meant to portable


it's considerably easier to do in Clojure - where in ClojureScript it's significantly more challenging to come up with solutions that don't create more problems

👍 1
Michael J Dorian22:04:02

Apologies for the weird premise, but I have a collection of things that I can't count. I can only run a variant of (map) on them, and I need to know how many there are. I would normally use agents or refs to update a reference each time the function in map runs, and then await it (in the case of agents). I have the code written right not with an atom, basically just treating the atom like an agent, and it works. As far as I can tell, the updates all get applied before I deref the atom 100% of the time, but it makes me nervous none the less. Is there any sort of drop in replacement I can use for synchronous state?


does the variant of map allow a callback at the end of the input?


if so, you could thread a promise or a chan write


also consider that the js env is only opt-in concurrent, so if your function doing the "variant of map" doesn't opt in, it won't be interrupted

Michael J Dorian22:04:59

It doesn't have callback support. I'm pretty sure the map (rewrite-clj's map-vals) doesn't do anything concurrent so if I could depend on it to work, maybe that's the best bet. I could even write a variant of the function for non-js that uses agents


can you make a seq out of the collection with a special sigil at the end to signal that you are done?


I checked the context - it's a zipper not a collection


but zippers are immutable, so you can safely extract the node you are at and do normal collection ops on it


of course you could also make assumptions about the zipper implementation (clojure zipper uses immutable data structures) but it's safer to inflate it first

Michael J Dorian22:04:22

I don't know how to collect them, though. The only rewrite-clj function that differentiates between map values and other nodes is this map one

Michael J Dorian22:04:02

Not coworkers @U11BV7MTK simple_smile I'm on a side project


ah ok. seemed like some shared context i was missing 🙂


I went and looked at what rewrite-clj was doing, it's using a zipper, these are defined by clojure.core


sometimes I get very curious

Michael J Dorian22:04:10

Hahaha, well my problem was weird, too. I wouldn't have been able to come up with such a good reason to not be able to count something if I tried


you can just call (count (zip/node x)) if they are using zippers that are compatible with


worth a try at least :D

Michael J Dorian22:04:08

It runs! So it's a real zipper, I would just need a way to filter out all the nodes based on their type. I wish there was a (z/map-val? ) function


(comp map? z/node) :D


z/node is relatively cheap, especially if you are further down the tree


zippers are on my "need a week off work, five gallons of caffeine, and a quiet space" list

Michael J Dorian22:04:00

ah, when I say map value I mean {:not-this "only this"}, map? is how I got here

Michael J Dorian22:04:33

LOL, maybe I should look into them more, I thought I was dealing with something specific to this lib


oh - map-val? would likely be something like #(and (map-entry? (z/node (z/up %))) ...)


where the second clause of and also checks that you are on the right-side of the parent rather than the left (don't know that one off the top of my head)

Michael J Dorian22:04:59

That's the trick though, because now I'm counting forms and throwing out comments and whitespace

Michael J Dorian22:04:29

Which may be the best answer 🤷 I just wanted an agent!

Michael J Dorian22:04:51

Thank you so much! I'm going to commit the reader conditional version where I can at least be confident that atoms are only used in a single threaded environment, and then read those!


So I have a promise in a test like so:

(deftest login-test
   (testing "login test"
     (async done
              (let [_ (<p! (js/Promise. (see/landing!)))
                (prn "done")
And running this test just hangs. What do you think is causing this?


Oh yeah, I'm also getting this error on evaluating just the js/Promise part, but have no clue what it means:

TypeError: Promise resolver #<cmp> is not a function
TypeError: Promise resolver #<cmp> is not a function
    at new Promise (<anonymous>)
    at eval (eval at shadow$cljs$devtools$client$browser$global_eval (), <anonymous>:1:2)
    at eval (<anonymous>)
    at Object.shadow$cljs$devtools$client$browser$global_eval [as global_eval] ()
    at eval ()
    at Object.shadow$cljs$devtools$client$env$repl_call [as repl_call] ()
    at Object.shadow$cljs$devtools$client$browser$repl_invoke [as repl_invoke] ()
    at shadow$cljs$devtools$client$browser$handle_message ()
    at eval ()
    at Object.shadow$cljs$devtools$client$env$process_next_BANG_ [as process_next_BANG_] ()


@pshar10 js/Promise. will accept a function which accepts two other functions to be called for resolve/reject cases. is that what (see/landing!) returning?


that function is supposed to and returns nil


oof, what are you trying to do?


I'm trying to mount a component with (see/landing!) on the dom. And after that check whether it was mounted


(deftest-sync login-test ( (testing "login test" (async done (go (let [_ (<p! (js/Promise. (see/landing!))) click-login-btn (<p! (js/Promise. (interact/click-login-btn)) ) ] (prn "done") ) (done) ) ) ) ) )


so you want to wait for the see/landing! to finish doing its thing?


not check but click a button on the mounted component


I would think in that case, see/landing! would need to indicate that somehow (that its done), either by returning a async/chan or a Promise.


also evaluating the promise part gives me this:

TypeError: Promise resolver #<cmp> is not a function
    at new Promise (<anonymous>)
    at eval (eval at shadow$cljs$devtools$client$browser$global_eval (), <anonymous>:1:118)
    at eval (eval at shadow$cljs$devtools$client$browser$global_eval (), <anonymous>:7:3)
    at eval (<anonymous>)
    at Object.shadow$cljs$devtools$client$browser$global_eval [as global_eval] ()
    at eval ()
    at Object.shadow$cljs$devtools$client$env$repl_call [as repl_call] ()
    at Object.shadow$cljs$devtools$client$browser$repl_invoke [as repl_invoke] ()
    at shadow$cljs$devtools$client$browser$handle_message ()
    at eval ()


that was my intention of returning a promise by wrapping it with (js/Promise.)


yeah because you're passing in nil where its expecting the executor function


maybe forget what I have here. From scratch, how would you approach this problem?


(js/Promise. (fn [resolve reject] (somehow-wait-for (see/landing!)) (resolve)))


this is how the react-testing-library does it: But it uses jest, which I can't install


depending on what see/landing! is doing, it might vary


what is some-how-wait-for?


and reject and resolve are specious here.


some kind of wait mechanism


see landing is


(defn landing! [] (start-router!) (ajax/load-interceptors!) (mount-components)) )


are these all "sync" calls?


Let's assume they are.


you can also directly wrap with Promise.resolve


but if they are sync why are you wrapping them in a promise, sorry I am trying to understand the problem


Here's the problem. I'm testing user interaction, and I first mount the component on the screen using see/landing!, and then make the user click a button on that component, using interact/click-login-btn


so they must run sequentially.


How do I do that?


just directly call (see/landing!) since its sync, when the call returns things are in place


promise/async are to wait for async things, since your stuff is sync, just call one after the other


wrap it in async or not?


you wouldn't need to I would think.


then it's async, because it didn't work that way


then (see/landing!) needs to somehow indicate when its done (by returning a promise) .. or you if want to wait for things to settle try (<! (async/timeout 10000)) ..


terrible advice though, I would suggest modeling see/landing! differently to allow for proper async initialization


what's a different way to model it? Maybe using the built-in render function from react-testing-library?


(defn landing! []
     (<! (start-router!))
     (<! (ajax/load-interceptors!))
     (<! (mount-components))))


I am not aware of implementation details, but async call other async sort of


in that case, you can use the chan landing returns (go returns a channel)


To be more concrete, go returns a channel, the channel provides the value of the last statement in the block, when that statement returns. You can make your own go that uses that channel, and does other things after reading, or use take! and put your code into the optional callback arg that isn't called until the channel provides a value


would you please give an example @noisesmith?


(let [c (see/landing!)] (take! c (fn [] (my-code-goes-here))))


see/landing! returns nil though


not a channel


or (go (<! (see/landing)) (my-code-goes-here))


then the code that verma shared above isn't the code for landing


if so, I apologize for the confusion


oh! - I misread, @verma was suggesting an implementation, not sharing what it was facepalm


@pshar10 anyway, there's no simple solution to this stuff in js, people use async to deal with the vm only having one thread, but async introduces complexity and thus bugs


learning to use promises and/or core.async makes things harder at the start but will be better in the long term


I'm having quite some trouble following the ClojureScript webpack guide somehow. Would anyone know why ClojureScript would appear to emit this in 'main.js', when set to emit with REPL?

var CLOSURE_UNCOMPILED_DEFINES = {"clojure.browser.repl.PORT":9000,"cljs.core._STAR_target_STAR_":"bundle","clojure.browser.repl.HOST":"localhost","goog.json.USE_NATIVE_JSON":true};
var CLOSURE_NO_DEPS = true;
document.write('<script src="out/goog/base.js"></script>');
document.write('<script src="out/goog/deps.js"></script>');
document.write('<script src="out/brepl_deps.js"></script>');
note the line /cljs_deps.js"></script>'); which is invalid When I ignored this error and just built a basic core.cljs using Helix, I ran into a separate issue, which I also had trouble diagnosing: My config is also present in this latter gist.


hey tekacs. I'm guessing that the master branch of helix won't work with the webpack guide


there's another branch, called fix-figwheel, that might work better for you


it doesn't seem directly related to the issue you're dealing with now, but once you get past it, try the fix-figwheel branch using git deps


@tekacs seems very strange, did you try to erase your :output-dir and start fresh?


trying now


same result 😞


let me bundle this up and push it


k can't take a look right now, but maybe someone else can check it out - if it seems reproducible then open an issue and of course I'll look into it


of course -- I'll put it up where folks can take a look and keep trying to debug myself


thanks for chiming in


@tekacs I will say what you're seeing seems almost impossible


make sure you don't have multiple compiler process running accidentally


like a forgotten one in a different terminal


checking out on another computer


it's here: I'll pull it on another machine and test


nope -- I checked it out on a completely different computer from scratch using the repo above and saw the same result... 😓


I even used curl to pull /out/main.js to be sure that my browser wasn't causing the issue


so it should be possible to reproduce by checking out the above repo and running: $ yarn && yarn start to start the watcher and $ curl to see the broken output I can poke around to see if I can reduce the example further, but there's really not much happening in that repo.