re-frame

https://github.com/Day8/re-frame/blob/master/docs/README.md https://github.com/Day8/re-frame/blob/master/docs/External-Resources.md
ruben.hamers 2021-01-22T04:41:06.011Z

Hey, Could someone maybe point me toward some resources that describe how to properly write (unit) tests for re-frame pages or components? What would be best practices here?

p-himik 2021-01-22T08:00:50.012100Z

There's a documentation page on that topic: https://day8.github.io/re-frame/Testing/

ruben.hamers 2021-01-23T07:53:16.021200Z

thx ;)

zendevil 2021-01-22T07:11:31.011700Z

I have the following re-frame handler with which I’m trying to upload a video from a local uri in mobile.

(reg-event-fx
 :upload-shot-video
 (fn [coeffects _]
   (prn "uploading video")
   (let [video {:type "video/mov"
                :uri (-> coeffects :db :shot-video-uri)}
         body (js/FormData.)]
     (prn "uri is " (-> coeffects :db :shot-video-uri))
     (.append body "video" video)
     {:http-xhrio {:method :post
                   :uri (str "<http://d18a6571c2e5.ngrok.io>" "/api/upload-shot-video")
                   :body body
                   :on-success [:upload-success]
                   :on-failure [:upload-error]
                   :response-format (edn/edn-response-format)}})))
