I have something to confess: I haven’t written any ClojureScript tests until this very morning. There were various reasons for that and often I would copy whatever was possible to Clojure namespace and test it there using clojure.test. So when a new ClojureScript with a port of the clojure.test namespace – cljs.test – was released, I could no longer ignore it.
I wrote some tests, I googled for information on how to actually run them, and I hit the wall. Most of the posts were outdated and if it weren’t for Andrew Keedle‘s post on basic cljs.test setup, I’d probably be still banging my head against the wall.
I like open source projects, and I like Travis CI (which is free for open source projects), so the next step was quite obvious:
Set up ClojureScript tests with Travis CI
1. Add .travis.yml
script: lein2 cljsbuild test
If you followed Andrew’s post you should have phantom directory in your project already, and unit-test.js and unit-test.html within it.
With this setup you can now either continuously test your project by running lein cljsbuild auto test (tests will be run whenever you save changes to your project) or you can run your tests manually by executing lein cljsbuild test. The latter option will be invoked by Travis.
For a real life, but tiny, example you can go to my is-it-time repository.
Thanks to good people at Cognitect and the sponsors of the Opportunity Grant I had an opportunity to speak at Clojure/conj 2014. It was the second time I’ve given a talk, and a fourth tech conference I attended. And it’s been amazing!
The venue, Warner Theatre, is the most beautiful conference venue I’ve seen. Just look at this photo! It might have been a little cold, but nothing that hot coffee or tea wouldn’t fix.
The talks were awesome, speakers well prepared and approachable and organisers friendly and helpful. I’m very glad my talk was second on the first day as I could just sit back and take it all in. And there was a lot to take in. Eye-opening talk about data-driven systems by Paul deGrandis, brain melting introduction to persistent data structures by Michał Marczyk, very educational talk about variants by Jeanine Adkisson, hilarious walk through game development by Zach Oakes, two amazing keynotes and lots of other talks left me with a long TODO list. There’s so much I want and need to learn and I’m very grateful to all speakers and attendees for sharing their knowledge and experiences. You can watch all talks on Clojure TV YouTube channel.
But as we all know people is what makes for a great conference. We can watch the talks online but we can’t talk to the speakers and other attendees, be challenged, go through “a-ha!” moments or have a small hackathon in the hotel lobby. We can’t make new friends and new interesting contacts. And being at Clojure/conj provided me with all the above. I’ve said it before, and I’m going to say it again: Clojure community is the friendliest community I’ve experienced. I felt very welcomed and supported both as a speaker and attendee. And I felt safe and treated like an equal. I truly hope other communities will follow in our footsteps because nothing inspires more than a room full of smart people who don’t try to prove their superiority but share their knowledge instead. We all have a common goal after all: improve technology, improve industry, improve our lives and ourselves.
Dinner with the Lambda Ladies, sponsored by the kind people at Living Social was a blast too! Lots of good advice and laughter – I hope it won’t be long before I see you again!
I’ve returned to London energised, with some great memories that I play on repeat in my head. I hope this state of mind will last a little longer or at least till the next event.
Thank you everyone who made Conj so memorable – I hope we meet again!
It’s been a while since the last post. More mistakes have been made, lessons have been learned, so here’s a handful:
Make sure you’re updating the cursor and not the map that combines them.
Let’s say you want to create a component that has a view of bands and titles of films. You don’t want to pass whole of the app state, you just want to pass :albums and :titles. You combine them like this:
Sometimes you may forget the protocol implementation or you may provide something that doesn’t match the method signature. If you see no meaningful errors coming from the compiler, upgrade ClojureScript.
ClojureScript compiler warns you nicely about the mistake:
WARNING: Bad method signature in protocol implementation, om/IRenderState does not declare method called render at line 159 src/cljs/pumpkin/core.cljs
I remember seeing java.lang.IndexOutOfBoundsException which was caused by missing protocol implementation. Upgrading helped. Try to stay up to date with both Om and ClojureScript. You’ll see more meaningful errors and warnings.
Don’t do computations in render
If you need to group-by, or do other sorts of data transformations, it’s a bad idea to do it in render as it will slow it down. Try to transform your data as early as possible if the transformation is not caused by immediate user interaction. I usually do it in will-mount.
Don’t create mult channel in render
Let’s say some parent component creates a number of components that depend on size of your data and you want all children to receive messages broadcasted on a core.async channel. Create a mult of that channel in init-state. Then, when children components are built in render, create a copy of that mult channel using tap. If you create mult in render all sorts of weirdness will happen.
Oh god, don’t use lazy sequences in cursors.
This one should be obvious, but if you map, remove or filter something in your data and update the cursor with the result, you will end up with a lazy sequence. Remember about mapv, filterv or into .