diff --git a/example/dev_entrypoint.cljc b/example/dev_entrypoint.cljc index 9260a29..59073b5 100644 --- a/example/dev_entrypoint.cljc +++ b/example/dev_entrypoint.cljc @@ -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))) diff --git a/src/hyperfiddle/rcf.cljc b/src/hyperfiddle/rcf.cljc index 8d73bc1..75b6818 100644 --- a/src/hyperfiddle/rcf.cljc +++ b/src/hyperfiddle/rcf.cljc @@ -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] @@ -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 @@ -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 @@ -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)))) @@ -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))) @@ -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 @@ -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] @@ -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))) diff --git a/src/hyperfiddle/rcf/analyzer.clj b/src/hyperfiddle/rcf/analyzer.clj index fe4ed04..e9d54a1 100644 --- a/src/hyperfiddle/rcf/analyzer.clj +++ b/src/hyperfiddle/rcf/analyzer.clj @@ -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))) @@ -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)))