|
@@ -8,13 +8,42 @@
|
|
|
{:dev/always true} ;; necessary for test-data freshness
|
|
{:dev/always true} ;; necessary for test-data freshness
|
|
|
(:require [shadow.test.env :as env]
|
|
(:require [shadow.test.env :as env]
|
|
|
[clojure.tools.cli :as cli]
|
|
[clojure.tools.cli :as cli]
|
|
|
- [shadow.test.node :as node]
|
|
|
|
|
[clojure.string :as str]
|
|
[clojure.string :as str]
|
|
|
[clojure.set :as set]
|
|
[clojure.set :as set]
|
|
|
|
|
+ [shadow.test :as st]
|
|
|
|
|
+ [cljs.test :as ct]
|
|
|
["util" :as util]
|
|
["util" :as util]
|
|
|
;; activate humane test output for all tests
|
|
;; activate humane test output for all tests
|
|
|
[pjstadig.humane-test-output]))
|
|
[pjstadig.humane-test-output]))
|
|
|
|
|
|
|
|
|
|
+;; Cljs.test customization
|
|
|
|
|
+;; Inherit behavior from default reporter
|
|
|
|
|
+(derive ::node ::ct/default)
|
|
|
|
|
+
|
|
|
|
|
+;; Needed for process to exit correctly
|
|
|
|
|
+(defmethod ct/report [::node :end-run-tests] [m]
|
|
|
|
|
+ (if (ct/successful? m)
|
|
|
|
|
+ (js/process.exit 0)
|
|
|
|
|
+ (js/process.exit 1)))
|
|
|
|
|
+
|
|
|
|
|
+;; Improves on default error behavior by printing full stacktrace.
|
|
|
|
|
+;; clojure.test runner does this but cljs.test does not - https://github.com/clojure/clojure/blob/9af0d1d9a0dc34c406c3588dfe9b60dbe4530981/src/clj/clojure/test.clj#L384-L395
|
|
|
|
|
+(defmethod ct/report [::node :error] [m]
|
|
|
|
|
+ ;; Add to counter for ::node
|
|
|
|
|
+ (ct/inc-report-counter! :error)
|
|
|
|
|
+
|
|
|
|
|
+ ;; Print standard error messages
|
|
|
|
|
+ (let [env (ct/get-current-env)]
|
|
|
|
|
+ (binding [ct/*current-env* (assoc env :reporter ::ct/default)]
|
|
|
|
|
+ (ct/report m)))
|
|
|
|
|
+
|
|
|
|
|
+ ;; Also print stacktrace
|
|
|
|
|
+ (when (.hasOwnProperty (:actual m) "stack")
|
|
|
|
|
+ (println (.-stack (:actual m)))))
|
|
|
|
|
+
|
|
|
|
|
+;; CLI utils
|
|
|
|
|
+;; =========
|
|
|
|
|
+
|
|
|
(defn- print-summary
|
|
(defn- print-summary
|
|
|
"Print help summary given args and opts strings"
|
|
"Print help summary given args and opts strings"
|
|
|
[options-summary additional-msg]
|
|
[options-summary additional-msg]
|
|
@@ -35,30 +64,65 @@
|
|
|
(js/process.exit 1))
|
|
(js/process.exit 1))
|
|
|
parsed-input)))
|
|
parsed-input)))
|
|
|
|
|
|
|
|
-(defn- run-test-options
|
|
|
|
|
- "Given available tests namespaces as symbols, test vars and options,
|
|
|
|
|
-returns run options for selected tests to run"
|
|
|
|
|
- [namespaces
|
|
|
|
|
- vars
|
|
|
|
|
- {:keys [include exclude namespace namespace-regex]}]
|
|
|
|
|
|
|
+(defn- get-selected-tests
|
|
|
|
|
+ "Given available tests namespaces as symbols, test vars and user options,
|
|
|
|
|
+returns selected tests and namespaces to run"
|
|
|
|
|
+ [test-namespaces
|
|
|
|
|
+ test-vars
|
|
|
|
|
+ {:keys [include exclude namespace namespace-regex vars]}]
|
|
|
(let [focused-tests (cond
|
|
(let [focused-tests (cond
|
|
|
|
|
+ (seq vars)
|
|
|
|
|
+ vars
|
|
|
(seq include)
|
|
(seq include)
|
|
|
(map symbol (filter
|
|
(map symbol (filter
|
|
|
#(seq (set/intersection include (set (keys (meta %)))))
|
|
#(seq (set/intersection include (set (keys (meta %)))))
|
|
|
- vars))
|
|
|
|
|
|
|
+ test-vars))
|
|
|
(seq exclude)
|
|
(seq exclude)
|
|
|
(map symbol (remove
|
|
(map symbol (remove
|
|
|
#(seq (set/intersection exclude (set (keys (meta %)))))
|
|
#(seq (set/intersection exclude (set (keys (meta %)))))
|
|
|
- vars)))
|
|
|
|
|
|
|
+ test-vars)))
|
|
|
test-syms (cond (some? focused-tests)
|
|
test-syms (cond (some? focused-tests)
|
|
|
focused-tests
|
|
focused-tests
|
|
|
namespace
|
|
namespace
|
|
|
[namespace]
|
|
[namespace]
|
|
|
namespace-regex
|
|
namespace-regex
|
|
|
- (filter #(re-find namespace-regex (str %)) namespaces))]
|
|
|
|
|
- (cond-> {}
|
|
|
|
|
- (some? test-syms)
|
|
|
|
|
- (assoc :test-syms test-syms))))
|
|
|
|
|
|
|
+ (filter #(re-find namespace-regex (str %)) test-namespaces))]
|
|
|
|
|
+ test-syms))
|
|
|
|
|
+
|
|
|
|
|
+;; This is a patched version of https://github.com/thheller/shadow-cljs/blob/f271b3c40d3ccd4e587b0ffeaa2713d2f642114a/src/main/shadow/test/node.cljs#L44-L56
|
|
|
|
|
+;; that consistently works for all symbols
|
|
|
|
|
+(defn find-matching-test-vars
|
|
|
|
|
+ "Converts symbols to vars"
|
|
|
|
|
+ [test-syms all-test-vars]
|
|
|
|
|
+ (let [test-namespaces
|
|
|
|
|
+ (->> test-syms (filter simple-symbol?) (set))
|
|
|
|
|
+ test-var-syms
|
|
|
|
|
+ (->> test-syms (filter qualified-symbol?) (set))]
|
|
|
|
|
+ (->> all-test-vars
|
|
|
|
|
+ (filter (fn [the-var]
|
|
|
|
|
+ (let [{:keys [ns] :as m} (meta the-var)]
|
|
|
|
|
+ (or (contains? test-namespaces ns)
|
|
|
|
|
+ ;; PATCH: (symbol SYMBOL SYMBOL) leads to buggy equality behavior
|
|
|
|
|
+ ;; in cljs. In clj, this throws an exception. Modified to
|
|
|
|
|
+ ;; (symbol STRING STRING) to avoid bug
|
|
|
|
|
+ (contains? test-var-syms
|
|
|
|
|
+ (symbol (name ns) (name (:name m)))))))))))
|
|
|
|
|
+
|
|
|
|
|
+(defn- get-selected-vars
|
|
|
|
|
+ "Given test selections from user options, returns the selected tests as
|
|
|
|
|
+ vars"
|
|
|
|
|
+ [test-namespaces test-vars options]
|
|
|
|
|
+ (->> [:include :exclude :namespace :namespace-regex :vars]
|
|
|
|
|
+ ;; Only AND options users have specified
|
|
|
|
|
+ (filter #(let [val (get options %)]
|
|
|
|
|
+ ;; Some options default to empty so we have filter these out
|
|
|
|
|
+ (if (coll? val) (seq val) (some? val))))
|
|
|
|
|
+ (map #(get-selected-tests test-namespaces test-vars (select-keys options [%])))
|
|
|
|
|
+ (map #(set (find-matching-test-vars % test-vars)))
|
|
|
|
|
+ (apply set/intersection)))
|
|
|
|
|
+
|
|
|
|
|
+;; Main test functionality
|
|
|
|
|
+;; =======================
|
|
|
|
|
|
|
|
(def cli-options
|
|
(def cli-options
|
|
|
[["-h" "--help"]
|
|
[["-h" "--help"]
|
|
@@ -76,49 +140,45 @@ returns run options for selected tests to run"
|
|
|
:multi true
|
|
:multi true
|
|
|
:update-fn conj
|
|
:update-fn conj
|
|
|
:desc "Exclude tests that have this keyword"]
|
|
:desc "Exclude tests that have this keyword"]
|
|
|
|
|
+ ;; --test is long name for compatability with older runner
|
|
|
|
|
+ ["-v" "--test VAR" "Fully qualified var to test"
|
|
|
|
|
+ :id :vars
|
|
|
|
|
+ :default #{}
|
|
|
|
|
+ :default-desc ""
|
|
|
|
|
+ :parse-fn symbol
|
|
|
|
|
+ :multi true
|
|
|
|
|
+ :update-fn conj]
|
|
|
["-n" "--namespace NAMESPACE"
|
|
["-n" "--namespace NAMESPACE"
|
|
|
:parse-fn symbol :desc "Specific namespace to test"]
|
|
:parse-fn symbol :desc "Specific namespace to test"]
|
|
|
["-r" "--namespace-regex REGEX"
|
|
["-r" "--namespace-regex REGEX"
|
|
|
:parse-fn re-pattern :desc "Regex for namespaces to test"]])
|
|
:parse-fn re-pattern :desc "Regex for namespaces to test"]])
|
|
|
|
|
|
|
|
-;; Necessary to have test-data in this ns for freshness. Relying on
|
|
|
|
|
-;; node/reset-test-data! was buggy
|
|
|
|
|
|
|
+;; get-test-data is a macro so this namespace REQUIRES :dev/always hint ns so
|
|
|
|
|
+;; that it is always recompiled
|
|
|
(defn ^:dev/after-load reset-test-data! []
|
|
(defn ^:dev/after-load reset-test-data! []
|
|
|
(-> (env/get-test-data)
|
|
(-> (env/get-test-data)
|
|
|
(env/reset-test-data!)))
|
|
(env/reset-test-data!)))
|
|
|
|
|
|
|
|
-;; This is a patched version of https://github.com/thheller/shadow-cljs/blob/f271b3c40d3ccd4e587b0ffeaa2713d2f642114a/src/main/shadow/test/node.cljs#L44-L56
|
|
|
|
|
-;; that consistently works for all symbols
|
|
|
|
|
-(defn find-matching-test-vars [test-syms]
|
|
|
|
|
- (let [test-namespaces
|
|
|
|
|
- (->> test-syms (filter simple-symbol?) (set))
|
|
|
|
|
- test-var-syms
|
|
|
|
|
- (->> test-syms (filter qualified-symbol?) (set))]
|
|
|
|
|
- (->> (env/get-test-vars)
|
|
|
|
|
- (filter (fn [the-var]
|
|
|
|
|
- (let [{:keys [ns] :as m} (meta the-var)]
|
|
|
|
|
- (or (contains? test-namespaces ns)
|
|
|
|
|
- ;; PATCH: (symbol SYMBOL SYMBOL) leads to buggy equality behavior
|
|
|
|
|
- ;; in cljs. In clj, this throws an exception. Modified to
|
|
|
|
|
- ;; (symbol STRING STRING) to avoid bug
|
|
|
|
|
- (contains? test-var-syms
|
|
|
|
|
- (symbol (name ns) (name (:name m)))))))))))
|
|
|
|
|
|
|
+(defn- run-tests
|
|
|
|
|
+ [test-namespaces test-vars options]
|
|
|
|
|
+ ;; We define a custom runner so we can inherit behavior from the default
|
|
|
|
|
+ ;; runner and improve on it
|
|
|
|
|
+ (let [test-env (ct/empty-env ::node)
|
|
|
|
|
+ selected-vars (get-selected-vars test-namespaces test-vars options)]
|
|
|
|
|
+
|
|
|
|
|
+ (if (some? selected-vars)
|
|
|
|
|
+ ;; Don't run tests if none are selected
|
|
|
|
|
+ (let [test-vars (if (empty? selected-vars) [] selected-vars)]
|
|
|
|
|
+ (st/run-test-vars test-env test-vars))
|
|
|
|
|
+ (st/run-all-tests test-env nil))))
|
|
|
|
|
|
|
|
(defn main [& args]
|
|
(defn main [& args]
|
|
|
- ;; Load test data as is done with shadow.test.node/main
|
|
|
|
|
(reset-test-data!)
|
|
(reset-test-data!)
|
|
|
|
|
|
|
|
(let [{:keys [options summary]} (parse-options args cli-options)]
|
|
(let [{:keys [options summary]} (parse-options args cli-options)]
|
|
|
(if (:help options)
|
|
(if (:help options)
|
|
|
(do
|
|
(do
|
|
|
(print-summary summary
|
|
(print-summary summary
|
|
|
- "\n\nNone of these options can be composed. Defaults to running all tests")
|
|
|
|
|
|
|
+ "\n\nMultiple options are ANDed. Defaults to running all tests")
|
|
|
(js/process.exit 0))
|
|
(js/process.exit 0))
|
|
|
- (with-redefs [node/find-matching-test-vars find-matching-test-vars]
|
|
|
|
|
- (let [opts (run-test-options (keys (env/get-tests)) (env/get-test-vars) options)]
|
|
|
|
|
- ;; If :test-syms is specified but empty, skip execute-cli because the
|
|
|
|
|
- ;; user has specified an empty test selection
|
|
|
|
|
- (if (and (seq opts) (empty? (:test-syms opts)))
|
|
|
|
|
- (do (println "No tests found.")
|
|
|
|
|
- (js/process.exit 0))
|
|
|
|
|
- (node/execute-cli opts)))))))
|
|
|
|
|
|
|
+ (run-tests (keys (env/get-tests)) (env/get-test-vars) options))))
|