Fork me on GitHub
#fulcro
<
2022-01-22
>
sheluchin13:01:16

Any tips for testing state machines (specifically RAD reports, routers, forms) from the REPL? I'm spending way too much time in the UI trying to see if my changes are good.

Jakub Holý (HolyJak)16:01:01

Cannot you just send them events and observe their state in the DB and their effect on the Transactions?

sheluchin21:01:50

I run into a problem trying to get the same behaviour in my REPL as I do when going through the UI's dynamic router. Right here https://github.com/fulcrologic/fulcro-rad/blob/952278690222ed38d09eb15b28f13f09726d04ce/src/main/com/fulcrologic/rad/report.cljc#L169 the current-parameters ends up a nil each time. I tried doing it through uism/begin! and report/start-report! but neither seems to do the trick.

bbss01:01:34

I do something like this:

(defn my-state-machine []
  (uism/state-machine-env (app/current-state app) ::my.ns/statemachine-id))
then I can call my statemachine event handlers on that env.

❤️ 1
sheluchin13:01:06

@U09MR0T5Y thanks! I think I had bad expectations. I thought I would need to pull the SM from the application state after creating it, but just operating on the returned sm-env is what I should be doing.

Benjamin C17:01:58

I'm having a strange thing happen when I try to get my server working remote instead of on my local network. (I'll add more details in the thread)

1
Benjamin C17:01:44

Seems it is returning the csrf html for some reason. Pretty sure I need to go read up on ring, but I was curious if anyone would know why this might happen off the top of their head and maybe point me in the right direction. 🙂

Benjamin C17:01:10

For example, here is what I found via fulcro-inspect when trying to log-in:

(com.fulcrologic.fulcro.ui-state-machines/trigger-state-machine-event
 {:com.fulcrologic.fulcro.ui-state-machines/asm-id
  :app.model.session/session,
  :com.fulcrologic.fulcro.ui-state-machines/event-id :event/failed,
  :com.fulcrologic.fulcro.ui-state-machines/event-data
  {:com.fulcrologic.fulcro.ui-state-machines/mutation-result
   {:outgoing-request
    {:headers {"Content-Type" "application/transit+json"},
     :body
     "[[\"~#cmap\",[[\"~#list\",[\"~$app.model.session/login\",[\"^ \",\"~:username\",\"user\",\"~:password\",\"letmein\"]]],[\"~:session/valid?\",\"~:account/name\"]]]]",
     :url "",
     :method :post,
     :response-type :default},
    :original-transaction
    [{(app.model.session/login {:username "user", :password "letmein"})
      [:session/valid? :account/name]}],
    :headers
    {"Content-Type" "text/html; charset=utf-8",
     "Date" "Sat, 22 Jan 2022 17:35:37 GMT",
     "X-Xss-Protection" "0; mode=block",
     "Server" "http-kit",
     "Content-Length" "527",
     "Strict-Transport-Security" "max-age=31536000; includeSubDomains",
     "X-Frame-Options" "SAMEORIGIN"},
    :body
> "<!DOCTYPE html>\n<html><html lang=\"en\"><head lang=\"en\"><title>Application</title><meta charset=\"utf-8\"><meta content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" name=\"viewport\"><link href=\"https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css\" rel=\"stylesheet\"><link href=\"data:image/x-icon;,\" rel=\"shortcut icon\" type=\"image/x-icon\"><script>var fulcro_network_csrf_token = '';</script></head><body><div id=\"app\"></div><script src=\"js/main/main.js\"></script></body></html></html>",
:status-code 417,
    :status-text
    "body was either not transit or you have not installed the correct transit read/write handlers.",
    :error :none, 
    :error-text ""}}})

It seems to happen the same way for any API request. 

Benjamin C17:01:14

Seems it is returning the csrf html for some reason. Pretty sure I need to go read up on ring, but I was curious if anyone would know why this might happen off the top of their head and maybe point me in the right direction. 🙂

Benjamin C17:01:26

