RCF turns your Rich Comment Forms into tests (in the same file as your functions). Send form or file to REPL to run tests and it squirts dopamine ✅✅✅. It's good, try it!
Features
Deeper goal: a notation for communication
RCF is specifically engineered to support hyperfiddle/photon, our upcoming reactive dialect of Clojure, that we test, document and teach with RCF.
Hype quotes:
Project maturity: CLJ is stable, external users. CLJS is alpha
; stable
{:deps {com.hyperfiddle/rcf {:mvn/version "20220902-130636"}}}
Breaking changes:
:mvn/version "20220827-151056"
test forms no longer return final result:mvn/version "20220405"
maven group-id renamed from hyperfiddle
to com.hyperfiddle
for securityExperimental (master): the current development priority is improving complex async tests in ClojureScript, DX and some experiments with unification.
; development - not currently published
;{:deps {com.hyperfiddle/rcf {:git/url "https://github.com/hyperfiddle/rcf.git" :sha ...}}}
(tests)
blocks erase by default (macroexpanding to nothing), which avoids a startup time performance penalty as well as keeps tests out of prod.
It's an easy one-liner to turn on tests in your dev entrypoint:
(ns user ; user ns is loaded by REPL startup
(:require [hyperfiddle.rcf]))
(hyperfiddle.rcf/enable!)
Tests are run when you send a file or form to your Clojure/Script REPL. In Cursive, that's cmd-shift-L to load the file.
(ns example
(:require [hyperfiddle.rcf :refer [tests tap %]]))
(tests
"equality"
(inc 1) := 2
"wildcards"
{:a :b, :b [2 :b]} := {:a _, _ [2 _]}
"unification"
{:a :b, :b [2 :b]} := {:a ?b, ?b [2 ?b]}
"unification on reference types"
(def x (atom nil))
{:a x, :b x} := {:a ?x, :b ?x}
"multiple tests on one value"
(def xs [:a :b :c])
(count xs) := 3
(last xs) := :c
(let [xs (map identity xs)]
(last xs) := :c
(let [] (last xs) := :c))
(tests
"nested tests (is there a strong use case?)"
1 := 1)
(tests
"REPL bindings work"
(keyword "a") := :a
(keyword "b") := :b
(keyword "c") := :c
*1 := :c
*2 := :b
*3 := :a
*1 := :c ; inspecting history does not affect history
(keyword "d") := :d
*1 := :d
*2 := :c
*3 := :b
(symbol *2) := 'c ; this does affect history
(symbol *2) := 'd))
Loading src/example.cljc...
✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅Loaded
(ns example
(:require [clojure.core.async :refer [chan >! go go-loop <! timeout close!]]
[hyperfiddle.rcf :as rcf :refer [tests tap %]]
[missionary.core :as m]))
(rcf/set-timeout! 100)
(tests
"async tests"
#?(:clj (tests
(future
(rcf/tap 1) (Thread/sleep 10) ; tap value to queue
(rcf/tap 2) (Thread/sleep 200)
(rcf/tap 3))
% := 1 ; pop queue
% := 2
% := ::rcf/timeout)
:cljs (tests
(defn setTimeout [f ms] (js/setTimeout ms f))
(rcf/tap 1) (setTimeout 10 (fn []
(rcf/tap 2) (setTimeout 200 (fn []
(rcf/tap 3)))))
% := 1
% := 2
% := ::rcf/timeout))
"core.async"
(def c (chan))
(go-loop [x (<! c)]
(when x
(<! (timeout 10))
(tap x)
(recur (<! c))))
(go (>! c :hello) (>! c :world))
% := :hello
% := :world
(close! c)
"missionary"
(def !x (atom 0))
(def dispose ((m/reactor (m/stream! (m/ap (! (inc (m/?< (m/watch !x)))))))
(fn [_] #_(prn ::done)) #(prn ::crash %)))
% := 1
(swap! !x inc)
(swap! !x inc)
% := 2
% := 3
(dispose))
To run in CI, configure a JVM flag for RCF to generate clojure.test deftests, and then run them with clojure.test. Github actions example.
; deps.edn
{:aliases {:test {:jvm-opts ["-Dhyperfiddle.rcf.generate-tests=true"]}}}
% clj -M:test -e "(require 'example)(clojure.test/run-tests 'example)"
Testing example
✅✅✅✅✅✅✅✅
Ran 1 tests containing 8 assertions.
0 failures, 0 errors.
{:test 1, :pass 8, :fail 0, :error 0, :type :summary}
(ns dev-entrypoint
(:require [example] ; transitive inline tests will erase
[hyperfiddle.rcf :refer [tests]]))
; wait to enable tests until after app namespaces are loaded
(hyperfiddle.rcf/enable!)
; subsequent REPL interactions will run tests
; prevent test execution during cljs hot code reload
#?(:cljs (defn ^:dev/before-load stop [] (hyperfiddle.rcf/enable! false)))
#?(:cljs (defn ^:dev/after-load start [] (hyperfiddle.rcf/enable!)))
One of my tests threw an exception, but the stack trace is empty? — you want {:jvm-opts ["-XX:-OmitStackTraceInFastThrow"]}
explanation (this may be JVM specific)
I see no output — RCF is off by default, run (hyperfiddle.rcf/enable!)
Emacs has no output and tests are enabled — check if your emacs supports emojis
How do I customize what’s printed at the REPL? — see reporters.clj, reporters.cljs
#hyperfiddle @ clojurians.net
Can you improve this documentation? These fine people already did:
Dustin Getz, Geoffrey Gaillard, TristeFigure, xificurC & Eugen StanEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close