This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-29
Channels
- # announcements (35)
- # aws (40)
- # babashka (10)
- # beginners (119)
- # calva (25)
- # cider (13)
- # clj-kondo (15)
- # cljsrn (23)
- # clojure (205)
- # clojure-dev (3)
- # clojure-europe (15)
- # clojure-germany (3)
- # clojure-italy (3)
- # clojure-nl (2)
- # clojure-uk (58)
- # clojurescript (193)
- # community-development (2)
- # conjure (147)
- # core-async (49)
- # cursive (47)
- # datomic (27)
- # duct (1)
- # fulcro (19)
- # graalvm (3)
- # graphql (1)
- # helix (3)
- # hoplon (11)
- # jackdaw (1)
- # joker (1)
- # juxt (5)
- # kaocha (1)
- # keechma (3)
- # lambdaisland (6)
- # local-first-clojure (27)
- # malli (5)
- # off-topic (41)
- # rdf (27)
- # re-frame (7)
- # reagent (15)
- # reitit (5)
- # rum (11)
- # shadow-cljs (157)
- # spacemacs (18)
- # sql (4)
- # xtdb (8)
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
(reitit/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?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?
hello raziyeh you can use this kind of response format
:response-format {:content-type "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
:description "excel"
:read protocol/-body
:type :arraybuffer}
and on success you can create dialog window for download
but don't forget make it blob first
Thanks Doni Rubiagatra, what is protocol/-body ? and from what namespace I should require it?
yes you should require it
[ajax.protocols :as protocol]
And I should implement the protocol record myself or Is there an implementation for it?
no just call it by protocol/-body
by making it blob, you mean on-success of event handler I should change it?
maybe this will get you the idea
Aha Thank you very much 🙂
you are welcome 🙂
So I believe https://github.com/Olical/cljs-test-runner 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?
anyone have experience setting up testing of a CLJS lib w/ github actions? example repos appreciated
https://github.com/filipesilva/create-cljs-app/blob/master/.github/workflows/nodejs.yml
How do I make sure that all the functions in a test are run sequentially?
(deftest mytest
(f1)
(f2)
)
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
(go
(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
.then(f2)
after.
fyi I wrote a helper around the Clojurescript async testing to deal with timeout and exception http://widdindustries.com/cljs-async-tests/
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
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 defn
and 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
@dnolen Sounds reasonable, should be easy enough to work around this by patching the lib.
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.
I am going to try playing wth devcards
thank you guys!
cljs.test
and cljs.spec.alpha
demonstrate that non-trivial things can be done with reasonably similar APIs
@vishal.gautam This one is specific to re-frame, but pretty good in general https://github.com/day8/re-frame/blob/master/docs/Testing.md
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)
@lilactown do you have a sample code I can reference at
react-testing-library has a render
function that you pass a React element to. so something like:
(rtl/render (reagent.core/as-element [:div {:data-testid "my-div"} "Hello, world!"]))
the render
function returns a result object with a bunch of methods, that you call to test your view:
(deftest my-div-renders
(let [result (rtl/render ,,,)]
(cljs.test/is (.getByTestId result "my-div"))))
Alright, thank you, I will take a look
Made it work using karma and react-testing-library
thank you
(@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
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
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
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
Not coworkers @U11BV7MTK I'm on a side project
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
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 clojure.zip
worth a try at least :D
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
ah, when I say map value I mean {:not-this "only this"}, map? is how I got here
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)
That's the trick though, because now I'm counting forms and throwing out comments and whitespace
Which may be the best answer 🤷 I just wanted an agent!
this might help http://josf.info/blog/2014/03/21/getting-acquainted-with-clojure-zippers/
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!
Re: zippers, this is also a very good resource https://lambdaisland.com/blog/2018-11-26-art-tree-shaping-clojure-zip
So I have a promise in a test like so:
(deftest login-test
(day8.re-frame.test/run-test-async
(testing "login test"
(async done
(go
(let [_ (<p! (js/Promise. (see/landing!)))
]
(prn "done")
)
)
(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?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
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
(day8.re-frame.test/run-test-async
(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)
)
)
)
)
)
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 ()
this is how the react-testing-library does it: https://testing-library.com/docs/react-testing-library/example-intro. But it uses jest, which I can't install
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
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
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! []
(go
(<! (start-router!))
(<! (ajax/load-interceptors!))
(<! (mount-components))))
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))))
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
@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>');
/cljs_deps.js"></script>');
document.write('<script src="out/brepl_deps.js"></script>');
document.write('<script>goog.require("clojure.browser.repl.preload");</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:
https://gist.github.com/tekacs/a46476615782a45f29005d15bc0f27b7
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
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
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
it's here: https://github.com/tekacs/cljs-issue-reproduction-1 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... 😓