Here is the relevant router code: (defstate middleware :start (let [session-store (mem/memory-store) defaults-config (-> (:ring.middleware/defaults-config config) ;; If you want to set something like session store, you'd do it against ;; the defaults-config here (which comes from an EDN file, so it can't have ;; code initialized). (assoc-in [:session :store] session-store)) defaults-config-native (-> defaults-config ;; CSRF makes sense only in browser, so we disable it for native ;; and change cookie name to prevent CSRF against this endpoint (assoc-in [:security :anti-forgery] false) (update-in [:session :cookie-name] str "-native"))] (ring/ring-handler (ring/router [["/api" {:middleware [#(wrap-defaults % defaults-config) wrap-transit-response wrap-transit-params wrap-websockets] :post {:summary "Fulcro API" :handler api-handler}}] ["/api-native" {:middleware [#(wrap-defaults % defaults-config-native) wrap-transit-response wrap-transit-params wrap-websockets] :post {:summary "Fulcro API for Native" :handler api-handler}}]]) (-> (fn [req] (-> (resp/response (index req)) (resp/content-type "text/html"))) (wrap-defaults defaults-config) (wrap-websockets) (wrap-keyword-params) (wrap-params)) {:middleware [wrap-gzip]})))

Jakub Holý (HolyJak)17:01:39

And your api handler is bound to the /native-api path? I whould add logs to the handler and middleware...

Benjamin C18:01:19

Yes, it is based of the fulcro-mobile template.

Benjamin C18:01:55

Yep, that's what I'm doing right now. 🙂 (adding logging) Thanks, I'll take a look at that. The funny part is that it all works fine on my local network. But when I run it on the server part on my digital ocean droplet, it doesn't.

Jakub Holý (HolyJak)18:01:36

It's possible it has a proxy in the middle that changes the path. Change your handler to include the request path the handler sees in a resounds handler to check that. See https://blog.jakubholy.net/2020/troubleshooting-friendly-responses/

Benjamin C18:01:20

path seems fine as far as I can tell:

{:reitit.core/router #object[reitit.core$lookup_router$reify__32072 0x128cd8c8 "reitit.core$lookup_router$reify__32072@128cd8c8"],
 :cookies {},
 :remote-addr "216.137.253.17",
 :params {},
 :headers {"accept-encoding" "gzip",
           "connection" "Keep-Alive",
           "content-length" "139",
           "content-type" "application/transit+json",
           "host" "137.184.148.128:3050",
           "user-agent" "okhttp/3.14.9"},
 :async-channel #object[org.httpkit.server.AsyncChannel 0x605d25df "/137.184.148.128:3050<->/216.137.253.17:49146"],
 :server-port 3050,
 :content-length 139,
 :form-params {},
 :websocket? false,
 :session/key nil,
 :query-params {},
 :content-type "application/transit+json",
 :character-encoding "utf8",
 :uri "/native-api",
 :server-name "137.184.148.128",
 :query-string nil,
 :body #object[org.httpkit.BytesInputStream 0x71486970 "BytesInputStream[len=139]"],
 :multipart-params {},
 :scheme :http,
 :request-method :post,
 :session {}}
I originally put the logging function in the api-handler, and nothing showed up, so I know that something is causing it to not trigger.

Benjamin C18:01:50

I am going to try it local again and see if the comparison of the log is insightful.

Jakub Holý (HolyJak)19:01:28

Weird. I would ask in the #reitit channel for troubleshooting tips. Please share when you find the issue!

Benjamin C19:01:36

Okay, that was hilarious mistake to make - Turns out your first question was right on point: > And your api handler is bound to the /native-api path? it is actually bound to api-native, but with my dyslexia I didn't even notice. 😛 The reason it only showed up when using the remote server was beause I was using shadow-cljs.edn to override the server variable when running locally like so:

:closure-defines {app.client-native/SERVER_URL ""}

Benjamin C19:01:59

Thank you so much for your help! 😄