Last active
February 7, 2023 12:09
-
-
Save philomates/32f8e1f7a2a4e746ac0186964aaaa2d3 to your computer and use it in GitHub Desktop.
clojure.test re-interpretation of nubank/state-flow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns example-test | |
(:require [clojure.test :refer [is deftest testing]] | |
[flow :as f] | |
[matcher-combinators.test :refer [match?]])) | |
(f/tests-as-flows!) | |
(defn request! [verb url body] | |
(let [servlet (get-state #(get-in % [:system :http/server :io.pedestal.http/service-fn]))] | |
(-> (io.pedestal.test/response-for servlet verb url :body body) | |
...))) | |
(deftest ^{:flow-system-override f/experimental-flow-config} private-pages-are-private | |
(testing "if you try to access a private page while logged out you get redirected" | |
(is (match? {:status 302 | |
:headers {"Location" "/login?redirect-to=/ops/"}} | |
(request! :get "/ops/" {})))) | |
(testing "once logged in you can access private pages" | |
(dev-login) | |
(is (match? {:status 200} | |
(request! :get "/ops/" {}))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns flow | |
(:require [clojure.test :as t :refer [is testing]])) | |
;; Testing internals | |
;; ------------------------------------------------ | |
(def ^{:dynamic true | |
:private true} | |
*state* | |
nil) | |
(defonce test-report-methods (methods t/report)) | |
;; capture test results as data instead of report events | |
;; useful for building more tooling on top of clojure.test | |
(def ^:dynamic *test-results* nil) | |
(defn- register-test-result! [m] | |
(when *test-results* | |
(when-let [test-var (last t/*testing-vars*)] | |
(dosync | |
(commute *test-results* | |
update | |
test-var | |
(fnil conj []) | |
(assoc m :context-str t/*testing-contexts*)))))) | |
(defmethod t/report :pass [m] | |
(register-test-result! m) | |
((get test-report-methods :pass) m)) | |
(defmethod t/report :fail [m] | |
(register-test-result! m) | |
((get test-report-methods :fail) m) | |
;; interrupt the control flow by escaping back to the `deftest`, which | |
;; swallows the exception and aborts the rest of the test | |
(when *state* | |
(throw (ex-info "internal error" {:type ::fail})))) | |
(defmethod t/report :error [m] | |
(if (= ::fail (-> m :actual ex-data :type)) | |
;; pass internal exceptions through | |
(throw (:actual m)) | |
(do | |
(register-test-result! m) | |
((get test-report-methods :error) m)))) | |
;; Client-specific internals | |
;; ------------------------------------------------ | |
(def experimental-flow-config {:config {:datomic {:transact-experimental? true}}}) | |
(defn start-system! | |
([] (start-system! {})) | |
([config-overrides] | |
(try ;; starts a test instance of the server "system" | |
(system/init! :test {:config-overrides config-overrides}) | |
(catch Exception e | |
(when-let [system (:system (ex-data e))] | |
(integrant.core/halt! system)) | |
(throw e))))) | |
;; API | |
;; ------------------------------------------------ | |
(defn get-state | |
([] (get-state identity)) | |
([f] (f @*state*))) | |
(defn swap-state [& args] | |
(apply swap! *state* args)) | |
(defn as-flow [test-fn] | |
(binding [*state* (atom {:system (start-system! (-> t/*test-var* meta :flow-system-overrides))})] | |
(try | |
(test-fn) | |
(catch Exception e | |
(if (= ::fail (-> e ex-data :type)) | |
nil | |
(throw e))) | |
(finally | |
(ig/halt! (:system @*state*)))))) | |
(defn tests-as-flows! [] | |
(t/use-fixtures :each as-flow)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment