I'm still in a learning phase for Cljs and Om. I'm looking into writing comopnent test. Some components have cljs-http
calls to an API I created. When testing, I do not want those API calls to actually send the request, so I'm looking into mocking the request and returning a fixture. Here's an example component I have:
(defn async-component [data owner]
(reify
IWillMount
(will-mount [_]
(let [resp (go ((<! (async-call "/") :body))]
(om/update! data [:objects] resp)))
IRender
(render [_]
[:ul
(om/build-all item-component data)])))
(defn async-call [path]
(http/get path {:keywordize-keys true}))
Please don't mind if the code is actually syntactically correct, I'm just showing the gist of it.
What I now want to do is test this async-component
and the API call to see if it will render the fixture that I mock the request with. How is this done? I know cljs.test
has the async
block to test async code with, but all example show it testing actual code blocks that only have a go
in it, not in a larger context.
Here is a way you might use mocking to test your component:
(deftest test-async-component
(cljs.test/async done
(with-redefs
[async-call (fn [path]
(let [mock-ch (async/chan 1)
fixture-data {:body {:fixture-with path :and "foobar"}})]
(async/put! mock-ch fixture-data)
mock-ch)]
; At this point we successfully mocked out our data source (the API call)
; the only task that remains is to render our Om component into DOM and inspect it.
; As this task requires utility fns I will reuse the ones in this blog post:
; http://lab.brightnorth.co.uk/2015/01/27/unit-and-browser-testing-om-clojurescript-applications/
(let [c (new-container!)
initial-data {:objects [{:initial-object 42}]}]
; This will mount and render your component into the DOM residing in c.
(om/root async-component initial-data {:target c})
(testing "fixture data gets put into the DOM"
(is (= "foobar" (text (sel1 c :ul)))))
; You can add more tests in this manner, then finally call 'done'.
(done)))))
The steps taken in the above code in English:
async-call
's mock fn that returns a channel (the same interface as the original one) prefilled with fixture data.async-call
when om/will-mount
runs, taking the fixture-data
off the chan
).