This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-02
Channels
- # beginners (29)
- # boot (65)
- # cider (12)
- # cljs-dev (8)
- # cljsjs (31)
- # clojars (5)
- # clojure (147)
- # clojure-austin (47)
- # clojure-berlin (1)
- # clojure-brasil (7)
- # clojure-russia (5)
- # clojure-spec (18)
- # clojure-uk (18)
- # clojurescript (113)
- # css (2)
- # cursive (7)
- # datascript (5)
- # datomic (2)
- # dirac (4)
- # events (3)
- # funcool (143)
- # hoplon (287)
- # jobs (2)
- # off-topic (4)
- # om (10)
- # om-next (5)
- # onyx (18)
- # protorepl (1)
- # re-frame (93)
- # reagent (34)
- # rum (41)
- # test-check (51)
- # untangled (15)
- # yada (18)
@candera i was playing around with an svg animation myself, but ended up moving to pixi js instead >.<
Yeah, I was using canvas in my last version, but switched to SVG. I like how it’s declarative, and it’s a better fit with Hoplon. Based on looking at the API very briefly Pixi seems to be very imperative - do you find it so?
yeah the svg/hoplon fit was really good
my first pass with pixi is definitely full of imperative stuff, mutation and callbacks
but the animation looks noticeably better when you a/b
I still have some imperative reaction to cells changing in order to get reasonable performance. But less than I did with canvas.
i think i need to play around with it a bit
there are certain things, like tweening, that make it look worse because they’re rather low level
It’s amazing any of it works in a browser at all, let alone approaches what we had in C++ a decade ago.
but yeah, i’m using a lib for tweening but could probably use a cell= if i thought about it
with hoplon i think you can really make it nice, hide all of the imperative stuff really well
So, I think it’s entirely possible that Javelin itself is a tiny fraction of what I’m doing, and even a 10x speedup would be unnoticeable.
Like I said earlier, the gains I could get from going to WebGL have kept me from bothering to optimize.
@candera try the timeline tab?
ah, timeline is a different tab
looks more like this
you can see the rendering and painting
Yeah, I’m looking at something like that. Is that Chrome? Anyway, looks like the dominant costs are in DOM calls to update the grid. That’s the imperative bit I was talking about.
this is chrome
there are two tabs next to each other
profiles and timeline
same animation, different approaches
you can see more info about what’s going on with the dom rendering
a relatively even split
you could try messing around with css transforms, etc?
cool 🙂
@thedavidmeister: were you doing some more work on the hoplon unit tests recently? i got some selenium unit tests running on sauce labs.
ah actually i was going to suggest moving the hoplon tests to cljs tests
i’ve got working code for that in my project, but haven’t put a PR up for it
like, doo
my tests look more like this now
(deftest ??email
(let [email? (fn [el a t]
(is (dom.traversal/is? el (str "a[href=\"mailto:" a "\"]")))
(is (dom.traversal/is? el "a.email"))
(is (= t (dom.traversal/text el))))]
(email? (email) el.email.config/default el.email.config/default)
(let [a "as;lkfj"]
(email? (email a) a a))))
where dom.traversal
is just a thin wrapper on jquery
and the email
function is just a defelem
@jumblerg main advantages are speed, more “unit-y” and ability to directly inspect things like the state of cells
it’s basically the difference between firing up a browser that has a hoplon page in it and trying to inspect that with another tool like selenium
and firing up phantomjs and using it to run tests against itself and report on what happened
it looks like these might not be ideal for cross-browser testing though - are they just executing js in rhino or phantomjs?
yeah no cross browser testing
tradeoffs though
the selenium tests i had were ~15 minutes and they now run in about 6s in phantom
although, actually that’s a lie
the tests i just added are for exactly that: i need to check the rendered output on each supported browser/os for ui. but i'm running them all remotely on sauce labs now.
doo supports karma
i did get it set up
it just takes a little extra fiddling
- karma-chrome-launcher
- karma-firefox-launcher
- karma-safari-launcher
- karma-opera-launcher
- karma-ie-launcher
it worked fine for me, but at the time i wasn’t using it for cross browser testing per se
moving away from selenium doesn’t mean losing other browsers, it’s just a different approach
selenium is like a simulation of a user poking and prodding things in a browser to see what happens (but the user can only see the rendered result)
doo is like running a script in that browser and the script happens to be a test
so for unit tests, i’m suggesting doo is a better approach
but for end to end tests, selenium is what i’d use
that i don’t know, sorry >.<
it’s used by angular though, so i’m sure there’s decent support around the place
so now i can:
$ boot test
Classpath conflict: org.clojure/clojure version 1.7.0 already loaded, NOT loading version 1.8.0
Starting reload server on
Writing adzerk/boot_reload/init3863.cljs to connect to ...
env: loading "cnf/local.env"
Starting file watcher (CTRL-C to quit)...
Writing HTML files...
• index.html
Adding :require adzerk.boot-reload.init3863 to index.html.cljs.edn...
Compiling ClojureScript...
• index.html.js
Testing hoplon-test.ui
testing with (:chrome "26.0" :windows "7")
Jan 01, 2017 9:26:31 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Attempting bi-dialect session, assuming Postel's Law holds true on the remote end
Jan 01, 2017 9:26:39 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
testing with (:firefox "4.0" :windows "7")
Jan 01, 2017 9:26:44 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Attempting bi-dialect session, assuming Postel's Law holds true on the remote end
Jan 01, 2017 9:26:50 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
testing with (:iedge "11.0" :windows "7")
Jan 01, 2017 9:26:51 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Attempting bi-dialect session, assuming Postel's Law holds true on the remote end
Jan 01, 2017 9:26:56 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
testing with (:iedge "14.14393" :windows "10")
Jan 01, 2017 9:26:56 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Attempting bi-dialect session, assuming Postel's Law holds true on the remote end
Jan 01, 2017 9:27:15 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
testing with (:safari "7.0" :osx "10.9")
Jan 01, 2017 9:27:21 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Attempting bi-dialect session, assuming Postel's Law holds true on the remote end
Jan 01, 2017 9:27:36 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
Elapsed time: 90.233 sec
you can use them together
they’re tackling different aspects of the problem
looks like people use VMs with karma to get around the ie thing locally, fyi
yeah, that's what i figured re ie, which i just don't want to f with: much easier to rely on a hosted service for this, where we can get just about any permutation of platform (to include mobile) and browser we want.
"Karma is not a testing framework, nor an assertion library. Karma just launches a HTTP server, and generates the test runner HTML file you probably already know from your favourite testing framework. So for testing purposes you can use pretty much anything you like."
yeah, you should totally keep using sauce labs
they’ve been around forever too
i’m just suggesting that selenium might not be the best tool for writing/managing unit tests specifically
but i didn't really do my homework ahead of time. coded first, now i'm asking questions later.
based on my personal experience of that being difficult, slow and flaky 😛
they were pretty miserable when i was running them locally, and there was quite a bit of config-hell.
yeah, i actually quite like selenium, it’s a messy tool but it’s doing a messy job
but i only like it for what it’s designed to be used for...
once i switched to sauce labs it really sped up. now i save a file and the watch task fires to run them; it takes about a minute for them to be tested on the minimum supported version of all five browsers.
i haven't written any serious tests in practice yet though, mostly i'm just making sure google is there.
you might as well keep doing what you’re doing
when you say unit tests specifically, are you thinking more along the lines of testing an api as opposed to rendered dom output?
no, i mean testing attributes of dom (hoplon) elements and cells individually, rather than testing a page holistically
so, say i have a button that i pass a cell to, and clicking that button should change the value of that cell from false
to true
- i can actually check the value of the cell before/after
in my case, for ui, the thing i'm most concerned about is layout - making sure that when an elem is vertically aligned to the center, for example, it is in fact in the center in all the browsers.
aaah so you’re doing screenshots?
aaah cool
i’ve heard good things about https://ghostinspector.com/ too
haven’t used it personally yet
yeah that’s much much nicer than raw selenium output
i suppose you get what you pay for 😉
to do this right, we need to get it synced up with travis. esp for ui, where we need to catch any layout regressions asap associated with each contribution.
well tbh, i was working on it, then i went off and did my own thing, learned a bunch about everything i was doing wrong, and am not sure quite how to proceed with hoplon now 😛
i definitely now think that hoplon itself would benefit more from doo style tests than selenium, as you’d use something like ^^ to confirm visual and end to end things
it would be great if we could coordinate something, and get the same basic solution in place for both.
which makes more sense for a layout system like what you’re working on, or an actual user facing product
but trying to write comprehensive tests against hoplon core without, for example, being able to inspect the state of a cell, would get messy real fast
ok, well, in my mind atm:
- i think you can use sauce labs for both doo and selenium, as it’s just hosted browsers at its core
- selenium probably makes more sense for hoplon UI than hoplon core, where i think something more low level like doo is appropriate
- i was wondering if we should move from travis to circle ci, as i’ve found debugging, etc. a bit easier on circle in general
i’ve got examples of running clj, cljs and selenium tests in both travis and circle
but i got confused about the way github/circle interacts across PRs on forks
and stopped because i didn’t want to break anything
i wonder if things cljs.test would be good to use at the interfaces of libs like javelin, castra, etc where there are programmatic apis, but selenium better for testing libs that produce user interfaces.
probably yeah
some things maybe a split, like 90% cljs and 10% selenium
there’s no reason you can’t mix and match
i think the important thing to keep in mind is just that, while selenium gives you some super powers like videos and screenshots, it does come with significant time overhead and you lose visibility into low level state of the app
i don't think visibility into the low level state of the app is necessarily something we want though, based on the assumption that the purpose of these tests is not to debug, but simply identify errors. i tend to think that, in the case of any unit tests, we only want to test whatever the interface of the library in question is.
¯\(ツ)/¯
they can be whatever you want them to be
i think the focus should be on covering an interface's surface area, but without going to much deeper than that.
that’s certainly important
i just test whatever i think might break 😛
i don’t worry too much more about it than that
i generally don't unit too many things at all, especially at the application level. i typically find the cost of the overhead to outweigh the benefits.
even in the case of libraries, my applications happen to double as some pretty comprehensive tests (at least of the things i care about)
i guess i just write things weirdly
i’ve never not found a bug when i introduced tests to something
yeah well, i’d rather a robot trip over that tree than a user
nah, it’s often pretty obvious stuff
maybe i’m just bad at writing code 😉
but also, it’s kind of like the whole live reloading thing
but ui is a little different, because it is intensive to manually inspect and identify things like all the different layouts on each change to the box model.
you can write code in a way that’s super easy to test certain things about it
and you can write code that makes it near impossible
i personally find that i have fewer bugs if i write code that would be easy to test, even if i don’t write the actual test
so sprinkling some tests around keeps me from getting lazy
i’ve definitely worked on codebases where, not only do they really need tests because of the complexity of the whole thing, but writing tests was so hard/time consuming that it took more time than the code
it can be really depressing >.<
but i really like hoplon because it’s actually super simple to unit test, if you feel so inclined 🙂
definitely the intricacies around the box model are a great example of something complicated that you don’t want to test by hand 😕
yeah, it is one of the cases where i think a tdd approach might actually prove to be the more efficient use of my time.
or you can take the “write a test when it breaks” approach 😛
tdd lite
on a totally different topic...
how do you actually get rid of cells?
trying to replace tween.js with a cell= tied to requestAnimationFrame
i don’t really know how to deal with the tween finishing
@thedavidmeister can you elaborate a litle more? intrigued but don't know quite what you mean
@alandipert aaah like, i made a thing with webgl that draws circles and i want to tween their scale
looks something like this
(doto (js/TWEEN.Tween. (-> c .-scale))
(.to
(clj->js {:x next-scale :y next-scale})
animation-speed)
(.onUpdate #(this-as this
(-> c .-scale (.set (.-x this) (.-y this)))))
(.onComplete tween-scale)
(.start))))]
(letfn [(frame [t]
(.requestAnimationFrame js/window frame)
(.update js/TWEEN t)
(.render renderer stage))]
(.requestAnimationFrame js/window frame))
my gut tells me this could be replaced with something along the lines of
(defn position-cell
[t duration]
{:pre [(cell? t)]}
(let [start @t
end (+ start duration)]
(cell= (when t (/ (- t start) (- end start))))))
(defn interpolation-cell
[from to position]
(cell= (+ from
(* position (- to from)))))
something, something...
so iirc RAF takes a callback as an argument, right? and the callback is called with a timestamp
looks like thi TWEEN library helps generate the callback?
yeah, it’s pretty much like setTimeout
but it gives you a timestamp when it feels like it, rather than you giving it a delay
so the tween lib’s main thing is to take a timestamp on “update” and then it interpolates numbers for you
based on how close the timestamp you give it on update is to the timestamp that is when you want the tween to finish
and then some callback when it finishes, which in my case i’m using to immediately setup a new tween
so you get a looping animation
i see
i’m not tooo bothered about the whole timestamp management stuff, anything that keeps y in a fixed ratio with x as i vary x is good enough, as long as i can “finish” somehow when x goes out of bounds
i can see how separating reads and writes by making the callback dumb, ie it just resets a cell, is maybe good
and then the interpolation logic is hung off that cell
https://github.com/pleasetrythisathome/bardo is a thing i remember
it can do fancier interpolations
like easing
ooh i’ll check this out
this is as far as i’ve got
(defn animation-cell
[from to duration]
(let [t (cell nil)
p (position-cell t duration)
i (interpolation-cell from to p)]
(letfn [(frame [tick]
(reset! t tick)
(.requestAnimationFrame js/window frame))]
(.requestAnimationFrame js/window frame))))
that's cool
altho i can imagine, you just need one cell and one RAF thunk thing
and then all your animations can be hung off that one global cell?
i want everything to be local to the circle
i’ll probs have a few hundred circles
i imagine it would be private in the NS you dedicate to this
the thing it that approach helps with is latency
since you only have one thunk enqueue at any given time
vs. at least 1 per animation-cell
i used similar technique recently for basic interpreter w/ settimeout
i’ve been using the ndarray from http://thi.ng to build a grid of circles so far
i could tie the interpolation logic into rebuilding that grid
as in… i could make a cell= that is just a map of the above logic, essentially
across a seq of position and interpolation cells that all have the same t
so yeah, let’s say that t
is global but the other cells are specific to the individual circle 🙂
(def t (cell nil))
(letfn [(frame [tick]
(reset! t tick)
(.requestAnimationFrame js/window frame))]
(.requestAnimationFrame js/window frame))
(defn animation-cell
[from to duration]
(let [p (position-cell t duration)
i (interpolation-cell from to p)]))
@alandipert so i can probably make new animation cells with callbacks
(defn animation-cell
[from to duration cb]
(let [p (position-cell t duration)
i (interpolation-cell from to p)]
(cell= (when (< 1 p) (cb)))))
seems good, although, i'm wondering
is it important that the RAF callback does the work?
but then how do i stop animation cells piling up everywhere?
oh nvm i just realized, it still is .even if all it does is update a cell
oh the animation cells are ephemeral?
well i don’t know
that’s the bit i’m unsure of the best way to tackle
if they should be, maybe they somehow destroy themselves depending on some condition
like, do i try to make them reusable as a lens somehow, or try to make new ones and throw the old ones away, or something else entirely?
not sure, tho it's not clear to me cells are a great fit for this problem
but i've never used RAF or even done animations in browser other than via svg
cell= seems like a great fit for the tweening part to me
locking a ratio of some value (scale) to another (timestamp)
i just don’t know what to do at the end 😛
i guess the animation knows when it's done, right? it has stopped moving
as soon as p = 1
it’s done
so maybe when the prev val was equal to the new one, it destroys itself
a cell that destroyed itself would be a new one
actually, now that i think about it, that might cause chaos downstream 😛
it should just be the final value forever
maybe it detaches itself from the cell graph but keeps its last value?
but also not incur calculation overhead recalculating the same final value every frame
ie becomes constant
like, it converts from a cell= to a cell
maybe a lens is what i want
so the setter is the start/end vals and delay/duration ms, + a callback
and the getter is the interpolated values from the global t, or a constant if p
>= 1
@alandipert cheers for talking that through with me 🙂
i’ll see how i go
sure! fun problem
still not confident i'd use cells for this, but it's fun to think about 🙂
experience has shown that it's hard to make things worse by adding cells
@alandipert think of it like “cell that you can reset! but it takes its time to get there"
actually, that might be simpler, not worrying about a from...
@alandipert https://gist.github.com/thedavidmeister/563b86e4bc18d3aa27c89b9dc3ad5248
seems to work ok
woah, very slow though
@micha welp, i just made something that thrashes javelin pretty hard if you want profiling info ^^
I'm adding a Hoplon profile for Luminus, and I got a bit stumped on how to render an HTML string directly here https://github.com/luminus-framework/luminus-template/blob/41f90139eb7cc038d5643effcdf6278304a3b956/resources/leiningen/new/luminus/hoplon/src/cljs/core.cljs#L52 also, if anybody could let me know whether I'm doing anything else that's not idiomatic that would be appreciated as well 🙂
@yogthos (h/div :html (cell= (md->html docs))
I also recommend using defelem
any time you want a "template" of elements
instead of defn
although in cases defn is fine, when you make elements more complex you want the features of defelem
what version of hoplon?