From a08c7ff22e8c66d6f34f224c075125691403dcb4 Mon Sep 17 00:00:00 2001 From: yqrashawn Date: Wed, 3 Aug 2022 22:14:20 +0800 Subject: [PATCH] feat: add repl support for cljs test (#13754) --- shadow-cljs.edn | 17 +++-- src/status_im/integration_test.cljs | 9 ++- src/status_im/test_runner.cljs | 104 ++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 src/status_im/test_runner.cljs diff --git a/shadow-cljs.edn b/shadow-cljs.edn index 0198e3d411..def3554ec6 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -70,17 +70,20 @@ ;; produced by the target :mocks below and redefines node require ;; function to use the mocks instead of the rn libraries :test - {:output-to "target/test/test.js" - :output-dir "target/test" - :optimizations :simple - :target :node-test - :closure-defines {status-im.utils.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"} + {:output-to "target/test/test.js" + :output-dir "target/test" + :optimizations :simple + :target :node-test + :main status-im.test-runner/main + ;; set :ui-driven to true to let shadow-cljs inject node-repl + :ui-driven true + :closure-defines {status-im.utils.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"} :compiler-options {;; needed because we override require and it ;; messes with source-map which reports callstack ;; exceeded exceptions instead of real issues - :source-map false + :source-map false ;; needed because we use deref in tests - :static-fns false + :static-fns false :optimizations :simple}} ;; mock.js-dependencies is mocking the react-native libraries diff --git a/src/status_im/integration_test.cljs b/src/status_im/integration_test.cljs index 4d72c11286..969ca03720 100644 --- a/src/status_im/integration_test.cljs +++ b/src/status_im/integration_test.cljs @@ -1,9 +1,9 @@ (ns status-im.integration-test - (:require [day8.re-frame.test :as rf-test] - status-im.events + (:require [cljs.test :refer [deftest is run-tests]] + [day8.re-frame.test :as rf-test] [re-frame.core :as rf] + status-im.events [status-im.transport.core :as transport] - [cljs.test :refer [deftest is]] [status-im.utils.test :as utils.test])) (def password "testabc") @@ -56,3 +56,6 @@ (rf-test/wait-for ; wait for login [::transport/messenger-started] (assert-messenger-started)))))) + +(comment + (run-tests)) diff --git a/src/status_im/test_runner.cljs b/src/status_im/test_runner.cljs new file mode 100644 index 0000000000..ccfaaa41fd --- /dev/null +++ b/src/status_im/test_runner.cljs @@ -0,0 +1,104 @@ +(ns status-im.test-runner + {:dev/always true} + (:require + [cljs.test :as ct] + [clojure.string :as str] + [shadow.test :as st] + [shadow.test.env :as env])) + +(defonce repl? (atom false)) + +(defmethod ct/report [::ct/default :end-run-tests] [m] + (when-not @repl? + (if (ct/successful? m) + (js/process.exit 0) + (js/process.exit 1)))) + +;; 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! [] + (-> (env/get-test-data) + (env/reset-test-data!))) + +(defn parse-args [args] + (reduce + (fn [opts arg] + (cond + (= "--help" arg) + (assoc opts :help true) + + (= "--list" arg) + (assoc opts :list true) + + (= "--repl" arg) + (assoc opts :repl true) + + (str/starts-with? arg "--test=") + (let [test-arg (subs arg 7) + test-syms + (->> (str/split test-arg ",") + (map symbol))] + (update opts :test-syms into test-syms)) + + :else + (do (println (str "Unknown arg: " arg)) + opts))) + {:test-syms []} + args)) + +(defn find-matching-test-vars [test-syms] + ;; FIXME: should have some kind of wildcard support + (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 [name ns]} (meta the-var)] + (or (contains? test-namespaces ns) + (contains? test-var-syms (symbol ns name))))))))) + +(defn execute-cli [{:keys [test-syms help list repl] :as _opts}] + (let [test-env + (-> (ct/empty-env) + ;; can't think of a proper way to let CLI specify custom reporter? + ;; :report-fn is mostly for UI purposes, CLI should be fine with default report + #_(assoc :report-fn + (fn [m] + (tap> [:test m (ct/get-current-env)]) + (prn m))))] + + (cond + help + (do (println "Usage:") + (println " --list (list known test names)") + (println " --test=, (run test for namespace or single var, separated by comma)") + (println " --repl (start node without automatically running tests)")) + + list + (doseq [[ns ns-info] + (->> (env/get-tests) + (sort-by first))] + (println "Namespace:" ns) + (doseq [var (:vars ns-info) + :let [m (meta var)]] + (println (str " " (:ns m) "/" (:name m)))) + (println "---------------------------------")) + + repl + (do + (reset! repl? true) + (js/process.on "SIGINT" #(js/process.exit 0))) + + (seq test-syms) + (let [test-vars (find-matching-test-vars test-syms)] + (st/run-test-vars test-env test-vars)) + + :else + (st/run-all-tests test-env nil)))) + +(defn ^:export main [& args] + (reset-test-data!) + + (let [opts (parse-args args)] + (execute-cli opts)))