Fork me on GitHub
#clojurescript
<
2020-04-27
>
Spaceman00:04:47

What are some good alternatives to the jest testing library for clojurescript?

plexus08:04:40

what are you looking for in a testing library?

Spaceman16:04:30

A testing library that lets me test user interaction with the app. I'm using the react-testing-library, which integrates with jest and jsdom. But not being able to install jest and that jsdom works with node.js only, I'm looking for alternatives. Jest api's for checking which components are visible are pretty neat:

expect(screen.getByRole('heading')).toHaveTextContent('hello there')

Spaceman16:04:26

the haveTextContent functionality is what I aim to use 80% of the time from jest.

Spaceman16:04:24

So long as a small script can recreate this function, I won't need jest for the most part.

Schpaa08:04:25

I have something that takes & pairs but I want to give it a map, how can I do this?

plexus08:04:13

some utility libraries (I think medley?) have an mapply that does this. Or you can do (apply foo (mapcat identity m))

Schpaa10:04:33

that worked out fine, thanks

Schpaa08:04:15

the context is the kee-frame switch-route function which looks like this:

[k/switch-route (fn [route] (:handler route)) :index [:div \"This is index page\"] :about [:div \"This is the about page\"] nil [:div \"Probably also the index page\"]]

ingesol09:04:41

@dnolen Using deps.edn with latest cljs master, I got my system almost to stable build. CLJSJS problems seem gone. Our project depends on a few NPM deps, and there are some remaining problems. See thread here for some remaining feedback/questions

ingesol09:04:32

"react-content-loader": "^4.2.1",
Earlier we did this in our index.js
import ContentLoader from 'react-content-loader';
window.ContentLoader = ContentLoader;
Usage
[:> js/ContentLoader args]
Now, when using bundle, I inserted
(require [react-content-loader])
The var react-content-loader now is of type Module and the property default of that object contains the behaviour I want. I know that because I get it by doing
(let [content-loader (.-default react-content-loader)]
  [:> content-loader args])
Doing this does not work
[:> react-content-loader args]
Not too strong on JS modules, but I assume this is an ES6 module? Is it supported?

ingesol09:04:06

Was going to post more cases, but realized they were the same

ingesol09:04:55

Got a bunch of source map errors, they may be due to other errors in my setup, but posting here in case they ring a bell. These examples are 2 of many (tens or hundreds)

DevTools failed to parse SourceMap: webpack:///node_modules/react-draggable/dist/react-draggable.js.map

ingesol09:04:30

DevTools failed to parse SourceMap: 
I verified that both of these exist on my file system

dnolen11:04:16

the sourcemap stuff doesn't yet seem ClojureScript related will need more information

dnolen11:04:02

the default thing is known and will be addressed soon like in a couple of week but not in the pending release which is just about fixing the immediate small issues w/ the last release

dnolen11:04:38

is the ticket if you want to follow along

ingesol11:04:50

Ok, thanks! Nothing more to report for now, then.

henrik09:04:48

Is there any way to distinguish between an integer and a float in CLJS?

henrik09:04:13

I.e., there’s js/Number.isInteger , but it considers e.g. 1.0 to be an int.

henrik10:04:12

JS truly is the Comic Sans of langauges.

dnolen11:04:47

@henrik there is nothing in ClojureScript that isn't effectively that predicate, we just use JS numerics so you can't mask anything

henrik12:04:29

Gotcha. I’m communicating with WASM. I’ll just have to state the intention separately and coerce it to the proper format when the WASM receives it.

dominicm11:04:16

For externs & externs inference, is there an important distinction between:

var x = {
  a: null,
}
and
var x = {}
x.a = function(){}
I'm asking because externs inference doesn't seem to be working for some pretty common cases, and I suspect it's an us thing rather than a cljs thing.

dominicm12:04:03

Just spotted that 597 had a fix for foreign libs & externs

plexus11:04:32

cljs.main is adding a preload of clojure.browser.repl.preload even though I'm doing a simple compile.

$ clojure -m cljs.main --compile-opts '{:output-dir "out" :output-to "out/main.js" :main glogi-demo.demo}' --verbose --compile
Options passed to ClojureScript compiler: {,,, :preloads [process.env clojure.browser.repl.preload] ,,, }

plexus11:04:48

am I holding it wrong or is that an issue?

plexus11:04:38

I ran into this because I'm compiling for a target without a dom, and the repl preload pulls in goog.dom.DomHelper

dnolen12:04:29

@plexus it's always done that, but it's innocuous for dev builds

dnolen12:04:54

unless of course you're not targeting the browser which is in fact the default

dnolen12:04:16

so maybe explain a bit more what you are attempting to do?

dnolen12:04:18

:browser-repl false in your config should prevent that - if not that's a bug

plexus12:04:36

yes, I found :browser-repl false, that works. I'm compiling with :taget :graaljs.

plexus12:04:19

I found it surprising since I'm not using --repl

plexus12:04:31

Ah so it drops it with :optimizations :advanced, but not with :simple

plexus12:04:48

oh but I guess the :graaljs target is removed? I thought it was just the REPL...

dnolen12:04:59

no target support except for browser, webworker, node, bundle

dnolen12:04:32

@plexus I understand why it might seem confusing but in fact the REPL environment knows things that compile must know

dnolen12:04:48

in some sense more like Clojure

dnolen12:04:58

there is no compiler in Clojure (in one sense) just the REPL

dnolen12:04:00

@plexus all :graaljs did was generate a simple bootstrap file, you can now do this yourself with :target-fn

dnolen12:04:40

also I thought @kommen made a thing to replace the :graaljs target using the new stuff

plexus12:04:43

oh ok, I didn't realize the target/bootstrap is pluggable. that's ok then 🙂

dnolen12:04:09

yeah we made all the necessary changes to offset the removal

dnolen12:04:28

anyone can reintroduce the old targets and REPL as third party efforts

dnolen12:04:39

I tried to make everything public that is required, Krell the React Native tool is worth studying - there's a couple more things to make public and these will appear over time - will happen faster as people decide to extend the compiler for custom build stuff / REPLs

theeternalpulse13:04:08

Is there a way to enable live reloading in a Clojusrescript application? Also is there a way to specify what folder to search for index.html in?

dominicm13:04:59

I'm using 597, not latest due to figwheel-main, but is it expected that this should be picked up by externs inference? Or is this invalid use?

(ns (:require [react]))

(.useState react ...)
Doesn't work on latest either. I guess not a bug, invalid use.

dnolen14:04:44

(react/useState ...) is the correct way, react is namespace here

dominicm14:04:14

@dnolen figured as much, wanted to double check before rewriting all the code (80 instances!). Thanks for confirming 🙂

dnolen14:04:03

@dominicm re: externs inference it should work since that's exactly the usage style covered by the webpack guide - if it's not working specifically for useState then that's a bug

dnolen14:04:22

@theeternalpulse live reloading is generally a feature of the REPL / build tool - figwheel, shadow-cljs, krell, etc.

dominicm14:04:31

@dnolen For me,

(ns dmc.core (:require [react]))

(.useState react #js {})
Compiles to this for the useState call
z.h({});
When using foreign libs & infer-externs with a webpack build.

dominicm14:04:02

@dnolen apologies, I just realised you were responding to my original query 😄

dnolen14:04:55

try with the namespace pattern, and scan your inferred_externs.js

dnolen14:04:06

you should have Object.useState in there

dnolen14:04:06

as a general rule :require does not result in objects you can use in this way

dnolen14:04:36

there are some exceptions to this rule for interop - but these should be seen as special cases

dnolen14:04:40

If you have questions, problems, bug reports, please post them there - Slack is great but too transient

👍 28
dnolen14:04:36

It's also the place for feature requests - while we rarely accept anything language related that doesn't align with Clojure, we're always looking for things to make ClojureScript usage easier for whatever JavaScript environment you're interested in targeting

dominicm14:04:19

@dnolen namespace pattern works perfectly :)

Lone Ranger16:04:57

Is anyone doing any work with the serviceworker API?

Lone Ranger16:04:21

I'm finding it very challenging maintaining a REPL connection with a serviceworker. There are a lot of moving parts. Additionally, it's pretty challenging have two builds going simultaneously -- one to compile the serviceworker js, and one to compile the reagent/view js. Effectively where I'm at is ... I don't even bother trying to get the repl connection going with the service worker and I'm just reloading the damn thing. Currently using deps.edn/figwheel-main. Open to shadow-cljs or any other thing that works for this crazy build process

john19:04:19

You can check out how I do it here with fighweel https://github.com/johnmn3/tau.alpha

john19:04:02

There's a lot of changes coming with the :bundle stuff though, so it'll probably need some tweaking for that sitch

Lone Ranger20:04:46

wow cool! Do you have a config that allows integrated REPL development aka through CIDER?

Lone Ranger20:04:58

first of all I think this is fantastic but I'm also curious if this will apply to service workers ... slightly different API than web workers: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

Lone Ranger20:04:30

same issues essentially but no idea if they use a sharedarraybuffer or not between them and main thread

john20:04:56

Haven't used cider in years... Does it use figwheel? If so you might be able to use whats in that project.

john20:04:22

Yeah, the code in there might not work in the service worker. But the mechanism of connecting back to the repl might be similar

john20:04:33

I've definitely repled from a service worker before

john20:04:45

Many years ago when I was exploring them

Lone Ranger21:04:22

awesome... I think this will help a lot 🙂 I'll let you know what I come up with, thanks for fighting the good fight on this

john21:04:24

No prob! Oh, sharedarraybuffers? those should be orthogonal concerns.

john21:04:33

Are you trying use SABs?

Lone Ranger22:04:29

really my issue is maintaining a persistent repl connection to serviceworkers

Lone Ranger22:04:17

since the serviceworker is not started by the main thread necessarily (it has a bit of a life of its own), it's a little tricky

Lone Ranger22:04:59

I'm not sure how to force the service worker to open a websocket to figwheel

john22:04:02

Right, with figwheel.main, it's a little more straightforward since you can just include figwheel.repl and then connect to the server. Pretty easy.

Lone Ranger22:04:33

ah that's not a bad idea. you mean embed a repl in the client code?

john22:04:02

Just that figwheel.repl has the necessary machinary to connect back to figwheel server

Lone Ranger22:04:46

right so you would include (require 'figwheel.repl) in serviceworker.cljs? or am I misunderstanding?

john22:04:13

and then it's something like repl/connect url-string

Lone Ranger22:04:24

gotcha. Yeah that's a really good idea

john22:04:24

It's in tau.alpha

Lone Ranger22:04:45

awesome. There are SO many moving parts its hard to keep track of

john22:04:17

You have to disable config validation figwheel, which you can see in the example project in tau.alpha

john22:04:32

It is, I agree

Lone Ranger22:04:53

oh man I can't even imagine how long it took to figure that out... and the chrome flag for sharedarraybuffers

Lone Ranger22:04:43

that's partly why I haven't switched to shadow-cljs. took me so long to figure out how to use figwheel-main I'm just sticking with it until I have a compelling reason to switch

Lone Ranger22:04:56

everyone says it's the bees knees but my brain is only so big

john22:04:08

You don't need SABs for any of this though

john22:04:29

same here lol

Lone Ranger22:04:35

I'm not sure what a SABs is 😅

Lone Ranger22:04:02

sharedarraybuffers

john22:04:13

aye lol s18

Lone Ranger22:04:22

(I thought that was pivotal for switching repl between main thread and workers but maybe I read docs wrong)

john22:04:41

Where did you read that?

Lone Ranger22:04:16

my brain summarized that as "need SABs for tauons"

john22:04:23

Ah yeah, for tau.alpha...

john22:04:07

in that particular implementation, a tauon is basically a webworker, with some extra semantics wrapped around it

john22:04:52

You can think of tauons and webworkers as somewhat synonymous

john22:04:52

Tauons add more semantics to act more like threads in an executor pool though

john22:04:28

Then you have a tau, which is like an atom

john22:04:40

and that atom is backed by a SAB

john22:04:48

things are serialized to and from it

Lone Ranger22:04:00

sorry I'm a bit confused only because you mentioned alpha like its a separate thing, is there a different repo?

Lone Ranger22:04:37

"Ah yeah, for tau.alpha..."

Lone Ranger22:04:47

is there a regular "tau" or something?

john22:04:49

The library, tau.alpha, is kinda named after the primary shared-atom thing called a tau

Lone Ranger22:04:12

I like it 😄

Lone Ranger22:04:36

ok ok, I'm caught up

john22:04:40

So, a shared-atom (a tau) is backed by SABs, and data is serialized to and from it

Lone Ranger22:04:56

you didn't realize I was talking about the need for SABs in reference to tau.alpha, you thought I meant in reference to figwheel

john22:04:00

you can actually use that channel for communication between workers, if you want

Lone Ranger22:04:46

😅 if I can't even communicate with humans I'm not sure how much luck I'll have with serviceworkers but you never know

Lone Ranger22:04:52

hopefully they are equally patient

john22:04:11

But primarily it's a shared container for data structures, rather than a comms channel

Lone Ranger22:04:50

I think it's a really fascinating approach. It's too bad we don't have journals or anything to write to, it's worthy of a write up

john22:04:11

fwiw, I'm thinking about scrapping the whole tau naming thing... The architecture there kinda straddles a world where shared-atoms can either be abstractions that serialize and synchronize state between atoms via postMessage. Vs a world where you can just use SABs. So I'm thinking about making a fresh lib that focuses specifically on SABs.

nprbst22:04:36

@U050PJ2EU do you have any insight into when SABs will be widely available again? https://caniuse.com/#feat=sharedarraybuffer

john22:04:09

but probably in a few months

Lone Ranger22:04:49

@U050PJ2EU I might consider making something that has the same API but you could swap out underlying configurations between SABs and syncronized atoms via msg

Lone Ranger22:04:07

or whatever other abstraction

john22:04:13

@U3BALC2HH probably a good idea

nprbst22:04:18

I haven't looked...but do you happen to know about support in more controlled environments like Cordova and Electron?

Lone Ranger22:04:28

you could checkout some of the architecture #datahike uses to encourage pluggable back ends. I'm not trying to scope creep you here but I think it's a very cool concept and I would just hate to see some folks not adopt it b/c they have concerns about the underlying implmentation

john22:04:40

Cordorva... I think tries to have many js vm targets. Electron always targets V8, so it should have the same functionality, after the updates roll in.

👍 4
🙏 4
Lone Ranger22:04:40

it solves a very generic problem

Lone Ranger22:04:30

also that way when they fix the spectre situation your users can just flip a config value and get the benefits of SABs w/o having to change any code

Lone Ranger22:04:47

but what do I know ¯\(ツ)

Lone Ranger22:04:59

I don't have a great track record with anyone adopting my tools sooo

Lone Ranger22:04:13

take my opinion with a grain of salt

john22:04:35

It's a good idea. The pieces of tau should be busted out into libs, especially now that the project has spread out a little more

Lone Ranger23:04:11

nod. Here's something to keep an eye on too... so service workers, I'm not sure if you're familiar with them, are like web workers but more persistent and with network proxy abilities. So serviceworkers + webRTC + tauons == really slick peer 2 peer information exchange and data sync

Lone Ranger23:04:47

it's an area that I'm actively researching 🙂

john23:04:00

Yeah, service workers are interesting

john23:04:52

Before SABs, I used them to make a hack to simulate blocking semantics, to enable future/await

😮 4
john23:04:25

Cause you could do a blocking xhr call and then use the service worker to hang the call and return when you want to wake the worker up.

john23:04:33

They're interesting for proxy stuff. Or maybe doing SSR, client side 😆

Lone Ranger23:04:47

HAHA yesss!!!

Lone Ranger23:04:21

I was wondering what the possibility of moving the react diffing stuff to a service worker would be

john23:04:23

But ultimately, I think you could probably get most of that done in regular workers

john23:04:15

As long as you don't do any computation heavy stuff on the worker, and only use it for routing and proxying

Lone Ranger23:04:33

I considered some kind of complex scheme with two datascript conns, one in the main thread and one in the service worker, and the one in the worker would be the one you "write" to (like a transactor) and the one in the main thread would be the one you read from (like a peer) and this would give you fine grained control on when and what data reaches the main thread. That way you could throttle the datom flow to ensure 60fps paint cycles

Lone Ranger23:04:19

but ultimately it always paid to just write less shitty, less complicated main thread code than put that crazy scheme together

john23:04:43

have you seen the example on tau.alpha? https://johnmn3.github.io/tau.alpha/

john23:04:03

that's basically how it's done

john23:04:14

Your bottleneck is on serialization to and from the SAB

john23:04:43

so we need to rebuild datastructures on top of typed arrays so they can live in SABs transparently

Lone Ranger23:04:30

ahhhhh interesting. I wasn't sure how much the bottleneck would be. Does it bottleneck throughput, choke on serialization, or mostly just volume of data that is the biggest issue?

Lone Ranger23:04:58

i.e., would it be more efficient to transmit a million words in seperate messages or a million words in one big message?

john23:04:21

Try not to think about "transmit" anymore

Lone Ranger23:04:43

:rolling_on_the_floor_laughing: yeah with covid it's a bad idea

john23:04:44

Your writing to a place that both the main thread and the workers can see at the same time

Lone Ranger23:04:08

I was thinking from the traditional onMessage perspective, not SABs

john23:04:56

That's the old way 🙂

john23:04:28

But in the example above, there is no serialization

john23:04:37

Because we're operating on binary data, in cljs

john23:04:40

so it's fast

john23:04:59

We're not serializing CLJS persistent datastructures in that example

john23:04:24

So, either way, via onMessage or via sabs, you'll have to serialize

john23:04:04

The benefits of sabs though... If your data is already well typed, it can live in both places at once, because it's literally shared memory.

john23:04:21

If you have it living in the SAB

Lone Ranger23:04:43

Oh yeah I have no doubts. Will be interested to see how you handled mutexes there

Lone Ranger23:04:53

seems like race-condition city!

john23:04:04

Here's a sneak peak I made of trying to make a memory pool for SABs, to start building shared persistent data structures on top of https://twitter.com/Doxosophoi/status/1236337446729719810

Lone Ranger23:04:22

Yeah @U050PJ2EU this is really fascinating stuff. I hope they fix the speculative execution vulnerability soon because there are so many great applications for this.

Lone Ranger23:04:22

I'll certainly be watching the project!

john23:04:50

Yup! Once you have a working, good lock-free mem pool on top of sabs, with weak references for managing clean up, we should be able to build a datascript like thing on it and do exactly what you described.

john23:04:00

What I think is most fascinating is, down the road, as latencies continue to drop, actually reimplementing the SAB interface, so that workers can attach to SABs via network. Then you could do some really interesting distributed systems stuff with just that abstraction.

john23:04:49

Like, if you're in a datacenter and can ensure low latency data access between a few million workers

rgm16:04:44

Can anyone recommend a cljs-compatible graph library? I see loom and ubergraph are clj-only, and it’d be just swell for my life if there were a clj and cljs version of loom.alg/dag? lying around someplace https://github.com/aysylu/loom/blob/0d4d74ad90acb3b1d3d0a1515f68caf482c66600/src/loom/alg.cljc#L254-L257

rgm16:04:15

(not that I couldn’t port, I suppose)

noisesmith16:04:27

when I last worked on a cljs library we just used a js graph lib

rgm16:04:39

:man-facepalming:

rgm16:04:45

right, those exist.

noisesmith17:04:38

but this was a special case, we were doing a lot of performance intensive graph ops in our app (it was the premise of the app really) so we needed raw perf in the fronted more than the convenience of immutability / not using interop / having a predicatable well designed clojure friendly api

noisesmith17:04:13

we used the graph parts of d3

rgm17:04:50

ok double :man-facepalming: I’m already using D3 and js/d3 is defined. Wrapper fn it is.

noisesmith17:04:59

if all you need to know is whether a graph is a dag, you could port that from loom or ubergraph

rgm17:04:10

thanks; total JS lib blindness there.

noisesmith17:04:37

quick google finds this which looks fun https://github.com/erikbrinkman/d3-dag

rgm17:04:59

I’m mostly shy about porting because I’m very capable of screwing up recursive &/or graph code in ways subtle and unsubtle but should be alright if I have some reasonable deftests.

noisesmith17:04:06

(but you don't need the layout, just the underlying graph functions)

👍 4
🙏 4
noisesmith17:04:32

you could also just re-implement that one js function in cljs

noisesmith17:04:57

(if you meet their license requirements for doing that of course :D)

Takis_17:04:01

is it possible to have this kind of autocomplete in Clojurescript?i try to use mongodb nodejs driver,i asked yesterday also but still i cant find the way to do it.

grumplet21:04:27

@dnolen. My first naive reaction on seeing your webpack integration was Wow! - would this get me access to some of those crazy bloated UI libraries that are hopeless without webpack? So I tried adding antd to your hello-bundle starter - and yes it worked! Still rather bloated though - it took a 275kb reagent image to a hefty 1.88Mb with the inclusion of just one DatePicker. I think that’s better than without webpack (I remember around 6Mb last time I looked). Maybe still on the high side of usefulness.

grumplet21:04:14

@dnolen I remember that the icons take a lot of room in that library, so stated looking at the separate @ant-design/icons package. No idea why they have to start the package name with ‘@’, but of course that causes cljs to complain. Any thoughts on a getaround for crazy npm package naming issues?

Roman Liutikov21:04:45

@grumplet Nothing has changed in regards of optimizing JS dependencies, they are not going through Closure Compiler, it's just that with the new compiler target Webpack itself can consume compiled cljs code and put it into a bundle together with JS deps.

Roman Liutikov21:04:10

> I think that’s better than without webpack (I remember around 6Mb last time I looked). but you are right here, Webpack will try to shave off from JS deps as much as it can

Roman Liutikov21:04:29

it's better than packaged cljsjs library that you can't do anything with

grumplet21:04:42

Ah ok - maybe it’s just easier to integrate with webpack in this version though? I always had difficulties before and avoided it.

Roman Liutikov21:04:09

also might be interesting to try RollupJS instead of Webpack and see if Rollup does a better job at dead code removal

grumplet21:04:18

Worth a try… @roman01laany thoughts on how we might get round the crazy @naming incompatibilities? Is there some way to alias those packages perhaps?

Roman Liutikov21:04:33

I think you can use string requires from cljs (require '["@ant-design/icons" :as icons])

grumplet21:04:08

Like shadow-cljs syntax

ingesol06:04:42

As @dnolen pointed out to me, it’s not shadow-cljs specific, it’s part of core cljs. I never used it before now, so I thought so too. That said, if you want to you can alias deps in your package.json to make them look more cljs-friendly.

grumplet07:04:27

Good to know - thanks for the tip!.

Roman Liutikov21:04:28

@ thing is NPM's artifact groupid

Roman Liutikov21:04:49

@my-group/my-project

grumplet21:04:20

I’ve been out of that world happily 🙂

grumplet21:04:33

But thanks will look into it!

Roman Liutikov21:04:26

I dunno what's better tbh, to be outside of that world and constantly feel lost or suffer and learn everything about it 🙂

Roman Liutikov21:04:51

and still feel lost most of the time lol

grumplet21:04:24

too right - though you seem to cope. Really happy to see all the work you’re putting into Rum.

grumplet21:04:54

@roman01la Just confirming your syntax suggestion worked fine. ["@ant-design/icons" :refer [StarOutlined StarFilled StarTwoTone]]

🎉 4
Spaceman22:04:30

I'd like to run clojurescript tests using https://github.com/lambdaisland/kaocha-cljs kaocha-cljs. So I put the [lambdaisland/kaocha-cljs "0.0-71"] dependency in my lein project.clj, and restart the repl and run the command in the root directory:

clojure -m kaocha.runner unit-cljs
But I get the error:
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate kaocha/runner__init.class, kaocha/runner.clj or kaocha/runner.cljc on classpath.
Why would this be, and how can I fix this?

andy.fingerhut23:04:53

I haven't used that before, but in general clj and clojure commands read your deps.ednfile to determine what dependencies your project has, and lein commands read your project.clj file, and neither command will read the file of the other.

ingesol06:04:42
replied to a thread:Like shadow-cljs syntax

As @dnolen pointed out to me, it’s not shadow-cljs specific, it’s part of core cljs. I never used it before now, so I thought so too. That said, if you want to you can alias deps in your package.json to make them look more cljs-friendly.