【发布时间】:2014-11-30 08:57:05
【问题描述】:
我已经开发了 Om/React 组件,但无法通过单元测试来推动我的开发,我感到非常不舒服。我试图设置我的 clojurescript 项目来对这些组件运行单元测试,到目前为止,我已经能够编写单元测试并实例化我的组件。我缺少的是确保我的组件正确响应某些事件的能力,例如onChange 这样我就可以模拟用户输入。
这是我的测试代码:
(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))
)))
此测试运行但失败,因为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 组件,但不确定如何处理。
【问题讨论】:
-
只是为了确保:您的测试组件是否完全由 om 呈现(甚至只是“在内存中”?)您能否确认 DOM 元素是实际创建的,并且附加了 onChange 处理程序?跨度>
-
是的。
on click事件被触发,我可以看到消息通过 core.async 通道:这就是submit-registration所做的,将 xhrio 调用的结果发送到source通道,然后由(go ...)接收在测试中循环。 -
@insitu 也许不同的方法会有所帮助。我使用 mochify 测试反应组件,并在 mochify 的 wiki 页面中添加了一个示例:github.com/mantoni/mochify.js/wiki/…
-
@TJ。感谢您的指点。我也在用同样的方式思考,使用 React 自己的测试工具。但这可能需要一些工作才能正确集成到 clojurescript 和 Om 中。会看看我是否可以回到它...
标签: unit-testing reactjs clojurescript om