How to (unit) check Om / React components correctly?

I developed the Om / React components, but it’s really inconvenient for me that I can’t manage my development with unit tests. I tried to set up my clojurescript project to run unit tests for these components and came to the point where I was able to write unit tests and create instances of my components. What I am missing is the ability to ensure that my components respond correctly to certain events, for example. onChange so that I can simulate user inputs.

Here is my test code:

 (defn simulate-click-event "From https://github.com/levand/domina/blob/master/test/cljs/domina/test.cljs" [el] (let [document (.-document js/window)] (cond (.-click el) (.click el) (.-createEvent document) (let [e (.createEvent document "MouseEvents")] (.initMouseEvent e "click" true true js/window 0 0 0 0 0 false false false false 0 nil) (.dispatchEvent el e)) :default (throw "Unable to simulate click event")))) (defn simulate-change-event "From https://github.com/levand/domina/blob/master/test/cljs/domina/test.cljs" [el] (let [document (.-document js/window)] (cond (.-onChange el) (do (print "firing on change on " el) (.onChange el)) (.-createEvent document) (let [e (.createEvent document "HTMLEvents")] (print "firing " e " on change on " (.-id el)) (.initEvent e "change" true true) (.dispatchEvent el e)) :default (throw "Unable to simulate change event")))) (def sink "contains a channel that receives messages along with notification type" (chan)) ;; see http://yobriefca.se/blog/2014/06/04/publish-and-subscribe-with-core-dot-asyncs-pub-and-sub/ (def source (pub sink #(:topic %))) (defn change-field! [id value] (let [el (sel1 (keyword (str "#" id)))] (dommy/set-value! el value) (simulate-change-event el) )) (deftest ^:async password-confirmation (testing "do not submit if passwords are not equal" (let [subscription (chan)] (sub source :user-registration subscription) (om/root (partial u/registration-view source sink) nil {:target (sel1 :#view)}) (go (let [m (<! subscription)] (is (= :error (:state m))) (done) )) (change-field! "userRequestedEmail" "foo@bar.com") (change-field! "userRequestedPassword" "secret") (change-field! "confirmPassword" "nosecret") (simulate-click-event (sel1 :#submitRegistration)) ))) 

This test runs but fails because the change-field! function change-field! does not actually change the state of the component. Here is the (part) component code (to forgive duplication ...):

 (defn registration-view "Registration form for users. Submitting form triggers a request to server" [source sink _ owner] (reify om/IInitState (init-state [_] {:userRequestedEmail "" :userRequestedPassword "" :confirmPassword ""} ) om/IRenderState (render-state [this state] (dom/fieldset nil (dom/legend nil "User Registration") (dom/div #js { :className "pure-control-group" } (dom/label #js { :for "userRequestedEmail" } "EMail") (dom/input #js { :id "userRequestedEmail" :type "text" :placeholder "Enter an e-mail" :value (:userRequestedEmail state) :onChange #(om/set-state! owner :userRequestedEmail (.. % -target -value))})) (dom/div #js { :className "pure-control-group" } (dom/label #js { :for "userRequestedPassword" } "Password") (dom/input #js { :id "userRequestedPassword" :type "password" :placeholder "Enter password" :value (:userRequestedPassword state) :onChange #(om/set-state! owner :userRequestedPassword (.. % -target -value))})) (dom/div #js { :className "pure-control-group" } (dom/label #js { :for "confirmPassword" } "") (dom/input #js { :id "confirmPassword" :type "password" :placeholder "Confirm password" :value (:confirmPassword state) :onChange #(om/set-state! owner :confirmPassword (.. % -target -value))})) (dom/button #js {:type "submit" :id "submitRegistration" :className "pure-button pure-button-primary" :onClick #(submit-registration state sink)} "Register"))))) 

What I see when placing the trace in the test is that the state of the component is not updated when I fire the change event, although it is correctly fired. I suspect this is due to how Om / React wraps the DOM components, but am not sure how to handle this.

+8
unit-testing reactjs om clojurescript
source share
1 answer

You can mock events in your components with ReactTestUtils from react libraries. I use mocha and do something like this to check for change events:

 var comp = ReactTestUtils.renderIntoDocument(<Component />); var changingElement = ReactTestUtils.findRenderedDOMComponentWithClass(comp, 'el-class'); it ('calls myChangeMethod on change', function() { ReactTestUtils.Simulate.change(changingElement); assert(comp.myChangeEventMethod.called, true); } 
+1
source share

All Articles