浏览代码

Add shadow test runner that provides most test-runner like options

Gabriel Horner 3 年之前
父节点
当前提交
35d2023e24
共有 5 个文件被更改,包括 98 次插入6 次删除
  1. 2 1
      .carve/ignore
  2. 0 1
      deps.edn
  3. 8 3
      docs/dev-practices.md
  4. 2 1
      shadow-cljs.edn
  5. 86 0
      src/test/frontend/test_runner.cljs

+ 2 - 1
.carve/ignore

@@ -65,4 +65,5 @@ frontend.util.pool/terminate-pool!
 ;; Repl fn
 frontend.util.property/add-page-properties
 ;; Used by shadow
-frontend.worker.parser/init
+frontend.test-runner/main
+

+ 0 - 1
deps.edn

@@ -43,7 +43,6 @@
            :test {:extra-paths ["src/test/"]
                   :extra-deps  {org.clojure/clojurescript        {:mvn/version "1.10.879"}
                                 org.clojure/test.check           {:mvn/version "1.1.1"}
-                                org.clojars.lucywang000/shadow-test-utils {:mvn/version "0.0.2"}
                                 org.clojars.knubie/cljs-run-test {:mvn/version "1.0.1"}}
                   :main-opts   ["-m" "shadow.cljs.devtools.cli"]}
 

+ 8 - 3
docs/dev-practices.md

@@ -86,8 +86,13 @@ shadow-cljs watch test --config-merge '{:autorun true :ns-regexp
 #### Focus Tests
 
 Tests can be automatically compiled and then selectively run on the commandline
-using https://github.com/lucywang000/shadow-test-utils. For this workflow:
+using our own test runner which emulates most of the options of [cognitect-labs/test
+runner](https://github.com/cognitect-labs/test-runner#invoke-with-clojure--m-clojuremain).
+For this workflow:
 
 1. Run `clj -M:test watch test` in one shell
-2. Focus a test by adding a `^:focus` metadata flag
-3. In another shell, run `node node static/tests.js`
+2. Focus tests or namespaces:
+  1. To focus test(s), add `^:focus` metadata flags. In another shell, run `node static/tests.js -i focus`
+  2. Alternatively, focus namespaces by using the regex option e.g. `node static/tests.js -r text` which runs tests for `frontend.text-test`.
+
+For help on more focusing options, run `node static/tests.js -h`

+ 2 - 1
shadow-cljs.edn

@@ -61,7 +61,8 @@
   :test {:target          :node-test
          :output-to       "static/tests.js"
          :closure-defines {frontend.util/NODETEST true}
-         :devtools        {:enabled false}}
+         :devtools        {:enabled false}
+         :main            frontend.test-runner/main}
 
   :publishing {:target        :browser
                :module-loader true

+ 86 - 0
src/test/frontend/test_runner.cljs

@@ -0,0 +1,86 @@
+(ns frontend.test-runner
+  "shadow-cljs test runner for :node-test that provides most of the same options
+  as
+  https://github.com/cognitect-labs/test-runner#invoke-with-clojure--m-clojuremain.
+  This gives the user a fair amount of control over which tests and namespaces
+  to call from the commandline. Once this test runner is stable enough we should
+  contribute it upstream"
+  (:require [shadow.test.env :as env]
+            [clojure.tools.cli :as cli]
+            [shadow.test.node :as node]
+            [clojure.string :as str]
+            ["util" :as util]))
+
+(defn- print-summary
+  "Print help summary given args and opts strings"
+  [options-summary additional-msg]
+  (println (util/format "Usage: %s [OPTIONS]\nOptions:\n%s%s"
+                        "$0"
+                        options-summary
+                        additional-msg)))
+
+(defn- parse-options
+  "Processes a command's functionality given a cli options definition, arguments
+  and primary command fn. This handles option parsing, handles any errors with
+  parsing and then returns options"
+  [args cli-opts & parse-opts-options]
+  (let [{:keys [errors] :as parsed-input}
+        (apply cli/parse-opts args cli-opts parse-opts-options)]
+    (if (seq errors)
+      (do (println (str/join "\n" (into ["Options failed to parse:"] errors)))
+        (js/process.exit 1))
+      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]}]
+  (let [focused-tests (cond
+                        (seq include)
+                        (map symbol (filter (fn [v]
+                                              (let [metadata (meta v)]
+                                                (some metadata include)))
+                                            vars))
+                        exclude
+                        (map symbol (remove (comp exclude meta) vars)))
+        test-syms (cond (some? focused-tests)
+                    focused-tests
+                    namespace
+                    [namespace]
+                    namespace-regex
+                    (filter #(re-find namespace-regex (str %)) namespaces))]
+    ;; NOTE: If include points to a nonexistent metadata flag, this results in test-syms being '().
+    ;; We would expect no tests to run but instead the node test runner runs all tests.
+    ;; We may want to workaround this
+    (cond-> {}
+            (some? test-syms)
+            (assoc :test-syms test-syms))))
+
+(def cli-options
+  [["-h" "--help"]
+   ["-i" "--include INCLUDE"
+    :default #{}
+    :parse-fn keyword
+    :multi true :update-fn conj
+    :desc "Run only tests with this metadata keyword. Can be specified more than once"]
+   ;; TODO: Fix and enable once it's determined if this is an internal or shadow bug
+   #_["-e" "--exclude EXCLUDE" :parse-fn keyword]
+   ["-n" "--namespace NAMESPACE"
+    :parse-fn symbol :desc "Specific namespace to test"]
+   ["-r" "--namespace-regex REGEX"
+    :parse-fn re-pattern :desc "Regex for namespaces to test"]])
+
+(defn main [& args]
+  ;; Load test data as is done with shadow.test.node/main
+  (node/reset-test-data!)
+
+  (let [{:keys [options summary]} (parse-options args cli-options)]
+    (if (:help options)
+      (do
+        (print-summary summary
+                       "\n\nNone of these options can be composed. Defaults to running all tests")
+        (js/process.exit 0))
+      (node/execute-cli
+       (run-test-options (keys (env/get-tests)) (env/get-test-vars) options)))))