Fork me on GitHub
#clojurescript
<
2019-01-19
>
Karol Wójcik15:01:29

What is your approach for mocking the inner call of http/get in function some-example assuming that http/get should return a channel with some string?

Karol Wójcik15:01:04

I did try something like this:

(t/deftest get-products-test
  (t/testing "should output mocked status"
    (t/async done
             (with-redefs [http/get (fn [_ __] (async/go {:status "great"}))]
               (async/go
                 (t/is (= (async/<! (fablo/get-products {})) "okkkk"))
                 (done))))))
But it seems that the go block does not play nicely with with-redefs. Could you please recommend me some other approach?

joshkh16:01:20

in the past i've used defprotocol to override clj-http / cljs-http functions. it's been a while, but maybe i can dig up some code.

Karol Wójcik16:01:34

To override you mean that the first variable in your functions was a http which implements a Http protocol. Is that so?

Karol Wójcik16:01:08

I think I will do the same

(defn get-products
  [^Http http
   {:keys [results search-string]
    :or {results 5
         search-string "water"}}]

joshkh16:01:35

yeah, something like this (but not entirely)

(defprotocol Http
  (GET    [this url params])
  (POST   [this url params])
  (PUT    [this url params])
  (DELETE [this url params]))

(defn do-http [http method url params]
  (case method
    :get (GET http url params)
    :post (POST http url params)
    :delete (DELETE http url params)
    :put (PUT http url params)
    (GET http url params)))

joshkh16:01:29

can't find a working example at the moment 😉

Karol Wójcik16:01:04

Looks perfect!

Karol Wójcik16:01:29

@U0GC1C09L Btw can I implement only a part of a protocol in Clojure/script? Or do I have to specify implementation for all of methods in Protocol?

joshkh16:01:45

i guess neither? i remember only implementing functions that i wanted to override depending on the context (dev / test).

joshkh16:01:10

but i'm not an expert in the matter!

joshkh16:01:46

(deftype ActualHttp []
  Http
  (GET [this url params]
    (http/get url params))
  (POST [this url params]
    (http/post url params))
  (DELETE [this url params]
    :delete-not-implemented)
  (PUT [this url params]
    :put-not-implemented))

joshkh16:01:09

i guess you could chuck in a test flag somewhere and dispatch a real or mock request

Karol Wójcik16:01:29

@U0GC1C09L I tried to reify Http Protocol in test namespace but I’m unable to do it. 😮 I received an error about calling the function of undefined. But when I try to reify in the same namespace then everythin works like a charm

(defprotocol Http
  "Abstraction over http requests"
  (get [this url opts] "GET http request"))

(get
 (reify Http
   (get [this url opts] (println "Hello")))
 "Hello" {})

joshkh16:01:04

just curious -- are you testing on the jvm or a (headless?) browser?

joshkh17:01:53

admittedly i've never had the need to reify anything

Karol Wójcik17:01:51

Well I don’t know which one is used by figwheel main. I quess that it’s done by JVM

Karol Wójcik17:01:02

but the results are indeed in the browser

joshkh17:01:36

that's beyond my knowledge. 🙂 last time i checked though, clj-http was not browser compatible, and cljs-http was not JVM compatible. that's probably just a tangent but you never know.

Karol Wójcik17:01:03

Hmm. Now I’m talking about regular protocols in Clojurescript. I defined a simple protocol in one namespace

(defprotocol Http
  "Abstraction over http requests"
  (get [this url opts] "GET http request"))
Then I just defined a implementation of a protocol in test namespace like so:
(deftype http []
  Http
  (get [this url opts]
    (println "Hello")))

(get (http.) "" {})
What is very bizzare is that I’m receiving an error:
#object[TypeError TypeError: (intermediate value).get is not a function]
	 (<NO_SOURCE_FILE>)
Completely don’t know why it’s happening

joshkh15:01:34

how can i keep the integrity of a CLJS function name when using :advanced compilation?

(defn ^:export myfunction []
  "abcdefg")
output: function P(){return"abcdefg"} is this a job for externs? but they're for third party libraries, right?

joshkh15:01:36

cheers! but that's what i'm already doing: ^:export

Karol Wójcik16:01:18

Btw how do you try to require your function?

joshkh16:01:16

ah jeez, i wasn't calling it via its nested namespace. my bad.

joshkh16:01:45

someproject.core.myfunction();
"abcdefg"

Karol Wójcik16:01:29

Happy that I could help

joshkh16:01:35

much appreciated!

mfikes17:01:30

FWIW, ^:export doesn't really preserve the function name. All it does is make a non-minified name that points to the original function.

👌 5
Karol Wójcik17:01:20

I completely don’t get it. Why calling a method of instance of deftype in namespace where defprotocol is defined works like a charm while in different namespace calling a method from a instance of deftype throws an error 😮?

Alex Miller (Clojure team)17:01:31

how are you referring to the function?

Alex Miller (Clojure team)17:01:05

protocol functions are functions in the namespace where they are defined, so you need to require the protocol namespace and either refer or qualify the function from the protocol namespace to invoke

Karol Wójcik17:01:14

:man-facepalming:

Karol Wójcik17:01:20

Sorry for the mess

mfikes22:01:20

If you are already a user of Replete for iOS, some new things you may like are the new replete.core, , and replete.http namespaces. 🙂

mfikes22:01:17

(With , you can learn , right on your mobile device.)

🎉 5