cider

2024-11-13T17:15:37.639949Z

i develop an alternative test framework called #lazytest that supports running tests from the repl. i don't use emacs or CIDER so I'm unfamiliar with how it works, but someone has asked for help on getting the CIDER keybinds/workflow to integrate with lazytest. i use neovim and have instructions for neovim (conjure) and calva and intellij, but i'd love for some help with CIDER. can one of you help me/us?

2024-11-13T17:16:04.191529Z

https://github.com/NoahTheDuke/lazytest?tab=readme-ov-file#editor-integration has the existing "Editor Integration" instructions

2024-11-13T17:17:50.627019Z

in short, you can call (lazytest.repl/run-all-tests) to run all loaded tests, (lazytest.repl/run-tests ) to run the tests in a given namespace, or (lazytest.repl/run-test-var #') to run a given var's test (either a defdescribe test var or a function with :test metadata, which lazytest supports). All three functions also support an optional trailing config map, so you can say (lazytest.repl/run-test-var #'example-var {:reporter [lazytest.reporters/nested]}) and it "just works"

2024-11-13T17:18:51.919499Z

i know CIDER has a whole test integration toolbox for looking at stack traces and jumping to errors etc. I don't expect to copy all of that, just a way to say "add X to your emacs config and you can run tests under your cursor with a keybind" or similar

2024-11-13T17:56:20.020489Z

so basically cider testing functionality allows you to run single test, all tests inside a ns and all tests in a project. Under the hood I think it uses clojure.test which runs all vars with a :test meta

2024-11-13T17:59:01.095609Z

that said you can easily create some elisp function to run whatever function you want runtime side like this :

(defun run-all-lazy-tests ()
  (interactive)
  (let* ((current-ns (cider-current-ns)))
    (cider-interactive-eval "(lazytest.repl/run-all-tests)"
                            nil
                            nil
                            `(("ns" ,current-ns)))))

2024-11-13T17:59:26.544469Z

those are interactive functions, so you can run them by command name or assign a keybinding

2024-11-13T18:00:05.290239Z

cool, thanks

2024-11-13T18:00:25.817279Z

yeah, this is wholly separate from clojure.test, no overlap at all, so i can't rely on the clojure.test functionality

2024-11-13T18:01:39.209419Z

then maybe you can create a couple elisp functions like that for calling lazytest.repl functions

2024-11-13T18:03:11.300069Z

let me try to create those functions for your description

2024-11-13T18:06:43.602919Z

thank you, that's kind of you

2024-11-13T18:10:08.002029Z

these seams to work :

(defun lazy-tests-run-var ()
  (interactive)
  (let* ((current-ns (cider-current-ns))
         (var (cider-last-sexp)))
    (cider-interactive-eval (format "(lazytest.repl/run-test-var #'%s)" var)
                            nil
                            nil
                            `(("ns" ,current-ns)))))

(defun lazy-tests-run-ns ()
  (interactive)
  (let* ((current-ns (cider-current-ns)))
    (cider-interactive-eval (format "(lazytest.repl/run-tests '%s)" current-ns)
                            nil
                            nil
                            `(("ns" ,current-ns)))))

(defun lazy-tests-run-all ()
  (interactive)
  (let* ((current-ns (cider-current-ns)))
    (cider-interactive-eval "(lazytest.repl/run-all-tests)"
                            nil
                            nil
                            `(("ns" ,current-ns)))))

2024-11-13T18:11:07.013629Z

I tried them with :

(ns lazytest.repl)

(defn run-test-var [v] (println "Running" v))
(defn run-tests [ns] (println "Running ns" ns))
(defn run-all-tests [] (println "Running all tests"))

2024-11-13T18:11:20.693769Z

and seams to be printing the correct messages when I fire those commands

2024-11-13T18:12:31.689119Z

hell yeah, thank you so much

2024-11-13T18:12:46.103019Z

you are welcome!

2024-11-13T18:21:28.512289Z

if you use this instead for the var one :

(defun lazy-tests-run-var ()
  (interactive)
  (let* ((current-ns (cider-current-ns))
         (var (cider--extract-test-var-at-point))
         (var-ns (first var))
         (var-name (second var)))
    (cider-interactive-eval (format "(lazytest.repl/run-test-var #'%s/%s)" var-ns var-name)
                            nil
                            nil
                            `(("ns" ,current-ns)))))
then you don't need to run the lazy-tests-run-var command with the cursor on the var name, you can do it on the body of the form. But I'm not sure it will work with your tests forms, to find the test var name cider does some fancy lookup for "the var" by looking at its highlighting 😅, and checks it contains :test meta

2024-11-13T18:22:18.257759Z

yeah, cider--extract-test-var-at-point doesn't quite work, i looked at that earlier. if there's an extract-root-form or similar then that could be used