Here’s my handler in the server:
(defn upload-shot-video [req]
  (prn "uploading video")
  (prn "video is! " (-&gt; req :params))
  (prn "video is " (-&gt; req :body))
  (<http://clojure.java.io/copy|clojure.java.io/copy> (-&gt; req :body) (<http://clojure.java.io/file|clojure.java.io/file> "./resources/public/video.mov"))
  (r/response {:res "okay!"}))
Even though an Input stream shows up in (-> req :body), and is saved as a file “./resources/public/video.mov”, the file it is saved as is showing up as a file of 0 bytes, suggesting that the data is never sent to the server. How to fix this error?

p-himik 2021-01-22T08:01:43.012400Z

I've seen suggestions for you to check the Network tab in your browser's DevTools. Have you done that? Is the size there larger than 0? If so, then it's something with your server.

p-himik 2021-01-22T08:07:02.012600Z

But your event handler is still strange. Your video is just a map. What do you expect to happen? That something downloads the video with that :type from that :uri?

zendevil 2021-01-22T08:56:08.014900Z

I have checked dev tools but haven’t seen video uploads there after sending the request. I expect the video to be in the inputstream that’s being copied to the file on the server

p-himik 2021-01-22T08:59:52.015100Z

But what video? Your code does not upload any video. It is trying to upload the map {:type "video/mov", :uri ...}. This map is not a video.

p-himik 2021-01-22T09:01:20.015300Z

Here's what your code is essentially doing:

{:http-xhrio {..., :body (doto (js/FormData.) (.append "video" {:type "video/mov", :uri ...}))}}
Nowhere does this code refer to anything video-like, which should be a binary blob.

zendevil 2021-01-22T09:03:01.015600Z

:uri (-&gt; coeffects :db :shot-video-uri)

zendevil 2021-01-22T09:03:22.016200Z

Here the video uri is passed into the map

zendevil 2021-01-22T09:03:40.016900Z

The video uri is saved in another handler when the video is done recording

p-himik 2021-01-22T09:05:39.017300Z

OK. But your code has to use the video data, not its URL.

p-himik 2021-01-22T09:06:01.017700Z

It has to be something like :body (doto (js/FormData.) (.append "video" binary-video-blob)).

zendevil 2021-01-22T09:06:12.018100Z

This is a .mov uri

(-&gt; coeffects :db :shot-video-uri) 

p-himik 2021-01-22T09:07:03.018700Z

What you have is a URL. An address of a thing. What you need is the binary data to which that URL links. The thing itself, not its address.

zendevil 2021-01-22T09:08:38.019500Z

Got it thanks. Do you know how to convert it?

p-himik 2021-01-22T09:12:17.019700Z

I wouldn't call it "convert". In any case, depends. If you initially upload the video to :shot-video-url somewhere in the same app, then just preserve the data as well and feed it to js/FormData. If it's not the same code and you have nothing but the URL, then you will have to download the video and then upload it. Or, if possible, just create adapt your HTTP handler so it can download the video from the URL itself to avoid sending the binary data over the wire one extra time.

zendevil 2021-01-22T09:17:02.019900Z

my question is. Suppose I have the .mov uri of the local file just shot from the phone

zendevil 2021-01-22T09:17:22.020200Z

How to get the blob behind this uri?

p-himik 2021-01-22T09:20:06.020400Z

If your code is executed by a browser, you cannot just magically get that file by a local URL. It's a matter of security - otherwise, any web page could yank any file from your drive. You will have to use &lt;input type="file&gt; and manually specify that file.

zendevil 2021-01-22T09:20:35.020600Z

it’s a react native app

p-himik 2021-01-22T09:21:08.020800Z

And by "local URL" I mean of course the file:// protocol. Sorry, I don't have any experience with either react native or mobile development in general.

zendevil 2021-01-23T08:26:31.021400Z

I have converted it into a blob using js/fetch

zendevil 2021-01-23T08:27:40.021600Z

(reg-event-fx
 :upload-shot-video-server
 (fn [coeffects [_ blob]]
   (let [body (js/FormData.)]
     (.append body "video" blob)
     {:http-xhrio {:method :post
                   :uri (str "<http://d18a6571c2e5.ngrok.io>" "/api/upload-shot-video")
                   :body body
                   :on-success [:upload-success]
                   :on-failure [:upload-error]
                   :response-format (edn/edn-response-format)}}))
 )
(reg-event-fx
 :upload-shot-video
 (fn [coeffects _]
   (prn "uploading video")
   (let [response (js/fetch (-&gt; coeffects :db :shot-video-uri))]
     (try
       (go
         (let [blob (&lt;p! (. (&lt;p! response) blob))]
           (js/console.log "blob is " blob)
           (dispatch [:upload-shot-video-server blob])))
       (catch js/Error e (js/console.log "Error is " e)))
     {})))
And the handler is as follows:
(defn upload-shot-video [req]
  (prn "uploading video")
  (prn "video is! " (-&gt; req :params))
  (prn "video is " (-&gt; req :body))
  (<http://clojure.java.io/copy|clojure.java.io/copy> (-&gt; req :body) (<http://clojure.java.io/file|clojure.java.io/file> "./resources/public/video.mov"))

  
  (let [filename (str (rand-str 100) ".mov")]
    (s3/put-object
     :bucket-name "humboi-videos"
     :key filename
     :file "./resources/public/video.mov"
     :access-control-list {:grant-permission ["AllUsers" "Read"]})
    (db/add-video {:name (-&gt; req :params :name)
                   :uri (str "<https://humboi-videos.s3-us-west-1.amazonaws.com/>" filename)}))
  (r/response {:res "okay!"}))

zendevil 2021-01-23T08:27:52.021800Z

But the saved file is still 0 bytes

p-himik 2021-01-23T11:11:57.022Z

One small issue - don't call dispatch in event handler. Use effect handlers for that. Move all promise machinery into an effect handler. But that's not what causing you problems. (js/console.log "blob is " blob) - does this print out a blob of the correct non-zero size?

zendevil 2021-01-23T12:17:19.022700Z

it prints ellipses for everything Blob related

zendevil 2021-01-23T12:19:06.022900Z

p-himik 2021-01-23T12:25:48.023300Z

Those ellipses are usually clickable.

zendevil 2021-01-23T12:28:19.023500Z

not in this case

zendevil 2021-01-23T12:29:39.023700Z

also how can the dispatch be in an effect handler if it has to be called in a go block?

zendevil 2021-01-23T12:30:35.023900Z

if it has to be called inside a go block, go returns nil, which means that the effect can’t be specified in the re-frame map

p-himik 2021-01-23T12:35:28.024100Z

Try logging (.-size blob) then. Move the whole go block into an effect handler.

zendevil 2021-01-23T12:40:08.024300Z

yes the size is showing as 4462885

zendevil 2021-01-23T12:40:22.024500Z

which means that the blob is correct

p-himik 2021-01-23T12:42:43.025500Z

In that case I have no idea, sorry. Maybe it's something about React Native, maybe I missed something, maybe you haven't shown something that's important. Or maybe it's something else altogether. The next step would be to confirm that the data is sent to the backend. The Network tab in the DevTools should help with that. If the data is not sent, then I have no clue what's going on. If the data is sent, then it's something on your backend.

zendevil 2021-01-23T12:50:04.025700Z

there are absolutely no new entries showing up in the network tab

zendevil 2021-01-23T12:50:13.025900Z

during the request

zendevil 2021-01-23T12:50:45.026200Z

what’s the best way to debug this?

p-himik 2021-01-23T12:51:14.026400Z

No idea. Especially given that you do receive the request on your backend.

zendevil 2021-01-23T13:03:46.026600Z

another strange thing that happens is that the (-> req :body) only contains a single input stream even when I add multiple key value pairs with (.append …)

zendevil 2021-01-23T13:04:32.026800Z

if the data is multipart, then why only a single input stream in body?

zendevil 2021-01-23T13:15:29.027Z

and why no data in (-> req :params) after adding the wrap-multipart-params middleware?

zendevil 2021-01-23T13:38:18.027200Z

after changing to

(.append body "video" blob "video.mov")
from
(.append body "video" blob)
I get the error:
unrecognized request format nil

zendevil 2021-01-23T13:38:58.027900Z

How to fix this?

zendevil 2021-01-23T13:51:31.028100Z

the server is definitely receiving the request. After adding the request format as (json-request-format), I am seeing the following on (-> req :params)

zendevil 2021-01-23T13:51:32.028300Z

{:parts [[“video” {:data {:collector nil, :offset 0, :name “D7A13384-801E-4D72-8912-9FA967BD61AB.mov”, :type “video/quicktime”, :size 1286383, :blobId “17FC5EC0-7B3E-4F9E-A666-0A46AD771FD2"}}]]}

p-himik 2021-01-22T08:00:50.012100Z

There's a documentation page on that topic: https://day8.github.io/re-frame/Testing/

p-himik 2021-01-22T08:01:43.012400Z

I've seen suggestions for you to check the Network tab in your browser's DevTools. Have you done that? Is the size there larger than 0? If so, then it's something with your server.

p-himik 2021-01-22T08:07:02.012600Z

But your event handler is still strange. Your video is just a map. What do you expect to happen? That something downloads the video with that :type from that :uri?

zendevil 2021-01-22T08:56:08.014900Z

I have checked dev tools but haven’t seen video uploads there after sending the request. I expect the video to be in the inputstream that’s being copied to the file on the server

p-himik 2021-01-22T08:59:52.015100Z

But what video? Your code does not upload any video. It is trying to upload the map {:type "video/mov", :uri ...}. This map is not a video.

p-himik 2021-01-22T09:01:20.015300Z

Here's what your code is essentially doing:

{:http-xhrio {..., :body (doto (js/FormData.) (.append "video" {:type "video/mov", :uri ...}))}}
Nowhere does this code refer to anything video-like, which should be a binary blob.

zendevil 2021-01-22T09:03:01.015600Z

:uri (-&gt; coeffects :db :shot-video-uri)

zendevil 2021-01-22T09:03:22.016200Z

Here the video uri is passed into the map

zendevil 2021-01-22T09:03:40.016900Z

The video uri is saved in another handler when the video is done recording

p-himik 2021-01-22T09:05:39.017300Z

OK. But your code has to use the video data, not its URL.

p-himik 2021-01-22T09:06:01.017700Z

It has to be something like :body (doto (js/FormData.) (.append "video" binary-video-blob)).

zendevil 2021-01-22T09:06:12.018100Z

This is a .mov uri

(-&gt; coeffects :db :shot-video-uri) 

p-himik 2021-01-22T09:07:03.018700Z

What you have is a URL. An address of a thing. What you need is the binary data to which that URL links. The thing itself, not its address.

zendevil 2021-01-22T09:08:38.019500Z

Got it thanks. Do you know how to convert it?

p-himik 2021-01-22T09:12:17.019700Z

I wouldn't call it "convert". In any case, depends. If you initially upload the video to :shot-video-url somewhere in the same app, then just preserve the data as well and feed it to js/FormData. If it's not the same code and you have nothing but the URL, then you will have to download the video and then upload it. Or, if possible, just create adapt your HTTP handler so it can download the video from the URL itself to avoid sending the binary data over the wire one extra time.

zendevil 2021-01-22T09:17:02.019900Z

my question is. Suppose I have the .mov uri of the local file just shot from the phone

zendevil 2021-01-22T09:17:22.020200Z

How to get the blob behind this uri?

p-himik 2021-01-22T09:20:06.020400Z

If your code is executed by a browser, you cannot just magically get that file by a local URL. It's a matter of security - otherwise, any web page could yank any file from your drive. You will have to use &lt;input type="file&gt; and manually specify that file.

zendevil 2021-01-22T09:20:35.020600Z

it’s a react native app

p-himik 2021-01-22T09:21:08.020800Z

And by "local URL" I mean of course the file:// protocol. Sorry, I don't have any experience with either react native or mobile development in general.