Fork me on GitHub
#clojurescript
<
2020-04-25
>
didibus02:04:06

So, when and why do you sometimes need to use strings for require?

lilactown02:04:50

generally if they have characters that aren't valid symbol

didibus03:04:51

Ok, that's what I thought

lilactown02:04:22

e.g. scoped npm packages are of the form @corp/my-lib

didibus03:04:03

I noticed it isn't documented it seems

didibus03:04:57

Neither on the namespace guide, or on the doc-string of require and ns

Spaceman04:04:48

Does anyone use a testing library for testing react components? Which one do you use and why?

lilactown04:04:02

I like react-testing-library

4
Spaceman04:04:46

is there a way to find the exact line number where an error occured in my cljs file? My stack trace doesn't show the line so it's harder to debug:

Error mounting card {ns: myapp.workspaces.cards-test", name: "cart-not-shown-initially-test", str: "myapp.workspaces.cards-test/cart-not-shown-initially-test", _hash: 69565119, _meta: null, …}cljs$lang$protocol_mask$partition0$: 2154168321cljs$lang$protocol_mask$partition1$: 4096name: "cart-not-shown-initially-test"ns: "myapp.workspaces.cards-test"str: "vendo.workspaces.cards-test/cart-not-shown-initially-test"_hash: 69565119_meta: null__proto__: Objectapply: ƒ (self__,args66157)call: ƒ (unused__32982__auto__)cljs$core$IComparable$: {}cljs$core$IComparable$_compare$arity$2: ƒ (x,y)cljs$core$IEquiv$_equiv$arity$2: ƒ (_,other)cljs$core$IFn$_invoke$arity$1: ƒ (coll)cljs$core$IFn$_invoke$arity$2: ƒ (coll,not_found)cljs$core$IHash$_hash$arity$1: ƒ (sym)cljs$core$IMeta$_meta$arity$1: ƒ (_)cljs$core$INamed$_name$arity$1: ƒ (_)cljs$core$INamed$_namespace$arity$1: ƒ (_)cljs$core$IPrintWithWriter$_pr_writer$arity$3: ƒ (o,writer,_)cljs$core$IWithMeta$_with_meta$arity$2: ƒ (_,new_meta)cljs$spec$alpha$Specize$: {}cljs$spec$alpha$Specize$specize_STAR_$arity$1: ƒ (s)cljs$spec$alpha$Specize$specize_STAR_$arity$2: ƒ (s,_)equiv: ƒ (other)garden$selectors$ICSSSelector$: {}garden$selectors$ICSSSelector$css_selector$arity$1: ƒ (this$)toString: ƒ ()constructor: ƒ (ns,name,str,_hash,_meta)__proto__: Object TypeError: Cannot read property 'cljs$core$IFn$_invoke$arity$1' of null
    at Object.nubank$workspaces$ui$render_card [as render_card] (ui.cljs:71)
    at nubank$workspaces$ui$WorkspaceSoloCard.eval [as componentDidMount] (ui.cljs:226)
    at commitAllLifeCycles (react-dom.development.js:17335)
    at HTMLUnknownElement.callCallback (react-dom.development.js:150)
    at Object.invokeGuardedCallbackImpl (react-dom.development.js:200)
    at invokeGuardedCallback (react-dom.development.js:257)
    at commitRoot (react-dom.development.js:18949)
    at eval (react-dom.development.js:20419)
    at Object.exports.unstable_runWithPriority (scheduler.development.js:256)
    at completeRoot (react-dom.development.js:20418)

Spaceman04:04:10

@lilactown I mount the component like so, using react-testing-library

(defn mount-cart-component! []
  (render ([:div {:id "cart"}]))
  )

(deftest my-test
    (mount-cart-component!)
    ;; ...
)
But I get the error repl/invoke error Error: Invalid arity: 0. Why would this be?

Oliver George05:04:24

This looks broken also unless render is a macro. It calls a vector as a function. Pretty sure you’re calling (render nil).

johanatan06:04:28

Yep, that’s what it looks like to me as well. Extra set of parens around the :div

Spaceman05:04:28

When I do it this way, the error disappears:

(defn mount-cart-component! []
  (render (:div {:id "cart"} "Cart"))
  )
But afterward doing
(.getByText screen "Cart")
I get
TestingLibraryElementError: Unable to find an element with the text: Cart.
which means render doesn't load the component to the dom. It's most likely because I'm using #workspaces? How would I mount it in workspaces then?

Oliver George05:04:00

That code is quite broken. The :div is being called as a function. It will pick the :div key out of your property map but since it’s not set it returns the second argument. So you’re calling (render “Cart”).

johanatan06:04:11

Yes you want square brackets around the :div, not parens.

Spaceman06:04:38

Using square brackets gives:

repl/invoke error Invariant Violation: Objects are not valid as a React child (found: object with keys {ns, name, fqn, _hash, cljs$lang$protocol_mask$partition0$, cljs$lang$protocol_mask$partition1$}). If you meant to render a collection of children, use an array instead.

Oliver George06:04:03

Ah. Sounds like you need (r/as-element ...)

Oliver George06:04:29

Reagent can wrap hiccup to act like a native react component

Spaceman06:04:32

That got rid of the error, but the component didn't mount on the dom though

Spaceman06:04:55

@lilactown, did you set up react-testing-library with jest? How do you automate testing in clojurescript when using jest+react-testing-library?>

johanatan05:04:22

Does anyone know if the new webpack support would offer anything over / be worth switching to from: deps.edn, figwheel-main w/ an existing webpack serving as input to the CLJS build?

💡 4
johanatan05:04:38

Looks like maybe it would just save having to manually type the :global-exports

johanatan05:04:42

Is that right?

Oliver George06:04:51

As you say fairly similar to preparing npm deps as a webpack and then consuming them.

Oliver George06:04:58

But it gives you js tooling reach too. I think you can get things like storybook to consume your views. (Untested)

Oliver George06:04:27

Others might have more compelling examples

johanatan07:04:04

@olivergeorge wouldn’t that “js tooling reach” be counteracted by a “cljs tooling shrinkage”? Or would it really be a “best of both worlds” scenario?

Oliver George07:04:45

I’m hoping it’s a “cherry pick the best” type scenario!

Spaceman09:04:47

does anyone know how to use the react-testing-library in clojurescript?

Spaceman09:04:34

my render function from this library doesn't load the rendered component on the dom.

Spaceman10:04:26

thanks. it works.

👍 4
Oliver George10:04:49

It’s a handy trick

schaueho13:04:42

I wanted to use testing-library/react too, but in the context of figwheel-main, not shadow-cljs. Alas, I can't figure out how to include it in the dependencies and would need some pointers and what to look at.

Oliver George10:04:19

I searched github for Clojure code including “testing library cljs react”

Oliver George10:04:32

There might be better examples out there.

dnolen11:04:00

@johanatan the problem w/ the old way is that it was "backwards" so it created more configuration - to be honest it wasn't really that hard but it was a stumbling block. In the new way where you pass on to a JS build tool you don't need to bother with configuration at all. So fewer opportunities for user error

👍 4
tatut11:04:38

been trying out the latest cljs with npm stuff, good stuff... wondering how the tree shaking works, if I require a bunch of node modules in my ns, but the functions that use them are ultimately unused, will they be left out of advanced build?

dnolen11:04:48

@johanatan re "tool-shrinking", there's actually not that many build tools in the ClojureScript system - nothing like JS. Part of the problem is that some fundamental things need to be solved in ClojureScript first like externs inference. There are exceptions like shadow-cljs because it reimplemented stuff or fixed stuff out of tree - but that's not helping anything but shadow-cljs.

👍 8
dnolen11:04:04

@tatut hopefully the initial docs were pretty clear on this, if you're passing onto bundler none of the node_modules stuff is going through Closure

dnolen11:04:39

it's trivial to take a bundle target project and convert it to pass everything through Closure but not useful because it's not going generate stuff that will work.

dnolen11:04:33

note not working has nothing to do w/ Closure or ClojureScript

dnolen11:04:45

the JavaScript stuff simply isn't compatible

dnolen11:04:57

(with advanced compilation)

tatut11:04:05

(ns foo (:require ["some/npm/Stuff" :as bar])) (defn baz [] (bar/dothing)))
so if baz in the above is never called by my other cljs code and no other code touches bar, will the npm library be included in advanced build?

