Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending a mock ring request with session data

I'm trying to unit test a ring app with 'fake' session data using ring.mock.request. But looking at its documentation it doesn't seem to have the functionality.

In the real app, I'm using the ring.middleware.session wrapper:

(defroutes routes
  (GET "/transactions"  [{session :session}]
    (response (str "Hello " (:username session)))))

(def app
  (wrap-session routes))

And in my test:

(app (ring.mock.request/request :get "/transactions"))

But I'm kinda stuck on where to add this 'fake' session data for my request (e.g. something like (ring.mock.request/request :get "/transactions" :session {:username "foo"}).

like image 367
Roberto Paredes Avatar asked Oct 28 '25 19:10

Roberto Paredes


2 Answers

You can use peridot for this. The important feature:

peridot is designed to be used with ->, and maintains cookies across requests in the threading.

(-> (peri/session app)
    (peri/request "/session-setter") ;; this would be the route that *sets* the session value
    (peri/request "/transactions"))

Where /session-setter is a route I added just to set a value in your session:

(GET "/session-setter" []
  {:status 200
   :body "OK"
   :session {:username "Roberto"}})

Ultimately you should get a map like this (I've removed some keys for brevity):

{:response {:status 200,
            :headers {...},
            :body "Hello Roberto"},
 :request {...},
 :cookie-jar {"localhost" {"ring-session" {:value "04110b66-1281-4e88-9470-546911e21ca1",
                                           :path "/",
                                           :domain "localhost",
                                           :raw "ring-session=04110b66-1281-4e88-9470-546911e21ca1",
                                           :http-only true}}}}

Notice in the response, we now see :body "Hello Roberto" which was built using the session key :username.

like image 191
Taylor Wood Avatar answered Oct 30 '25 11:10

Taylor Wood


There is no an option to provide the session data in that mocking library, because it depends on the server part, not the request by itself.

When the session middleware processes the request, it reads the cookie that represents session data signed with a secret key.

The idea is to prepare such a cookie and pass it within a request. But in such case, your test is not a black-box anymore, because you manipulate with some internal stuff that should not be touched and is subject to change.

One option would be to have a special handler available only when running tests that adds session data you need for further processing. In your test, you do two requests: the first one for that handler, and the second one to your normal handler but passing the cookies returned from the first request. That would be the most realistic case.

Another option would be to find a function inside ring.middleware.session guts that adds and signs session data to response. Or redefine some of them using with-redef-fn, what is almost the same.

Take a look at bare-session-request on the link above, the main logic runs in that function.

like image 37
Ivan Grishaev Avatar answered Oct 30 '25 11:10

Ivan Grishaev