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 deftest
s, 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 defn
s, 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 deftest
s 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?