clojurescript 2025-05-12

i have a macro that returns a call to deftest in clojure, and i'm trying to port it to clojurescript. the issue is that when called from another namespace, i need to have referred clojure.test already (because clojurescript lacks vars).

(ns opticlj.clojure-test
  (:require
   #?(:clj [clojure.test :refer [deftest is]]
      :cljs [clojure.test :refer-macros [deftest is]])
   #?(:clj [opticlj.core :as optic :refer [defoptic]]
      :cljs [opticlj.core :as optic :refer-macros [defoptic]])))

(defmacro defcram
  [test-name & body]
  (let [kw (keyword (str *ns*) (name test-name))]
    `(do (defoptic ~kw [~@body])
         (deftest ~test-name
           (is (optic/check (optic/run ~kw)))))))

> because clojurescript lacks vars

is not relevant to this in any way really

😮 1

things just get a bit confusing sometimes when youre mixing cljs/clj in weird ways

(ns opticlj.clojure-test
  (:require
    [clojure.test :refer [deftest is]]
    [opticlj.core :as optic :refer [defoptic]]
    ))

should be all you need. no need for those reader conditional gymnastics

the issue is in opticlj.cram-test:

(ns opticlj.cram-test
  (:require [opticlj.clojure-test :refer [defcram]]))

(defcram example-cram
  (= 6 (+ 3 3)))
produces:
------ WARNING #1 - :undeclared-ns ---------------------------------------------
 File: /Users/noah/personal/opticlj/test/opticlj/cram_test.cljc:4:1
--------------------------------------------------------------------------------
   1 | (ns opticlj.cram-test
   2 |   (:require [opticlj.clojure-test :refer [defcram]]))
   3 |
   4 | (defcram example-cram
-------^------------------------------------------------------------------------
 No such namespace: clojure.test, could not locate clojure/test.cljs, clojure/test.cljc, or JavaScript source providing "clojure.test"
and a bunch more errors

my apologies for not including that initially

ns opticlj.clojure-test again needs (:require-macros [opticlj.clojure-test])

i tried that, same issue

with macros using other macros its best to just use fully qualified names

(defmacro defcram
  [test-name & body]
  (let [kw (keyword (str *ns*) (name test-name))]
    `(do (defoptic ~kw [~@body])
         (clojure.test/deftest ~test-name
           (is (optic/check (optic/run ~kw)))))))

oh and which shadow-cljs version do you use? a rather long time ago there was a bug where aliasing didn't work

thheller/shadow-cljs {:mvn/version "2.28.21"}

technically clojure.test doesn't exist in CLJS, it is cljs.test. but there is aliasing in place that should take care of it

ok thats new enough

could be that this is a weird edge case that makes the aliasing fail

if you setup a repro I can take a look

$ npx shadow-cljs compile node-test && node target/shadow-node-test/node-tests.js
shadow-cljs - config: /Users/noah/personal/opticlj/shadow-cljs.edn
shadow-cljs - starting via "clojure"
[:node-test] Compiling ...
[:node-test] Build completed. (171 files, 3 compiled, 4 warnings, 2.51s)

------ WARNING #1 - :undeclared-ns ---------------------------------------------
 File: /Users/noah/personal/opticlj/test/opticlj/cram_test.cljc:4:1
--------------------------------------------------------------------------------
   1 | (ns opticlj.cram-test
   2 |   (:require [opticlj.clojure-test :refer [defcram]]))
   3 |
   4 | (defcram example-cram
-------^------------------------------------------------------------------------
 No such namespace: clojure.test, could not locate clojure/test.cljs, clojure/test.cljc, or JavaScript source providing "clojure.test"
--------------------------------------------------------------------------------
   5 |   (= 6 (+ 3 3)))
   6 |
--------------------------------------------------------------------------------

------ WARNING #2 - :undeclared-var --------------------------------------------
 File: /Users/noah/personal/opticlj/test/opticlj/cram_test.cljc:4:1
--------------------------------------------------------------------------------
   1 | (ns opticlj.cram-test
   2 |   (:require [opticlj.clojure-test :refer [defcram]]))
   3 |
   4 | (defcram example-cram
-------^------------------------------------------------------------------------
 Use of undeclared Var clojure.test/test-var
--------------------------------------------------------------------------------
   5 |   (= 6 (+ 3 3)))
   6 |
--------------------------------------------------------------------------------

------ WARNING #3 - :undeclared-var --------------------------------------------
 File: /Users/noah/personal/opticlj/test/opticlj/cram_test.cljc:4:1
--------------------------------------------------------------------------------
   1 | (ns opticlj.cram-test
   2 |   (:require [opticlj.clojure-test :refer [defcram]]))
   3 |
   4 | (defcram example-cram
-------^------------------------------------------------------------------------
 Use of undeclared Var opticlj.cram-test/java
--------------------------------------------------------------------------------
   5 |   (= 6 (+ 3 3)))
   6 |
--------------------------------------------------------------------------------

------ WARNING #4 - :undeclared-var --------------------------------------------
 File: /Users/noah/personal/opticlj/test/opticlj/cram_test.cljc:4:1
--------------------------------------------------------------------------------
   1 | (ns opticlj.cram-test
   2 |   (:require [opticlj.clojure-test :refer [defcram]]))
   3 |
   4 | (defcram example-cram
-------^------------------------------------------------------------------------
 Use of undeclared Var clojure.test/do-report
--------------------------------------------------------------------------------
   5 |   (= 6 (+ 3 3)))
   6 |
--------------------------------------------------------------------------------

Testing opticlj.cljs.core-test

Testing opticlj.cram-test

ERROR in (example-cram) (ReferenceError:NaN:NaN)
Uncaught exception, not in assertion.
expected: nil
  actual: #object[ReferenceError ReferenceError: java is not defined]

Ran 2 tests containing 2 assertions.
0 failures, 1 errors.

i'm running with npx shadow-cljs compile node-test && node target/shadow-node-test/node-tests.js

I can reproduce but it hurts my head thinking about this. the Use of undeclared Var opticlj.cram-test/java suggests this is expanding the CLJ version of is. which makes sense because at this stage it is in CLJ mode executing a CLJ file

it works fine if the aliases aren't involved, so just using cljs.test/is and cljs.test/deftest

the problem is that clojure.test/is actually exists, so the alias doesn't "trigger"

👍 1

thanks for the help