lilactown17:04:37

the npm lib will be included in your JS bundle unless you use the JS tooling (webpack/rollup/whatever) to remove it

lilactown17:04:10

cljs/gcc won't do any DCE or module splitting of external JS code that's loaded using the new method of :bundle target + JS tooling

dnolen11:04:28

I'd just be repeating myself

tatut11:04:45

ok, I'll try it.. still don't understand fully, sorry

dnolen11:04:55

nothing that you use from node_modules will ever be looked at by Closure

dnolen11:04:52

Closure doesn't know what you're calling, it will never see the thing called, so it can't possibly eliminate it

dnolen11:04:21

we could handle the trivial case you demonstrated but it's really meaningless

dnolen11:04:28

that's not how Closure DCE works

dnolen11:04:40

it looks at everything

dnolen11:04:03

(as long as it's something you've inputted to the compiler, not true for node_modules and the bundle target)

tatut11:04:50

ok, thanks for explaining

tatut11:04:31

if I understand correctly, there's possible implications for cljs library authors that rely on npm stuff on how to structure into namespaces

hindol13:04:53

The guide https://clojurescript.org/guides/webpack does not work under Windows (PowerShell). I get this,

;; clj -m cljs.main -co build.edn -O advanced -v -c -s
Applying optimizations :advanced to 42 sources
Execution error (InvalidPathException) at sun.nio.fs.WindowsPathParser/normalize (WindowsPathParser.java:182).
Illegal char <:> at index 2: /C:/Users/hiadhy/Code/<snipped>

