Welcome! Please see the About page for a little more info on how this works.

0 votes
in ClojureScript by

cljs.core/test does not work according to its docstring description.

The definition of cljs.core/test is

(defn test
  "test [v] finds fn at key :test in var metadata and calls it,
  presuming failure will throw exception"
  [v]
  (let [f (.-cljs$lang$test v)]
    (if f
      (do (f) :ok)
      :no-test)))

It's intended use, as far as I understand it, is as such (example copied from the documented Clojure version of the same function at ClojureDocs, https://clojuredocs.org/clojure.core/test#example-542692cac026201cdc326b8a ):

(defn my-function
  "this function adds two numbers"
  {:test #(do
            (assert (= (my-function 2 3) 5))
            (assert (= (my-function 4 4) 8)))}
  ([x y] (+ x y)))

(test #'my-function)  ;equal to (test (var my-function))
=> :ok

So, cljs.core/test enables functions to self-document their capabilities via tests made available in metadata under the :test key.

However, repeating the above in a CLJS environment yields a different result:

(defn my-function
  "this function adds two numbers"
  {:test #(do
            (assert (= (my-function 2 3) 5))
            (assert (= (my-function 4 4) 8)))}
  ([x y] (+ x y)))

(test #'my-function)
=> :no-test

The interesting thing is that, given that I evalated the above in a CLJS REPL, the metadata is available, as far as I can tell:

(meta #'my-function)
=>
{:ns cljs.user,
 :name my-function,
 :file "<cljs repl>",
 :end-column 18,
 :source "my-function",
 :column 1,
 :line 1,
 :end-line 1,
 :arglists ([x y]),
 :doc "this function adds two numbers", 
 :test #object[Function]}

This can be made even clearer by substituting the rather opaque function for a keyword:

(defn my-function
  "this function adds two numbers"
  {:test :just-a-keyword}
  ([x y] (+ x y)))

(meta #'my-function)
=>
{:ns cljs.user,
 :name my-function,
 :file "<cljs repl>",
 :end-column 18,
 :source "my-function",
 :column 1,
 :line 1,
 :end-line 1,
 :arglists ([x y]),
 :doc "this function adds two numbers", 
 :test :just-a-keyword}

I spoke to @theller and @hiredman about this on the Clojurians Slack, and they speculated that cljs.core/test has been repurposed to execute the body of deftests, since the two pieces seem to fit together. Observe:

(require '[cljs.test :as test])
(test/deftest foo (test/is (= 1 2)))
=> #'cljs.user/foo

(test foo)
FAIL in () (<NO_SOURCE_FILE>:1:28)
expected: (= 1 2)
  actual: (not (= 1 2))

:ok

The deftest body is executed and the keyword :ok is returned (regardless of the is result), as can also be gathered from reading definition of cljs.core/test.

If it is true that cljs.core/test has been repurposed in this manner, then two things are also true:

A) If it ever were the intent that cljs.core/test should enable testing :test assertions for defns, that no longer holds.
B) The docstring of cljs.core/test is somewhat misleading.

The first bit of the docstring, "test [v] finds fn at key :test in var metadata and calls it", may be technically correct, but mentions no connection with deftest, and therefore somewhat unhelpful.

The second bit of the docstring, ", presuming failure will throw exception", is certainly not correct when used for deftest - the cljs.test/is macro, which I think is fair to say that most deftests use, catches exceptions and reports instead. I think the original intent is that the execption is thrown, so :ok is not returned, but in this context, that construct fails.

The docstring seems to be a carbon copy of the Clojure version, so possibly, it warrants an update. Or maybe cljs.core/test is simply unused and redundant at this point?

1 Answer

0 votes
by
...