2014-10-06 94 views
8

我已經開發了Om/React組件,但是我感覺真的很不舒服,不能用單元測試來推動我的開發。我試圖設置我的clojurescript項目來對這些組件運行單元測試,並且到目前爲止我已經能夠編寫單元測試並實例化組件。我所缺少的是能夠確保我的組件正確地對某些事件做出反應,例如onChange,以便我可以模擬用戶輸入。如何正確(單元)測試Om/React組件?

這裏是我的測試代碼:

(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" "[email protected]") 
     (change-field! "userRequestedPassword" "secret") 
     (change-field! "confirmPassword"  "nosecret") 

     (simulate-click-event (sel1 :#submitRegistration)) 
    ))) 

此測試,但由於change-field!功能實際上並沒有改變組件的狀態失敗。這裏是(部分)組件的代碼(原諒重複...):

(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"))))) 

我可以把痕跡,測試看到的是,組件的狀態不更新,當我觸發change事件,雖然它被正確觸發。我懷疑這與Om/React的工作方式,包裝DOM組件有關,但不知道如何處理這個問題。

+0

只是爲了確保:是(「記憶」甚至只有?)由OM在所有渲染你能確認你的DOM測試組件元素實際上是創建的,並且onChange處理程序已連接? – phtrivier 2014-10-06 16:20:08

+0

是的。 'on click'事件被觸發,我可以看到消息通過core.async頻道:這就是'submit-registration'所做的,將xhrio調用的結果發送到'source'頻道,然後由'測試中的'(go ...)'循環。 – insitu 2014-10-06 17:42:01

+0

@insitu也許不同的方法會有所幫助。我使用mochify測試反應組件,並在mochify的wiki頁面中添加了一個示例:https://github.com/mantoni/mochify.js/wiki/Testing-a-ReactJS-Component-with-Mochify – 2015-03-18 10:13:13

回答

1

您可以使用來自反應庫的ReactTestUtils來模擬組件中的事件。 我使用摩卡和做這樣的事情來測試更改事件:

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); 
}