How to test with sessions in Hanami?

Romain Champourlier
JobTeaser Engineering
3 min readApr 16, 2017

Are you using Hanami and wonder how you’re gonna test your controller actions that rely on sessions? I did too! While this is probably not the only (nor the best) way to do it, here are the solutions I used.

Table of contents

  1. Enabling sessions in Hanami
  2. Session in action unit tests
  3. Bonus: on using binding.pry within an action’s #call method
  4. Sessions in feature tests

Enabling sessions in Hanami

First, let’s review how sessions are enabled in Hanami:

# apps/your_app/application.rb
# ...
sessions :cookie, secret: ENV[‘YOUR_APP_SESSIONS_SECRET’]
# ...

Sure, that’s only the basics. See the doc for the details.

Session in action unit tests

While relatively easy once you know it, I did struggle a bit to understand how I was supposed to specify my session in action unit tests. I kinda stubbled upon the solution by calling show-method session within a pry inside my action.

So, what does it gives us? (if you got unexpected results while using binding.pry — like just nothing happens and the request get’s stuck — check the bonus below):

2.3.3 (#<Web::Controllers::Home::Index:0x007f96a64a7768>):0 > show-method sessionFrom: …/gems/hanami-controller-1.0.0/lib/hanami/action/session.rb @ line 60:
Owner: Hanami::Action::Session
Visibility: public
Number of lines: 3
def session
@_env[SESSION_KEY] ||= {}
end

Well, that’s a first step in our understanding of Hanami’s sessions! Now, let’s say you’re injecting params in your action’s test:

action.call(some: ‘param’)

Now, in your binding.pry again, let’s discover what’s in @_env:

2.3.3 (#<Web::Controllers::Home::Index:0x007fad14b93980>):0 > @_env
=> {
:some => “param”
}

Well, now we have everything we need! Here’s how we can inject a session in our action!

action.call(some: ‘param’, Hanami::Action::BaseParams::RACK_SESSION => session_hash)

So, let’s recap with a full example:

describe Web::Controllers::Home::Index do
let(:action) { Web::Controllers::Home::Index.new }
let(:session) { { key: ‘value’ } }
let(:params) { { ‘rack.session’ => session } }
it ‘works’ do
response = action.call(params)
end
end

And here you go, injecting content in your session in action unit tests!

Bonus: on using `binding.pry` within an action

There’s an issue between Pry and Hanami, so it’s not possible to call binding.pryfrom a Hanami action #call (see this Github issue for details). If you need it, define a #bind method like this and call it instead:

module YourApp::Controllers::Home
class Index
def call(params)
# ...
bind
end
def bind
binding.pry
end
end
end

Sessions in feature tests

In a feature test, you can’t inject your session inside your action’s #call method’s params since you don’t perform this call yourself. So the solution I used is to override the session method of the action. I’m using a simple SessionMock module you may find in this gist.

Here’s how you may use it:

module Web::Controllers::Home::Index
include Web::Action
include SessionMock
end

I don’t really like this solution since it means you must make a change in your action for testing. But I’m pretty sure we can work something out to handle this through meta-programming magic in test initialization! At this point, I’m happy with it since it’s pretty simple and easy to understand.

I also tried to inject content in the @_env instance variable but I couldn’t. It is probably managed in the calling stack of the action, so it did not seem easy to change.

Closing up

Hanami is a pretty nice web framework, but it’s still young and you may get slowed down with some things you’re used to do easily with older frameworks, like Rails or Sinatra. One of them is testing with sessions, and I hope this article will help you with it!

If you find this article and solution useful, do not hesitate to tell me, that would encourage me to improve it and maybe build a gem around it for easier use. So feel free to comment or ask questions :)

--

--

Romain Champourlier
JobTeaser Engineering

Open-minded and empathic (hopefully) human, trying to reduce GHG emissions with software. Previously CTO/VPEng @ JobTeaser (French HR-tech scale-up)