hindol14:04:53

Dropping -O advanced makes it work.

hindol14:04:33

And looks like the error is from within Closure compiler.

dazld14:04:04

@dnolen if you're around, we spoke the other day about inference warnings and protocols - I've tried yesterday's release of CLJS and still unfortunately getting some warnings - is there something missing in the repro case on https://github.com/dazld/cljs-protocol-inference-warning ...?

dazld14:04:38

updated it to use 741 and the readme with the warnings received.

dazld14:04:03

looks like the inference warnings around defrecord etc are gone, but the protocol itself still triggers them

dnolen15:04:07

looking into, will minimize a bit more and open a issue

👍 4
Helins14:04:14

Hi! I understand that CLJS's resolvetakes only a static symbol because of advanced compilation. However, I need to resolve a symbol dynamically but at compile time, I cannot manage to find how to do that

dazld14:04:16

CLJS doesn't support it, sadly

dazld14:04:27

had this problem too 😉

dnolen14:04:29

@adam678 it's not possible

Helins14:04:20

Even though it would happen at compile time? I don't believe it would result in anything bad, at least not for my use case

phronmophobic18:04:19

is there a reason cljs.analyzer/resolve-var isn’t appropriate for resolving a symbol dynamically at compile time?

Space Guy14:04:57

https://ask.clojure.org/index.php/8976/offer-resolving-facility-friendlier-towards-macro-authors The ones here eg cljs.analyzer/resolve-var give you the known information about a symbol, which can be dynamic at compile time It just can't be dynamic at runtime

Frederik14:04:12

Hi, beginners question, but can't seem to find a straightforward solution for it: I'm using cljs-http to send a request to an api, but don't understand how to get the returned value out of the async channel. Within a go block, I can call <! and do things with the resulting response inside the go block, but I'd like to have my function return the response, rather than being forced to use it inside this go block. How do I get the go block to return the response, rather than the channel itself? I assume I'm tackling this from the wrong angle?

dazld14:04:45

there isn't a blocking version of <! in cljs - you have to use it in an async way, iirc

dazld14:04:54

would a promise be ok?

Frederik15:04:38

No experiences with promises yet (or async in general), but you're suggesting to deliver it to a promise inside the go block and deref the value when I need it?

dazld16:04:46

think that's not going to be a great idea, as derefing the atom (or whatever) wouldn't give you any guarantee that the value you requested is the one that came from that particular API call

dazld16:04:30

you could try something like..

dazld16:04:53

(defn some-api-call [path]
      (-> (js/fetch (str "" path))
          (.then (fn [r]
                     (if (.-ok r)
                       (.json r)
                       {:status (.-status r)})))))

(-> (some-api "uuid")
    (.then (fn [response]
               (js/console.log response))))

dazld16:04:48

fetch won't work in node (iirc) - it's a browser API

dazld16:04:31

you could throw an exception if the response isn't ok - that's up to you to handle as you wish.

Frederik16:04:17

Thanks for the help! Had to look into (.then ) and javascript interopt. Never done any of this. If I understand it well (probably not ...), this way I'm still tied to only being able to use my api respone within a certain "code block", here within the (.then (fn [response] ...) call. Is there no way to create a function that calls an api, waits for the result and returns the response body so it can be used somewhere else in the code? Disclaimer: Never done any frontend dev, so maybe this is a dumb idea.

dazld17:04:45

It’s a perfectly reasonable thing to want! It’s just not how good js is written. Back in the good old days, there was a synchronous xhr call which would do what you want, but as it blocks the main thread, this isn’t really what you want in 2020.. or even in 2010.

dazld17:04:36

There’s async await in recent js which let’s you write code that looks sync, but it’s still just sugar over promises.

dazld17:04:49

It’s a consequence of how js works - it’s single threaded backed by a thread pool that handles io in the background, hence all the fun with callbacks

dazld17:04:36

So, writing anything that is async means you have to yield to the event loop if you don’t want to block, which you don’t.

dazld17:04:19

Promises are arguably a good way of dealing with this, but it does mean that all your code that extracts a value from a promise has to be chained somehow. It’s a different paradigm.

dazld17:04:28

As an aside, promises are monadic in this sense, in that values have to be extracted from the wrapper, but that gives you nice properties for error handling and composition. They’re idiomatic and worth learning in js and cljs.

Frederik18:04:17

Ok, thanks for all the background info! I got "dragged" into this, because I wanted a small interactive webpage for a first clojure project I've been working on. So trying to cobble this together with no cljs or js experience and only a bit of clj skills, I bump into a bit more unexpected blocks then I expected.:) In the end, I stuck to using cljs-http. I pass in my reagent atom into the function that does the api call and update the atom inside the go block with the result of <! . Not sure if that is a good solution, but it seems to work at moment.

dazld18:04:52

that works too 🙂

dazld18:04:07

doing reset! or so in the go block?

