From e7b4c2c63762a5933e4c385f6b67a0885d6f2bf8 Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 23 Feb 2022 07:37:57 -0500 Subject: [PATCH] Added with-redefs macro and test --- src/promesa/core.cljc | 22 +++++++++++++++++++++- test/promesa/tests/core_test.cljc | 10 ++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/promesa/core.cljc b/src/promesa/core.cljc index eda4646..5618fe0 100644 --- a/src/promesa/core.cljc +++ b/src/promesa/core.cljc @@ -26,7 +26,7 @@ (:refer-clojure :exclude [delay spread promise await map mapcat run! future let loop recur - -> ->> as->]) + -> ->> as-> with-redefs]) (:require [promesa.protocols :as pt] [clojure.core :as c] @@ -535,3 +535,23 @@ ~(if (empty? forms) name (last forms)))) + +(defmacro with-redefs + "Like clojure.core/with-redefs, but it will handle promises in + body and wait until they resolve or reject before restoring the + bindings. Useful for mocking async APIs." + [bindings & body] + (c/let [names (take-nth 2 bindings) + vals (take-nth 2 (drop 1 bindings)) + orig-val-syms (map (comp gensym #(str % "-orig-val__") name) names) + temp-val-syms (map (comp gensym #(str % "-temp-val__") name) names) + binds (map vector names temp-val-syms) + resets (reverse (map vector names orig-val-syms)) + bind-value (fn [[k v]] (list 'alter-var-root (list 'var k) (list 'constantly v)))] + `(c/let [~@(interleave orig-val-syms names) + ~@(interleave temp-val-syms vals)] + ~@(map bind-value binds) + (c/-> (do! ~@body) + (finally + (fn [] + ~@(map bind-value resets))))))) diff --git a/test/promesa/tests/core_test.cljc b/test/promesa/tests/core_test.cljc index 6d9fb01..0282c87 100644 --- a/test/promesa/tests/core_test.cljc +++ b/test/promesa/tests/core_test.cljc @@ -458,3 +458,13 @@ test #(p/then p1 (fn [res] (t/is (= res 8))))] #?(:cljs (t/async done (p/do! (test) (done))) :clj @(test)))) + +(t/deftest with-redefs-macro + (let [a-fn (fn [] (p/resolved "original")) + a-var :original + p1 (p/with-redefs [a-fn (fn [] (p/resolved "mocked")) + a-var :mocked] + (p/then (a-fn) #(vector % a-var))) + test #(p/then p1 (fn [res] (t/is (= res ["mocked" :mocked]))))] + #?(:cljs (t/async done (p/do! (test) (done))) + :clj @(test))))