Large refactoring
- State handler intermediates between view, server
This commit is contained in:
parent
707fb9f22d
commit
1f9108b96a
9 changed files with 163 additions and 105 deletions
|
@ -1,5 +1,6 @@
|
|||
(ns grub.integration-test
|
||||
(:require [clj-webdriver.taxi :as taxi]
|
||||
(:require [grub.db :as db]
|
||||
[clj-webdriver.taxi :as taxi]
|
||||
[clj-webdriver.core :as webdriver]
|
||||
[clojure.test :as test]))
|
||||
|
||||
|
@ -23,20 +24,25 @@
|
|||
(add-grub driver1 grub))
|
||||
(doseq [grub grubs]
|
||||
(test/is (taxi/find-element driver2 {:text grub})
|
||||
"Added grubs should appear in other browser"))))
|
||||
"Added grubs should appear in other browser")))
|
||||
(db/clear-grubs))
|
||||
|
||||
(defn test-grubs-are-stored-on-server [url driver]
|
||||
(taxi/to driver url)
|
||||
(let [grubs (repeatedly 4 get-rand-grub)]
|
||||
(doseq [grub grubs]
|
||||
(add-grub driver grub))
|
||||
(Thread/sleep 200)
|
||||
(taxi/refresh driver)
|
||||
(Thread/sleep 200)
|
||||
(doseq [grub grubs]
|
||||
(test/is (taxi/find-element driver {:text grub})
|
||||
"Previously added grubs should be loaded on refresh"))))
|
||||
"Previously added grubs should be loaded on refresh")))
|
||||
(db/clear-grubs))
|
||||
|
||||
|
||||
(defn run [port]
|
||||
(db/connect-and-handle-events "grub-integration-test")
|
||||
(let [site-url (str "http://localhost:" port)]
|
||||
(println "Starting integration test")
|
||||
(let [driver1 (get-driver site-url)
|
||||
|
@ -44,4 +50,5 @@
|
|||
(test-adding-grubs site-url driver1 driver2)
|
||||
(test-grubs-are-stored-on-server site-url driver1)
|
||||
(taxi/quit driver1)
|
||||
(taxi/quit driver2))))
|
||||
(taxi/quit driver2)))
|
||||
(db/clear-grubs))
|
||||
|
|
|
@ -17,18 +17,21 @@
|
|||
(describe
|
||||
"grub.db"
|
||||
(before-all (db/connect-and-handle-events test-db))
|
||||
(before (mc/drop db/grub-collection))
|
||||
(describe "Create grub"
|
||||
(it "should create a grub when a create event comes"
|
||||
(before (db/clear-grubs))
|
||||
(describe "Add"
|
||||
(it "should add a grub when an add event comes"
|
||||
(let [test-grub "testgrub"
|
||||
test-id 12345]
|
||||
(>!! @db/incoming-events {:event :create :_id test-id :grub test-grub})
|
||||
(>!! @db/incoming-events {:event :add
|
||||
:_id test-id
|
||||
:grub test-grub
|
||||
:completed false})
|
||||
(short-delay)
|
||||
(should=
|
||||
{:_id test-id :grub test-grub :completed false}
|
||||
(mc/find-one-as-map db/grub-collection {:_id test-id})))))
|
||||
|
||||
(describe "Complete grub"
|
||||
(describe "Complete"
|
||||
(it "should complete a grub when a complete event comes"
|
||||
(let [test-grub {:_id 123456 :completed false}]
|
||||
(mc/insert db/grub-collection test-grub)
|
||||
|
@ -38,7 +41,7 @@
|
|||
{:_id (:_id test-grub) :completed true}
|
||||
(mc/find-one-as-map db/grub-collection {:_id (:_id test-grub)})))))
|
||||
|
||||
(describe "Uncomplete grub"
|
||||
(describe "Uncomplete"
|
||||
(it "should uncomplete a grub when an uncomplete event comes"
|
||||
(let [test-grub {:_id 123456 :completed true}]
|
||||
(mc/insert db/grub-collection test-grub)
|
||||
|
@ -48,7 +51,7 @@
|
|||
{:_id (:_id test-grub) :completed false}
|
||||
(mc/find-one-as-map db/grub-collection {:_id (:_id test-grub)})))))
|
||||
|
||||
(describe "Delete grub"
|
||||
(describe "Delete"
|
||||
(it "should delete a grub when a delete event comes"
|
||||
(let [test-grub {:_id 123456 :completed true}]
|
||||
(mc/insert db/grub-collection test-grub)
|
||||
|
|
|
@ -7,56 +7,61 @@
|
|||
[grub.macros :refer [log logs]]))
|
||||
|
||||
(describe
|
||||
"grub state"
|
||||
(before (reset! state/grubs []))
|
||||
"State"
|
||||
|
||||
(describe "Add grub"
|
||||
(it "should add a grub to the state when an add event comes"
|
||||
(let [test-grub {:_id 12345 :grub "testgrub" :completed true}
|
||||
add-event (assoc test-grub :event :add)]
|
||||
(state/handle-event add-event)
|
||||
(should-contain test-grub @state/grubs))))
|
||||
(describe
|
||||
"event handling:"
|
||||
(before (reset! state/grubs []))
|
||||
|
||||
(describe "Create grub"
|
||||
(it "should add a new grub to the state when a create event comes"
|
||||
(let [test-grub {:grub "testgrub"}
|
||||
expected-grub (assoc test-grub :completed false)
|
||||
create-event (assoc test-grub :event :create)]
|
||||
(state/handle-event create-event)
|
||||
(let [created-grub (first @state/grubs)]
|
||||
(should= (:grub created-grub) (:grub test-grub)))))
|
||||
(it "should generate an _id for the new grub"
|
||||
(let [test-grub {:grub "testgrub"}
|
||||
create-event (assoc test-grub :event :create)]
|
||||
(state/handle-event create-event)
|
||||
(let [added-grub (first (filter #(= (:grub %) (:grub test-grub))
|
||||
@state/grubs))]
|
||||
(should-not-be-nil (:_id added-grub))))))
|
||||
(describe "Add"
|
||||
(it "should add a grub to the state when an add event comes"
|
||||
(let [test-grub {:_id 12345 :grub "testgrub" :completed true}
|
||||
add-event (assoc test-grub :event :add)]
|
||||
(state/handle-event add-event)
|
||||
(should-contain test-grub @state/grubs))))
|
||||
|
||||
(describe "Complete"
|
||||
(it "should complete a grub in the state when a complete event comes"
|
||||
(let [test-grub {:_id 234243 :grub "testgrub" :completed false}
|
||||
expected-grub (assoc test-grub :completed true)
|
||||
complete-event (-> (select-keys [:_id])
|
||||
(assoc :event :complete))]
|
||||
(reset! state/grubs [test-grub])
|
||||
(state/handle-event complete-event)
|
||||
(should-contain expected-grub @state/grubs))))
|
||||
|
||||
(describe "Uncomplete"
|
||||
(it "should uncomplete a grub in the state when an uncomplete event comes"
|
||||
(let [test-grub {:_id 234243 :grub "testgrub" :completed true}
|
||||
expected-grub (assoc test-grub :completed false)
|
||||
complete-event (-> (select-keys [:_id])
|
||||
(assoc :event :uncomplete))]
|
||||
(reset! state/grubs [test-grub])
|
||||
(state/handle-event complete-event)
|
||||
(should-contain expected-grub @state/grubs))))
|
||||
|
||||
(describe "Delete"
|
||||
(it "should delete a grub from the state when a delete event comes"
|
||||
(let [test-grub {:_id 234243 :grub "testgrub" :completed true}
|
||||
delete-event {:_id (:_id test-grub) :event :delete}]
|
||||
(reset! state/grubs [test-grub])
|
||||
(state/handle-event delete-event)
|
||||
(should= [] @state/grubs)))))
|
||||
|
||||
(describe "Complete grub"
|
||||
(it "should complete a grub in the state when a complete event comes"
|
||||
(let [test-grub {:_id 234243 :grub "testgrub" :completed false}
|
||||
expected-grub (assoc test-grub :completed true)
|
||||
complete-event (-> (select-keys [:_id])
|
||||
(assoc :event :complete))]
|
||||
(reset! state/grubs [test-grub])
|
||||
(state/handle-event complete-event)
|
||||
(should-contain expected-grub @state/grubs))))
|
||||
|
||||
(describe "Uncomplete grub"
|
||||
(it "should uncomplete a grub in the state when an uncomplete event comes"
|
||||
(let [test-grub {:_id 234243 :grub "testgrub" :completed true}
|
||||
expected-grub (assoc test-grub :completed false)
|
||||
complete-event (-> (select-keys [:_id])
|
||||
(assoc :event :uncomplete))]
|
||||
(reset! state/grubs [test-grub])
|
||||
(state/handle-event complete-event)
|
||||
(should-contain expected-grub @state/grubs))))
|
||||
|
||||
(describe "Delete grub"
|
||||
(it "should delete a grub from the state when a delete event comes"
|
||||
(let [test-grub {:_id 234243 :grub "testgrub" :completed true}
|
||||
delete-event {:_id (:_id test-grub) :event :delete}]
|
||||
(reset! state/grubs [test-grub])
|
||||
(state/handle-event delete-event)
|
||||
(should= [] @state/grubs)))))
|
||||
(describe
|
||||
"view event handling"
|
||||
(describe "Create"
|
||||
(it "should add a new grub to the state when a create event comes"
|
||||
(let [test-grub {:grub "testgrub"}
|
||||
create-event (assoc test-grub :event :create)]
|
||||
(state/handle-view-event create-event)
|
||||
(js/setTimeout (fn [] (let [created-grub (first @state/grubs)]
|
||||
(should= (:grub test-grub) (:grub created-grub)))))))
|
||||
(it "should generate an _id for the new grub"
|
||||
(let [test-grub {:grub "testgrub"}
|
||||
create-event (assoc test-grub :event :create)]
|
||||
(state/handle-event create-event)
|
||||
(js/setTimeout (fn []
|
||||
(let [added-grub (first (filter #(= (:grub %) (:grub test-grub))
|
||||
@state/grubs))]
|
||||
(should-not-be-nil (:_id added-grub))))))))))
|
||||
|
|
|
@ -35,10 +35,19 @@
|
|||
(reload/wrap-reload (handler/site #'routes) {:dirs ["src/clj"]})
|
||||
(handler/site routes))))
|
||||
|
||||
(def default-port 3000)
|
||||
(def integration-test-port 3456)
|
||||
|
||||
(defn start-server [port]
|
||||
(println (str "Starting server on localhost:" port))
|
||||
(httpkit/run-server app {:port port}))
|
||||
|
||||
(defn run-integration-test []
|
||||
(let [stop-server (start-server integration-test-port)]
|
||||
(integration-test/run integration-test-port)
|
||||
(stop-server)))
|
||||
|
||||
(defn -main [& args]
|
||||
(let [port 3000]
|
||||
(println (str "Starting server on localhost:" port))
|
||||
(defonce stop-server (httpkit/run-server app {:port port}))
|
||||
(when (some #(= % "integration") args)
|
||||
(integration-test/run port)
|
||||
(stop-server))))
|
||||
(if (some #(= % "integration") args)
|
||||
(run-integration-test)
|
||||
(start-server default-port)))
|
||||
|
|
|
@ -11,10 +11,9 @@
|
|||
|
||||
(defmulti handle-event :event :default :unknown-event)
|
||||
|
||||
(defmethod handle-event :create [event]
|
||||
(defmethod handle-event :add [event]
|
||||
(let [grub (-> event
|
||||
(select-keys [:_id :grub])
|
||||
(assoc :completed false))]
|
||||
(select-keys [:_id :grub :completed]))]
|
||||
(mc/insert grub-collection grub)))
|
||||
|
||||
(defmethod handle-event :complete [event]
|
||||
|
@ -49,6 +48,9 @@
|
|||
(>! out grub-event))))
|
||||
out))
|
||||
|
||||
(defn clear-grubs []
|
||||
(mc/drop grub-collection))
|
||||
|
||||
(def default-db "grub")
|
||||
|
||||
(defn connect-and-handle-events
|
||||
|
|
|
@ -9,15 +9,12 @@
|
|||
[cljs.core.async.macros :refer [go]]))
|
||||
|
||||
(defn handle-grub-events []
|
||||
(let [local-events (view/get-local-events)
|
||||
[local-events' local-events''] (a/fan-out local-events 2)
|
||||
remote-events (ws/get-remote-events)
|
||||
events (a/fan-in [local-events' remote-events])]
|
||||
(a/do-chan! ws/send-to-server local-events'')
|
||||
(a/copy-chan state/incoming-events events)))
|
||||
(a/copy-chan state/incoming-view-events view/outgoing-events)
|
||||
(a/copy-chan state/incoming-events ws/outgoing-events)
|
||||
(a/copy-chan ws/incoming-events state/outgoing-events))
|
||||
|
||||
(defn init []
|
||||
(view/render-body)
|
||||
(view/init)
|
||||
(ws/connect-to-server)
|
||||
(handle-grub-events))
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
[cljs.core.async.macros :refer [go]]))
|
||||
|
||||
(def incoming-events (chan))
|
||||
(def incoming-view-events (chan))
|
||||
(def outgoing-events (chan))
|
||||
|
||||
(def grubs (atom []))
|
||||
|
||||
|
@ -22,13 +24,6 @@
|
|||
(let [grub (select-keys event [:_id :grub :completed])]
|
||||
(swap! grubs (fn [current] (conj current grub)))))
|
||||
|
||||
(defmethod handle-event :create [event]
|
||||
(let [grub (-> event
|
||||
(select-keys [:_id :grub])
|
||||
(assoc :_id (str "grub-" (.now js/Date)))
|
||||
(assoc :completed false))]
|
||||
(swap! grubs (fn [current] (conj current grub)))))
|
||||
|
||||
(defmethod handle-event :complete [event]
|
||||
(swap! grubs
|
||||
(fn [current]
|
||||
|
@ -51,7 +46,33 @@
|
|||
(defmethod handle-event :unknown-event [event]
|
||||
(logs "Cannot handle unknown event:" event))
|
||||
|
||||
|
||||
|
||||
(defn pass-on-view-event [event]
|
||||
(go (>! incoming-events event))
|
||||
(go (>! outgoing-events event)))
|
||||
|
||||
(defmulti handle-view-event :event :default :unknown-event)
|
||||
|
||||
(defmethod handle-view-event :create [event]
|
||||
(let [create-event (-> event
|
||||
(assoc :event :add)
|
||||
(assoc :_id (str "grub-" (.now js/Date)))
|
||||
(assoc :completed false))]
|
||||
(pass-on-view-event create-event)))
|
||||
|
||||
(defmethod handle-view-event :unknown-event [event]
|
||||
(pass-on-view-event event))
|
||||
|
||||
|
||||
(defn handle-incoming-events []
|
||||
(go-loop (handle-event (<! incoming-events))))
|
||||
|
||||
(defn handle-incoming-view-events []
|
||||
(go-loop (handle-view-event (<! incoming-view-events))))
|
||||
|
||||
(handle-incoming-events)
|
||||
(defn init []
|
||||
(handle-incoming-events)
|
||||
(handle-incoming-view-events))
|
||||
|
||||
(init)
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
[dommy.macros :refer [deftemplate sel1 node]]
|
||||
[cljs.core.async.macros :refer [go]]))
|
||||
|
||||
(def outgoing-events (chan))
|
||||
|
||||
(def add-grub-text
|
||||
(node [:input.form-control {:id "add-grub-input" :type "text" :placeholder "2 grubs"}]))
|
||||
|
||||
|
@ -92,10 +94,6 @@
|
|||
grub-events (map-chan (fn [id] {:event :delete :_id id}) ids)]
|
||||
grub-events)))
|
||||
|
||||
(defn get-local-events []
|
||||
(fan-in [(get-added-events)
|
||||
(get-completed-events)
|
||||
(get-deleted-events)]))
|
||||
|
||||
(defn render-grub-list [grubs]
|
||||
(let [grub-list (sel1 :#grubList)
|
||||
|
@ -104,7 +102,18 @@
|
|||
(doseq [grub sorted-grubs]
|
||||
(dommy/append! grub-list (grub-template grub)))))
|
||||
|
||||
(add-watch state/grubs
|
||||
:grub-add-watch
|
||||
(fn [key ref old new]
|
||||
(render-grub-list new)))
|
||||
(defn push-outgoing-events []
|
||||
(fan-in outgoing-events [(get-added-events)
|
||||
(get-completed-events)
|
||||
(get-deleted-events)]))
|
||||
|
||||
(defn watch-for-state-changes []
|
||||
(add-watch state/grubs
|
||||
:grub-add-watch
|
||||
(fn [key ref old new]
|
||||
(render-grub-list new))))
|
||||
|
||||
(defn init []
|
||||
(render-body)
|
||||
(watch-for-state-changes)
|
||||
(push-outgoing-events))
|
||||
|
|
|
@ -6,18 +6,23 @@
|
|||
(:require-macros [grub.macros :refer [log logs go-loop]]
|
||||
[cljs.core.async.macros :refer [go]]))
|
||||
|
||||
(def incoming-events (chan))
|
||||
(def outgoing-events (chan))
|
||||
|
||||
(def websocket* (atom nil))
|
||||
|
||||
(defn handle-incoming-events []
|
||||
(go-loop
|
||||
(let [event (<! incoming-events)]
|
||||
(.send @websocket* event))))
|
||||
|
||||
(defn handle-outgoing-events []
|
||||
(aset @websocket* "onmessage" (fn [event]
|
||||
(let [grub-event (cljs.reader/read-string (.-data event))]
|
||||
(logs "Received:" grub-event)
|
||||
(go (>! outgoing-events grub-event))))))
|
||||
|
||||
(defn connect-to-server []
|
||||
(reset! websocket* (js/WebSocket. "ws://localhost:3000/ws")))
|
||||
|
||||
(defn get-remote-events []
|
||||
(let [out (chan)]
|
||||
(aset @websocket* "onmessage" (fn [event]
|
||||
(let [grub-event (cljs.reader/read-string (.-data event))]
|
||||
(logs "Received:" grub-event)
|
||||
(go (>! out grub-event)))))
|
||||
out))
|
||||
|
||||
(defn send-to-server [event]
|
||||
(.send @websocket* event))
|
||||
(reset! websocket* (js/WebSocket. "ws://localhost:3000/ws"))
|
||||
(handle-incoming-events)
|
||||
(handle-outgoing-events))
|
||||
|
|
Loading…
Reference in a new issue