Frederik18:04:30

Exactly!

👍 4
dnolen15:04:22

@adam678 it's not about good or bad, it's actually not possible

dnolen15:04:38

because of advanced compilation

Spaceman15:04:38

does anyone use use-fixtures for testing in clojurescript? How do you get it to work?

aisamu15:04:24

It did work as advertised!

Spaceman15:04:30

This is my test file:

(use-fixtures :each {:before (fn []

   (prn "using fixtures")
                               )})

(deftest use-fixtures?
  (is (= 1 1))
  )
And while the test passes, I don't see the prn

Spaceman15:04:26

@U1UQEM078 can you share an example that worked as advertised for you?

👍 4
aisamu16:04:27

From a cljs codebase (simplified):

(use-fixtures :once (fn [f]
                      (with-redefs [something identity]
                        (f))))

Spaceman17:04:11

Would you please elaborate? How do I use this with a function, say (fn [] (prn "using fixtures))?

aisamu17:04:25

The (sync) fixture takes the test/tests as an argument (`f`):

(use-fixtures :once (fn [f]
                      (print "hi")
                      (f)))

aisamu17:04:25

Have you tried using js/console.log instead of prn? Your test runner might not be invoking enable-console-print!

Spaceman17:04:50

I know now why I wasn't seeing a console print. I'm running the tests through #workspaces, rather than using (run-tests). Only when using the latter, the prints work, but I would like use-fixtures to work with #workspaces too. #workspaces uses its own deftest macro

Spaceman17:04:55

(defmacro deftest
  "Creates a test card, you can replace your cljs.test/deftest call by this, will
  work the same, but also define a card (the original cljs.test/deftest will also be
  called)."
  [sym & forms]
  (let [fqsym  (if (namespace sym)
                 sym
                 (symbol (name (ns-name *ns*)) (name sym)))
        forms' (mapv (fn [exp] `(fn [] ~exp)) forms)
        card-form &form]
    `(do
       (init-test '~fqsym ~forms' '~card-form)
       (if-cljs
         (cljs.test/deftest ~sym [email protected])
         (clojure.test/deftest ~sym [email protected])))))
But that doesn't make a difference. It's just that the prints don't show in the console when running the tests in workspaces.

aisamu17:04:55

> I'm running the tests through #workspaces I'd give that channel a try then. Are you able to see fixtures operating properly outside workspaces?

Spaceman15:04:29

I have the following use-fixtures defined in my test file:

(use-fixtures :each {:before (fn []
                               (prn "using fixtures")
                               ) :after #()})
But running none of the tests in this file prints "using fixtures"

Rucy16:04:40

Hi what do you guys use for JWT? https://github.com/funcool/buddy seems to be very old and not taken care of

dpsutton16:04:49

i've used that at a previous job. i don't believe jwt's have changed in the meantime. it served my purposes fine and is maintained by some security conscious people as far as i know. but those are jvm based i believe so not suitable for cljs

👍 4
dpsutton17:04:28

wasn't there a ticket to have cljs.repl/{doc,dir} work on GCL? so you could call dir on goog.events and similar? I looked in jira and not finding it and wonder if i'm misremembering? and nevermind it works. i thought i had checked it recently.

dpsutton17:04:21

that is incredibly helpful. thanks @dnolen!

doubleagent17:04:57

Can someone help me with externs? I wrote this code to improve on the datatables recipe: https://pastebin.com/PxPinWKw. After setting infer-externs & `warn-on-infer` I get these warnings: https://pastebin.com/nwdFJSZQ. My understanding is that I'm supposed to provide type hints, but I don't know how to determine the types I'm supposed to hint eg "what is .destroy a member function of?" Additionally, I recompiled the namespace with *warn-on-infer* and these warnings went away. Does that mean an externs file has already been generated? Where would it be located?

dnolen17:04:15

@dpsutton I think with the new global require proposal this will be way cooler

dnolen17:04:30

docs and validation for all standard HTML apis

dpsutton17:04:52

i've overhauled inf-clojure so that the experience is extremely nice with just the raw cljs.main and i'm loving it. so thanks for prodding me on that. and i'm looking forward to it. thanks for all your work!

Ahmed Hassan17:04:58

How does it compare with cider and shadow-cljs?

dpsutton18:04:57

not as full featured. shadow can run an nrepl server so all the CIDER goodies apply. inf-clojure is super nice if you want to run simply clojure -m cljs.main -r It was prompted when i wanted to follow along with the new bundle target for clojurescript

dpsutton18:04:22

it puts you back at the classic repl experience of editor that can easily send commands to a running repl

dpsutton18:04:41

and some niceities to call dir,doc,apropos, loading namespaces, etc

Ahmed Hassan18:04:45

I have been using Chlorine Atom for 4 to 5 months, was using cider and emacs before that, now coming towards cider again with doom emacs.

Ahmed Hassan18:04:40

Any Suggestions, recommendations, advices?

Ahmed Hassan18:04:20

I am building application using Fulcro/Pathom and PostgreSQL.

dpsutton18:04:03

i think CIDER is probably right up your alley

dpsutton18:04:09

certainly worth trying out

dpsutton18:04:31

inf-clojure is not nearly as full featured and if nrepl works its clearly the way to go

doubleagent17:04:30

One way I thought of would be to save eg this in an atom and log it to the console in order to divine the type

doubleagent17:04:12

that just gives me the render function. pretty sure that doesn't factor into externs

doubleagent18:04:15

It looks like the warnings are still getting printed to the js console, just not in my repl

dnolen17:04:45

tons of stuff in the standard set of externs

dnolen17:04:20

@dpsutton glad to hear inf-clojure + cljs.main works well! that was my preferred Emacs setup

dpsutton17:04:12

it would parse that info to emit warnings similar to WARNING: cljs.core/+, all arguments must be numbers, got [string number] instead at line 1 <cljs repl> ?

dpsutton17:04:01

(from your "validation" suggestion)

dnolen17:04:06

not type based stuff, though I've had thoughts floating around but nothing actionable

dnolen17:04:19

stuff like doc would work for HTML apis

dnolen17:04:37

(doc window) (doc console)

dnolen17:04:47

but argument count would be validated just like for real GCL libs

dpsutton17:04:31

that sounds quite nice. i'm really digging the thoughful run-time documenting aspects of clojure. gonna have to go vote on that javadoc ticket for clojure 1.11

dnolen17:04:29

a bigger project to think about is seeing if we could reconcile fns specs w/ the interop barrier

dnolen17:04:52

instead of polluting our code w/ types we could just use the fnspecs and compare against the externs

dnolen17:04:20

this would get you at least Common Lisp level basic checking which is still reasonable - could be REPL friendly too

dnolen17:04:46

anyways - this not something I'm planning on working on in the very near future - but it's been in the back of my mind for a long time

dnolen17:04:39

we used to use Closure type checking, but I could not make it do what I wanted and it was not usable during REPL dev, only advanced

dnolen17:04:46

the type inference is getting good enough where this new line could be reasonably explored

dnolen17:04:59

REPL friendly type assistance would be pretty cool - not so common a feature in languages

dnolen17:04:02

not a huge fan of TypeScript, but I understand that having some type checking is flat yes/no for some people assessing technologies

dnolen17:04:24

I think having the option to check specs against inferred types and externs would draw those kinds of users in

lilactown17:04:43

by fnspecs do you mean cljs.spec fdefs, or are fnspecs something I haven't learned about yet?

dnolen17:04:57

yes I mean cljs.spec

👍 4
doubleagent18:04:24

Is there anything like (type thing) in cljs which gives me the information needed to include type hints? type works in clojure for this purpose but apparently not clojurescript.

doubleagent18:04:48

To try this a third way, the externs guide (https://clojurescript.org/guides/externs) teaches you to type hint in order to produce externs.  @dnolen goes through an example where he type hints `wrap-baz` with `^js/Foo.Bar`, but doesn't show me how he determined that `^js/Foo.Bar` is the type hint which was needed.  How did he do that?

dnolen18:04:54

there's not a generic way to get the type in JS

dnolen18:04:11

type just returns the constructor

dnolen18:04:11

for externs it's really not needed - you can just ^js and be done w/ it

doubleagent18:04:46

Thank you!!! I'll give ^js a try and see if that removes the inference warnings

Spaceman18:04:51

has anyone used jest with clojurescript? How did you install it? After I install it using npm install jest and add "test":"jest" in package.json, I expect keywords like "expect" to work:

(.toBeInTheDocument (expect (.getByText screen "Some Component")))
But I get that expect is undefined. js/expect gives undefined as well. How to get jest to work with clojurescript?

Spaceman16:04:27

How did you install it exactly? The documentation doesn't explain very clearly. Is there a reason why you only experimented with it and not use it regularly?

athomasoriginal21:04:57

> How did you install it exactly? This is covered in the https://github.com/athomasoriginal/demo-clojurescript-jest#quickstart guide. The idea is that Jest is such an NPM package, so it’s installed when you run yarn and then the webpack stuff is just what’s outlined in this guide: https://clojurescript.org/guides/webpack (or rather than guide before the awesome new CLJS that came out).

athomasoriginal21:04:41

Then you build your tests, and then you run yarn against your compiled tests

athomasoriginal21:04:11

> Is there a reason why you only experimented with it and not use it regularly? Yes. Part of the reason is I just didn’t find this worth while enough to keep pursuing. It would be cool to continue exploring at some point even if it was just to provide an example to the CLJS/JS community about how it can be done. The reasons though: • There is a performance cost while running the tests • The developer experience will require some work to get everything in a similar state to using Jest w/ JS • Most importantly, the cljs ecosystem provides most of the functionality and with a little elbow grease, you can get most of the same functionality Jest provides with CLJS libraries.

Spaceman21:04:54

Have you found a good test-runner for cljs?

Spaceman21:04:28

Is there a way to hack this file to create one for cljs?

athomasoriginal21:04:32

> Have you found a good test-runner for cljs? Yeah, so it depends what you want out of your “test-runner”. I would like to experiment with https://github.com/lambdaisland/kaocha-cljs, but right now I just write my own and tack on additional libraries as I need. an example of the simplest form of my setup: https://betweentwoparens.com/clojurescript-test-setup

athomasoriginal21:04:55

But to expand on the original question of why not jest and how clj/cljs provides what I need. Jes is • test runner • test environment • assertion library • reports • special tests (SNAPSHOT) • etc Then it just wraps them together.

Spaceman21:04:44

why not keep using kaocha-cljs? Why write your own toolchain?

athomasoriginal21:04:21

• test-runner is pretty easy to implement a basic one - kaocha would be a better one • clojure.test takes care of assertion library and such • The test environment is just JSDOM - see the blog post attached above and anything else like improved reporting, is pretty easy to cobble together from the CLJ/CLJS libraries available.

athomasoriginal21:04:00

> why not keep using kaocha-cljs? Why write your own toolchain? Oh, don’t get me wrong, I want to use kaocha, or just another test-runner, but I just haven’t had an opportunity to stetup yet

athomasoriginal21:04:43

My main point is that each of the things that Jest gives you is pretty easy to setup and you get the full clj/cljs experience

Spaceman21:04:20

Say I need to find if a button contains a piece of text [:div [:button {:on-click #()} "Continue"]]. What would a function look like to test that?

athomasoriginal21:04:28

And to give an example of what I test: • vanilla cljs code in browser and in our ci-environment (thanks, JSDOM!) • react components/screens - anything you like

athomasoriginal21:04:12

Yeah, so for that you can use the excellent react-testing-library and it might look something like this:

athomasoriginal21:04:37

(deftest test-button
  (let [button-click-count  (atom 1)
        left-click          {:button 0}
        handle-button-click #(swap! button-click-count inc)
        button              [button/button
                              {:on-click handle-button-click}
                              "My Button"]
        container           (test-library/render mounted-containers button)
        button-elem         (.. container (querySelector "button"))
        text-elem           (.. rts (getByText container #"(?i)my button"))]
    (testing "button text wrapped in span"
      (is (= (-> text-elem .-tagName string/lower-case) "span"))
      (is (= (-> text-elem .-textContent) "My Button"))) ...

athomasoriginal21:04:38

of course, you need to setup your app to use react-testing-library which is part of the JS ecosystem and for that checkout the webpack guide I posted above

athomasoriginal21:04:32

And also note that I have not included the setup/teardown functions. That’s what test-library/render is. It’s something I wrote really quickly. This means you have to track whats added to the DOM so you can remove them when the tests are done….otherwise you will have multiple elements attached at any one time

Spaceman21:04:40

Yeah, I am already using the react-testing-library. How do I include the setup/teardown functions to automatically run for each deftest?

athomasoriginal21:04:33

That is just how clojure.test does things. e.g.

(use-fixtures :each
  {:after #(cleanup-containers mounted-containers)})

athomasoriginal21:04:24

I will eventually write this stuff up in a proper document

Spaceman21:04:48

That's great. You have a reader for sure.

athomasoriginal21:04:45

Yeah, I mean, when you begin to piece together what JS is doing and a bit of how CLJS is working it’s surprising how much is already available in the CLJ/CLJS ecosystem

athomasoriginal21:04:31

Then, once yous solve your problems, as I have done in my own tests, you don’t need much more. The things I want now is just a better DX, aside from that, things work pretty well

Spaceman21:04:40

What do you not like about the current DX?

athomasoriginal21:04:06

Nothing big enough to really address here. Just subtle things that would improve my personal workflow.

athomasoriginal21:04:25

Also keep in mind that I like spartan setups in general, so my approach may not be great for everyone…but it does cover most all the things

athomasoriginal21:04:59

Example of things I can do without: snapshot tests. I don’t really see much value in them, but that is a point that many will argue with 🤷

Spaceman21:04:21

What is an example of a subtle thing that would improve your workflow?

Spaceman21:04:32

I think there are certain things as well that could be improved in my workflow, but some of them are subconscious

Spaceman21:04:57

or that I've gotten used to them and forgotten that they are a source of inefficiency

Spaceman21:04:59

So I added [lambdaisland/kaocha-cljs "0.0-71"] in my project.clj and ran

clojure -m kaocha.runner unit-cljs
but got
Could not locate kaocha/runner__init.class, kaocha/runner.clj or kaocha/runner.cljc on classpath.
Any ideas why?

athomasoriginal23:04:25

You have both lambdaisland/kaocha and lambdaisland/kaocha-cljs ?

athomasoriginal23:04:57

what does your deps.edn look like? and you have a test.edn file?

Spaceman23:04:11

it works now. I didn't have the bin/kaocha set up. I think that's why it wasn't working before

Spaceman23:04:41

But now I get the following error: No such namespace: @testing-library/react, could not locate CIRCAtesting_library_SLASH_react.cljs, CIRCAtesting_library_SLASH_react.cljc, or JavaScript source providing "@testing-library/react" (Please check that namespaces with dashes use underscores in the ClojureScript file name) in file /Users/...

Spaceman23:04:41

Although I have testing-library required in this file: ["@testing-library/react" :refer (render fireEvent waitFor screen cleanup)]

Spaceman23:04:22

why would this be?

athomasoriginal23:04:28

your using webpack, figwheel, shadow?

athomasoriginal23:04:04

not sure off the top of my head.

Spaceman23:04:52

is kaocha.repl only supposed to run in clj repl or also in the cljs repl?

Spaceman23:04:07

@U6GNVEWQG Maybe this is relevant

Spaceman11:04:00

@U6GNVEWQG you mentioned testing with jsdom. Why do you like testing using jsdom?

Spaceman12:04:58

also, is there a way to specify screen sizes in react-testing-library?

doubleagent18:04:33

@dnolen I added ^js type hints to three of the member accesses and I am still seeing inference warnings. https://pastebin.com/A7cbdjGB

lilactown18:04:18

try adding hints to the actual expression, e.g.:

(.-refs ^js component)

lilactown18:04:52

if that does fix it, I am not sure if that's an error with the inference or not

doubleagent18:04:29

Um, ew.

(defn home-did-mount [^js this]
  (.DataTable ^js/$
   (js/$ ^js (.-main ^js (.-refs ^js this)))
   (clj->js
    {:columns columns
     :data data
     :responsive true})))

doubleagent18:04:33

It does seem to get rid of the inference warnings around this function. I had to use ^js/$ for that second one, though.

lilactown18:04:03

do you have extern inference on?

doubleagent18:04:06

I have :infer-externs on in my cljsbuild config, but only for building the uberjar.

dnolen18:04:38

@doubleagent you should only need to do it once for this, are you using 1.10.741?

dnolen18:04:01

there some externs issues with 597, but anyways, what warnings do you get with only hinting the fn arg on 597

doubleagent19:04:51

Figwheel: Compile Warning - Adding extern to Object for property refs due to ambiguous expression (. this -refs) in file src/cljs/bigboard/core.cljs at line 381, column 4
Figwheel: Compile Warning - Adding extern to Object for property main due to ambiguous expression (. (.-refs this) -main) in file src/cljs/bigboard/core.cljs at line 381, column 4
Figwheel: Compile Warning - Adding extern to Object for property DataTable due to ambiguous expression (. (-> this .-refs .-main js/$) DataTable (clj->js {:columns columns, :data data, :responsive true})) in file src/cljs/bigboard/core.cljs at line 380, column 3

dnolen19:04:36

right it's just complaining about object so give it the type

nprbst19:04:38

@doubleagent see #figwheel-main

dnolen19:04:51

@nathan.probst this is not a figwheel issue it's ok

nprbst19:04:05

Ah. Cool.

dnolen19:04:19

@doubleagent what is the type of that argument, you must know since you're getting it from somewhere

doubleagent19:04:14

I think it's a React.Component, but honestly I don't know because reagent hides a lot of that stuff from me.

doubleagent19:04:18

I'll try that.

dnolen19:04:28

^js/React.Component

doubleagent19:04:13

@dnolen that reduces the warnings to one.

Figwheel: Compile Warning - Adding extern to Object for property DataTable due to ambiguous expression (. (-> this .-refs .-main js/$) DataTable (clj->js {:columns columns, :data data, :responsive true})) in file src/cljs/bigboard/core.cljs at line 380, column 3

ingesol19:04:43

Using :target :bundle and using the dependency "chart.js" , which has a non-valid clojure name and returns its constructor, what would be the sensible way to deal with that? I see that it’s possible to use an alias in package.json so you can call it something like "chartjs". But how about usage? You can’t run the alias as a constructor:

(require [chartjs])
(chartjs. params)

dnolen19:04:04

@ingesol we do support invokeable ns, but we may need to expand that

dnolen19:04:47

if it doesn't work file an issue in JIRA with error information etc.

dnolen19:04:41

@doubleagent same problem, what is the type of the thing with DataTable method?

doubleagent19:04:57

Beats me. It's whatever jquery's $ function returns when passed an HTMLTableElement Do I need to go read the jquery source code in order to figure it out?

dnolen19:04:10

I can't help you figure that out, you can also just ignore the warning

dnolen19:04:39

but it sounds like you know the answer anyway

dnolen19:04:50

HTMLTableElement will probably work fine

doubleagent19:04:36

jquery documentation says it's a collection, but maybe it collapses the colletion when there is only one matching element.

doubleagent19:04:57

I'll try ^js/HTMLTableElement

doubleagent19:04:09

That didn't work.

dnolen19:04:09

what didn't work? paste the expression

doubleagent19:04:17

(defn home-did-mount
  [^js/React.Component this]
  (reset! x this)
  (.DataTable
   ^js/HTMLTableElement
   (-> this .-refs .-main js/$)
   (clj->js
    {:columns columns
     :data data
     :responsive true})))
Figwheel: Compile Warning - Adding extern to Object for property DataTable due to ambiguous expression (. (-> this .-refs .-main js/$) DataTable (clj->js {:columns columns, :data data, :responsive true})) in file /c:/Users/doubl/OneDrive/Documents/GitHub/bigboard/src/cljs/bigboard/core.cljs at line 384, column 3

dnolen19:04:08

@doubleagent ok this one I think is fixed by 1.10.741

dnolen19:04:26

but Figwheel is not yet compatible - so you should just ignore

dnolen19:04:36

nothing bad is going to happen

doubleagent19:04:24

@dnolen my understanding was that it would break under advanced compilation

dnolen19:04:30

that's not correct

doubleagent19:04:40

Ah, okay. My mistake.

dnolen19:04:00

the warning just says it doesn't know what the type is so it's creating an extern on Object

doubleagent19:04:17

Alright, thanks

dnolen19:04:10

@ingesol I looked at the analyzer - it seems like it should work - but you didn't really give enough information about what didn't work for you

dnolen19:04:43

also you don't need to bother with the alias in package.json, (:require ["chart.js" :as chart]) should work

ingesol19:04:18

@dnolen oh, I just assumed that those things were specific to shadow-cljs. It probably works then, sorry for the confusion

dnolen19:04:36

@ingesol the semantics of shadow are subtly different and should never be relied upon in code you intend to publish (as a library)

dnolen19:04:12

in shadow-cljs I believe string requires means it's a JS module, not true for ClojureScript

dnolen19:04:27

ClojureScript just generally allows namespaces to specified as strings

dnolen19:04:25

that's pretty old feature too - almost three years now

ingesol19:04:44

@dnolen I learnt something today then :) only saw examples in shadow before

dnolen19:04:01

we had to solve that problem way back when we did all the work to push everything through Closure

dnolen19:04:49

lots of package names in node_modules aren't valid symbols

dnolen19:04:16

and all the various usage patterns etc.

dnolen19:04:33

those things were done independently of the bundler stuff

dnolen19:04:04

in the end while the bundler stuff appears to be big news, it was really minor changes to tie together the work of the past 5 years

didibus19:04:00

I guess in theory, if your npm deps can go through Closure, that might still be beneficial to go that route for those and get the benefit of dead code elimination

dnolen20:04:34

@didibus that's the long game

👍 4
Eccentric J22:04:02

I take it (with-open ...) doesn't work with cljs?

phronmophobic22:04:34

it should… is there an issue you’re running into?

Eccentric J22:04:19

Cool! Not yet. I just couldn't remember if it was tied to Java's IO. It also wasn't listed in http://cljs.github.io/api/cljs.core/ as far as I could tell.

phronmophobic22:04:21

weird. it doesn’t seem to be included, but there’s no reason you couldn’t write the macro to work in cljs

Eccentric J22:04:22

Actually, I guess I am running into an issue. Doesn't seem like it exists.

Eccentric J22:04:23

Ah yeah, found an example. http://clojurescriptmadeeasy.com/blog/cljs-read-files-line-by-line-on-nodejs-part-2.html which makes me think it's likely not included.

phronmophobic22:04:34

yea. doesn’t seem to be

phronmophobic22:04:16

but, conceptually, it seems like there’s no reason it couldn’t work. I guess .close is a less common interface in js than on the jvm (although there are examples like websockets)

Eccentric J22:04:08

That seems like a fairly consistent convention. I wonder why it wasn't ported over?

dpsutton22:04:17

I think there’s some prior art in planck’s utility namespaces if you’re interest

lilactown23:04:24

in general IO is completely different in JS - some environments don't have access to the file system, and most IO is async so with-open doesn't make nearly as much sense

Eccentric J01:04:47

That's a good point. I spaced on the notion that sync IO is atypical in JS.

hindol07:04:56

I am no expert but I read about the two phase evaluation of CLJS. The first phase happens in the JVM, the second phase happens at runtime in whatever environment you are targetting. I would think with-open can work normally in the first phase. You can read the file ahead of time and cache the contents. If you want to read the file at runtime, then you must rely on the functionality available in the target environment.

theeternalpulse23:04:18

I'm following the webpack guide, but noticed that with -r and -v option the repl doesn't appear in the console until I press enter. the initial output for the repl is injected somewhere in between the output

dnolen23:04:27

More less expected with -v output I’ll probably remove that, it just makes it easier to know that some is happening

dnolen23:04:45

Something I mean

schaueho13:04:42

I wanted to use testing-library/react too, but in the context of figwheel-main, not shadow-cljs. Alas, I can't figure out how to include it in the dependencies and would need some pointers and what to look at.