I'm stuck. I'm trying to read an ES6 file that basically just contains a data structure. If it was JSON I could parse it that way. I suspect this is possible, but I'm not a ClojureScript expert and don't know where to start. My Google search results are not too fruitful and I'm wondering if I'm going at it in the wrong way?
read it at runtime or use it during compile time to use in your app?
I would say compile time, although it's an intermediate step to use it in Clojure. I'm trying to do infrequent conversions from such .js files to .edn for use in my main project (Clojure), so I figure it can be considered to be compile time. I started looking at ClojureScript because I couldn't find tools just in Clojure and figured ClojureScript does this all the time, somehow, if I'm not misunderstanding. I just can't figure out how exactly I would go about it.
Nice, so I got some time tonight to play around/figure out doing this. Wish I had rather spent Friday doing this! π
Assuming you're using shadow-cljs, it should be possible, I think: https://shadow-cljs.github.io/docs/UsersGuide.html#_requiring_js
You just require that JS file and use it via JS interop of just convert it with js->clj
.
π Thank you, this is most helpful. I'm going to have a look. I've parsed it by hand using regex as the structure was simple enough but it's not sustainable π I have to get a real solution.
What do people use for UI test automation? Because I am struggling with puppeteer, I get different results in headful and headless mode and it's impossible to know what's different.
Somewhat off-topic but is anyone here using https://headlessui.dev/? What are your thoughts? We use Tailwind CSS and think it's brilliant so we're biased to think that Headless will be great too.
@ashnur fwiw I don't believe in UI test automation
too much work too brittle
a better approach to higher quality UI work is to adopt a pure functional UI
and for all components to be fully tested for the meaningful states in total isolation from all business logic
Storybook.js and Devcards permit this style of UI development
then any UI issue that crops up had to been business logic
not components
and the business logic is easier to understand/discern
QA is necessary of course
and maybe UI test automation can catch some QA issues - but I doubt it
any serious app needs to run on too many different platforms, too many differents OSes etc.
it's a waste of time
meaning the effort to set it all up is just enormous
vs.
what I'm saying above which is prevent writing bad code in the first place
and then when you get to QA and human has to drive it - it's meaningful testing - not BS
I'll reiterate something I've said before
Devcards or Storybook.js is probably the most important change I've made to UI development since the appearance of React
nothing else I've tried has been as transformative since ClojureScript+React
Thanks for taking the time to answer @dnolen. I am not writing these tests to achieve, as you write, 'higher quality UI', I am trying to not have to do these simple checks manually because it takes much more time like that.
sure but I'm just saying - you're not going to save any time
well maybe you will, or think you will
but I've never been able to get it save me any time in 16 years
I am going to lose quality of life if I have to repeat the same 10000 actions every day
so even if you are right and I am wrong about how much time it takes overall, the time I spent waiting for the tests (and writing them) to run is qualitatively different than the time I spent manually testing (and making humanly understandable but professionally very deteriorating mistakes)
but the question you should be asking
Agree with dnolan, automated ui testing ime is always greatly more effort than reward.
is why do you need to go through a flow
again and again if it's not QA
i.e. pre-ship time
because if I repeat the same actions, I will make mistakes, and get many more false positives and false negatives
everything you do should be setup so you don't have retest anything
it is pre-ship time
right there is no good answer for pre-ship time that I've seen other than manual QA
maybe AI one day
lol
sorry, I can't restrain myself when people idolize AI like that
but that's beside the point, I see that people do not have the same problems as I have, again
that was meant to be joke π and half-serious
as in I don't see how it can be solved
π
with existing methods
I know, I shouldn't be trying to create a fixed experience in the first place, people on the other side, using their own browsers should decide how the interface looks like, not us
but that's again, beside the point. I have very good experience with UI automation, I even used it in property based testing
this is the first time I have a redundant problem like this
another issue is when testing advanced compilation code - how can one do this without using a headless setup?
in like 7 years
@dnolen fww, i did try to use devcards and storybooks but 1. neither worked well with react hooks the way I tried 2. after I did the nice components there, I had to insert my react code into the actual Django templates from which they are served and they got wrapped into this minimized css that the company had for 7 years now and it's not being touched, don't even have the un-minimized source for it afaik, and of course the major business logic is not how things look but how things interact, and since it's not just a REST api but also cookies and other parts of the page define the context, I really didn't see any point to not develop the app inside the page where it will appear anyway. This way at least I can test it when I am working on it. But because testing means testing with all kinds of different users that I have to create manually because there is no other way, most of the time I am not actually testing my work, just "preparing the backend state" for testing, because that defines fully the frontend state.
I did build a functional UI on datascript and mori and mercury in 2015 2016, the two packages had to be compiled together, and it was really verbose to use them from js at the time, but it worked nicely, didn't have to test the UI by actually clicking on things to see if they work
@ashnur huh I don't understand your point about React Hooks, we use those those w/o issue
but note we just write our components in JS
I just don't believe in writing components where they are going to be anymore
it just NxN problems
vs. N
In your case that N may be large - and maybe, in this instance UI automation is going to get you something
yeah, I am not testing components, I have about a dozen files, each just opens the page, performs a bunch of user actions on the whole page and reads content of the page
I see zero sense in testing components out of their context, they are never actually used like that in practice.
we use CLJS + hooks + storybook in our apps
how do you write reusable stateful components
we also use react-testing-library to test our components in isolation
think something that handles a predictive input with arbitrary input text allowed
π€·:skin-tone-2: same way we would build any reusable stateful component. use local state inside the component, provide props to control the behavior
yeah, so where is the local state, in a use-state hook in the top component?
the link to headlessui.dev above is a good example of that
yeah
so, when you are in your editor, there is probably some repl connected to the browser runtime env?
um, yes when I'm developing in our app project I typically have a REPL connected
the REPL connection doesn't work with our storybook setup, but we mainly use it for documentation of our design library
and can you read current state of any shared component through your editor? I've been trying to see an example of that, especially with Storybooks
I typically use React DevTools + the JS console to inspect the state of React components
I have experimented with adding REPL support for inspecting the React tree but haven't found a really good interface to use it yet
I use (tap>) and shadow-cljs has a web ui where it is nicely browseable
and of course react devtools
the only solution is to not use hooks, this is why I said I couldn't make it work
@dnolen βοΈ:skin-tone-2:
I only mean state hooks, not effect hooks
so obviously use-ref would work fine, but it's really a hassle to set it up, and I am very much dissillusioned with react since they removed resuming
sounds like it's not that it didn't work i.e. you couldn't build an app with it, but that you didn't like the developer experience
which is fair
I find that using component local state is architecturally better for us so I'm willing to live without the ability to easily use the REPL for inspecting local component state
well, you have to choose, if I am not using react hooks the obvious choice is to not use react at all or use reagent
my issue with local state is this page https://reactjs.org/docs/lifting-state-up.html
or more specifically, this issue answer https://github.com/facebook/react/issues/11527#issuecomment-360199710
> I want to highlight that in typical React apps that rely onΒ `setState()`Β this isΒ the single most common kind of React-specific refactoring that you would do on a daily basis.
I just don't want to.
hrm I'm doing mostly React Native these days
I didn't find any of the React Native "tools" useful
so I don't know - I'm a minimalist
can I ask the same question from you? do you use atoms or something else for reusable component state?
reusable in the sense that the same namespace is used multiple times throughout the page with different state, but the logic is implemented only once and then gets required and filled out by other components
all components are written in JS, verified on the device and simulators via Storybook.js
all styling and theming is done via React context
all components are Pure Components, using hooks for state only for internal stuff
everything comes in via props
everything most compose and must be representable in Storybook.js
if you cannot create the state in Storybook - then it can't be created at all
once this cycle is done
we just adapt them to Reagent components
then the "app" is only like a thousand lines of ClojureScript code
even you have many screens and many states
the ClojureScript code has no styling, no theming
no presentation logic of any kind
other than the highest level structure
all routing is done via 10 lines of core.match
any internal route is handled because none of the Pure Components have subview order
so you can make the flow state machine w/ a ClojureScript map
and change it to be any order you want
the only thing of interest here is that it's shockingly simple
and probably this has lead to fewest bugs I've encountered on a UI project myself
nearly all issues stem from larger integration problems - but that's to be expected
sounds like a dream project π
it would be nice to replace the Storybook.js stuff w/ ClojureScript but in the end it really doesn't matter much
if you write only Pure Components it's feels more or less like ClojureScript
no data transformation of any kind is allowed
because of the ES6 iteration protocols, everything more or less works
we have one tiny clever thing w/ React Context which we inject from CLJS to convert props at Pure Component boundary (since this is nested React components not nested Reagent components)
but that was a couple of lines of code
we did the same thing at my last company. design library in JS + storybook, product used CLJS
however, the major reason we did that is we had other consumers of the design lib that had been written in JS
was wondering about that boundary between js objects/arrays and cljs immutable types
i imagine cljs-bean comes in handy?
An approach we are taking at work for e2e ui testings is allowing the test runner to introspect on the client state. This allows us to assert directly on app state instead of derived views. That also allows us to synchronize our ui interactions when we know the app is in a good state. Of course, the big assumption we make is that the mapping between app state and views is correct, which we mostly validate via unit tests.
Essentially the code looks like:
(defn e2e-test [driver user-story]
(loop
(let [state (get-state driver)
thing-to-do (next-thing-to-do state user-story)]
(do-the-thing! driver thing-to-do)
(when-not (done? driver user-story)
(recur)))))
The nice thing here is that the user-story and state are both just data and the thing to do can be wait for now cause I can't currently do anything
I thought about that, but because this is embedded in a django app and sometimes I need to check if things become disabled or enabled, checking the state might not be enough
@djblue right's more or less what I'm trying to suggest
if your components are in Storybook.js that's strong evidence of the mapping
then you can just write simple tests about state transitions about data
there are limits for our app though
because we have a lot of native code integration, remote services
and I'm not fan of mocked tests
In my code example above the driver is a handle into a browser that's connected to our development environment so the app has access to all necessary services and we don't need to mock anything, and we can test actual integration at every level
Another point of note here is that the user story itself is actually a subset of the app state. This means we can leverage our UI to also update the user story when things do change.
Hello There, I am having problem setting the dates in ClojureScript, for some reason the application is keeps on setting previous date.
{
:start-date (js/Date. start-date)
:end-date (js/Date. end-date)
}
Is this the correct way of setting the time?
When I change my computer timezone to different location, the application timing starts working fine.
(println start-date)
-> #time/date "2021-05-10"
(js/console.log (js/Date. start-date))
Sun May 09 2021 20:00:00 GMT-0400 (Eastern Daylight Time)
Any help would be appreciatedWhat do you mean by "setting the time"? Setting it where, exactly?
for example I have #time/date β2021-04-21β I am trying to convert this to as javascript new Date()
It is that js/Date
, most likely. It's just that println
prints it that way.
It's OK for println
and js/console.log
to output things differently.
is there any js/Date build in function in clojurescript that converts as following #inst β2021-04-21T00:00:00.000-00:00β
I don't understand what you mean.
You need some function to convert X to Y. What's (type X)
? What's (type Y)
?
Just in case, here's my REPL:
cljs.user=> (js/Date.)
#inst "2021-04-20T18:58:34.940-00:00"
what do you mean?
when calling cljs functions from js, ensuring that arrays becomes vectors, objects become maps, etc
So you write JSX as opposed to using React CLJS interop?
If youβre doing anything more than a trivial thing around dates, consider using a library.
Works the same both in CLJ and CLJS, which is great.
it depends. I typically don't see the point in transforming to and from unless it's a necessary to interface with a particular part of a system
i.e. if I'm getting some JSON from an endpoint and want to operate on it immutably in my UI, I'll do that transformation once on receiving and store it that way
or, if I'm using some 3rd party library that takes as input a JS object based on some immutable data I have in hand, then I'll manually write the construction of the JS object
clj->js
and js->clj
is a huge code smell to me IMO
sometimes it doesn't matter, but too often it can lead to errors or performance problems
we have a query analyzer that we added in to the frontend. and it of course "speaks" clojure, being built in the backend. and the frontend is a react js app. there's a huge boundary of arrays and objects and those js types can't really flow through the backend
so it makes sense to put a boundary layer, strings to keywords in some places, arrays to vectors, etc
yes, in that case I would make the layer very explicit
it's very tempting to just (js->clj x :keywordize-keys true)
and call it a day, but it makes it much more difficult to control the translation
you might find that the way the UI expresses certain things doesn't quite add up to what the analyzer expects and you end up having to translate it after the fact anyway