Skip to content

Commit

Permalink
Optional cljs dependency, proper test runs in CLJS repl
Browse files Browse the repository at this point in the history
  • Loading branch information
ggeoffrey committed Apr 14, 2022
1 parent dff4f9a commit 4c17903
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 25 deletions.
11 changes: 6 additions & 5 deletions example/dev_entrypoint.cljc
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
(ns dev-entrypoint
(:require [example]
[hyperfiddle.rcf :refer [tests]]))
[hyperfiddle.rcf :as rcf :refer [tests]]))

; enable tests after app namespaces are loaded (intended for subsequent REPL interactions)
#?(:clj (alter-var-root #'hyperfiddle.rcf/*enabled* (constantly true))
:cljs (set! hyperfiddle.rcf/*enabled* true))
(comment
(rcf/enable!)
)

; prevent test execution during cljs hot code reload
#?(:cljs (defn ^:dev/before-load stop [] (set! hyperfiddle.rcf/*enabled* false)))
#?(:cljs (defn ^:dev/after-load start [] (set! hyperfiddle.rcf/*enabled* true)))
#?(:cljs (defn ^:dev/before-load stop [] (rcf/enable! false)))
#?(:cljs (defn ^:dev/after-load start [] (rcf/enable! true)))
31 changes: 14 additions & 17 deletions src/hyperfiddle/rcf.cljc
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
(ns hyperfiddle.rcf
(:refer-clojure :exclude [=])
#?(:cljs (:require-macros [hyperfiddle.rcf :refer [tests deftest async]]
[hyperfiddle.rcf.impl :refer [make-queue]]
[cljs.test :as t :refer [assert-expr]]))
[hyperfiddle.rcf.impl :refer [make-queue]]))
(:require #?(:clj [hyperfiddle.rcf.impl :as impl])
#?(:clj [clojure.test :as t]
:cljs [cljs.test :as t])
#?(:clj [cljs.test :as cljs-test])
#?(:clj [hyperfiddle.rcf.analyzer :as ana])
#?(:clj [clojure.walk :as walk])
[clojure.string :as str]
Expand All @@ -19,7 +17,6 @@

#?(:cljs (goog-define ^boolean ENABLED false))
#?(:cljs (goog-define ^boolean TIMEOUT 400))
#?(:cljs (goog-define ^boolean GENERATE-TESTS false))

;; "Set to true if you want to generate clojure.test compatible tests. This
;; will define testing functions in your namespace using `deftest`. Defaults to
Expand All @@ -38,8 +35,7 @@
#?(:clj (alter-var-root #'*timeout* (constantly ms))
:cljs (set! *timeout* ms)))

#?(:clj (def ^:dynamic *generate-tests* (= "true" (System/getProperty "hyperfiddle.rcf.generate-tests")))
:cljs (def ^boolean ^:dynamic *generate-tests* GENERATE-TESTS))
#?(:clj (def ^:dynamic *generate-tests* (= "true" (System/getProperty "hyperfiddle.rcf.generate-tests"))))

(def ^{:doc "
Function to push value to async queue, e.g. `(! 42)`. RCF redefines this var in tests context. For REPL
Expand All @@ -63,16 +59,21 @@ convenience, defaults to println outside of tests context."}
(symbol (str "generated__" file "_" line))))

(defmacro tests [& body]
(cond
*generate-tests* `(deftest ~(gen-name &form) ~@body)
*enabled* (impl/tests* &env body)
:else nil))
(let [name (gen-name &form)]
(cond
*generate-tests* `(deftest ~name ~@body)
*enabled* (if (:js-globals &env)
`(do (defn ~name [] ~(impl/tests* &env body))
(when *enabled* (cljs.test/run-block (cljs.test/test-var-block* (var ~name) ~name))))
(impl/tests* &env body))
:else nil)))

(defmacro deftest
"When *load-tests* is false, deftest is ignored."
[name & body]
(if (:js-globals &env)
`(cljs.test/deftest ~name ~(impl/tests* &env body))
`(do (cljs.test/deftest ~name ~(impl/tests* &env body))
(when *enabled* (~name)))
(when t/*load-tests*
`(do (def ~(vary-meta name assoc :test `(fn [] ~(impl/tests* &env body)))
(fn [] (impl/test-var (var ~name))))
Expand All @@ -82,7 +83,7 @@ convenience, defaults to println outside of tests context."}

(defmacro async [done & body]
(if (ana/cljs? &env)
`(cljs-test/async ~done ~@body)
`(cljs.test/async ~done ~@body)
`(let [~done (constantly nil)]
~@body)))

Expand All @@ -103,9 +104,7 @@ convenience, defaults to println outside of tests context."}
[msg form]
(let [cljs? (ana/cljs? &env)
{:keys [file line end-line column end-column]} (meta form)]
`(try ~(if cljs?
(cljs-test/assert-expr &env msg form)
(t/assert-expr msg form))
`(try ~(t/assert-expr msg form)
(catch ~(if cljs? :default 'Throwable) t#
(do-report {:type :error, :message ~msg,
:file ~file :line ~line :end-line ~end-line :column ~column :end-column ~end-column
Expand Down Expand Up @@ -137,7 +136,6 @@ convenience, defaults to println outside of tests context."}
(first values#)))))

#?(:clj (defmethod t/assert-expr 'hyperfiddle.rcf/= [msg form] (assert-= nil msg form)))
#?(:clj (defmethod cljs-test/assert-expr 'hyperfiddle.rcf/= [menv msg form] (assert-= menv msg form)))

#?(:clj
(defn- assert-unify [menv msg form]
Expand All @@ -159,4 +157,3 @@ convenience, defaults to println outside of tests context."}
lhs#))))))

#?(:clj (defmethod t/assert-expr :hyperfiddle.rcf/= [msg form] (assert-unify nil msg form)))
#?(:clj (defmethod cljs-test/assert-expr :hyperfiddle.rcf/= [menv msg form] (assert-unify menv msg form)))
9 changes: 6 additions & 3 deletions src/hyperfiddle/rcf/analyzer.clj
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
;; A simpler tools.analyzer for the restricted use case of RCF
;; Adapted from https://github.com/clojure/tools.analyzer
(ns hyperfiddle.rcf.analyzer
(:refer-clojure :exclude [macroexpand-1 macroexpand update-vals resolve])
(:require [cljs.analyzer.api :as cljs-ana])
(:refer-clojure :exclude [macroexpand-1 macroexpand update-vals])
(:import (clojure.lang IObj)))

(defn cljs? [env] (some? (:js-globals env)))
Expand Down Expand Up @@ -49,11 +48,15 @@
(defn to-var [{:keys [macro meta ns name]}]
(with-meta {:ns ns, :name name} (assoc meta :type ::var)))

(defn cljs-resolve [env sym]
(require '[cljs.analyzer.api])
((resolve 'cljs.analyzer.api/resolve) env sym))

(defn resolve-sym
"Resolves the value mapped by the given sym in the global env"
[sym {:keys [ns] :as env}]
(if (cljs? env)
(let [resolved (cljs-ana/resolve env sym)]
(let [resolved (cljs-resolve env sym)]
(if (or (:macro resolved) (= :var (:op resolved)))
(resolve-sym (:name resolved) (dissoc env :js-globals))
(to-var resolved)))
Expand Down

0 comments on commit 4c17903

Please sign in to comment.