33

I am developing an app for Shopify and I want to do integration testing.

I need to be able to store some values in the session variable, so that authentication works.

How could I do that?

I use Capybara and Capybara-webkit.

Nerian
  • 15,901
  • 13
  • 66
  • 96
  • 1
    In integration testing, you should log users from the login forms. – apneadiving Dec 17 '11 at 18:49
  • 1
    That won't work. The key issue is that I am using an external authentication system: Shopify. So Shopify is configured to return a successful log-in to a specific URL. Do see the problem? That URL can't be localhost. That's why I need to fake the log in process, even if I am in Integration testing – Nerian Dec 17 '11 at 20:53
  • how can i use the same for cucumber in shopify app? – Navin Bista Jun 14 '18 at 08:07

5 Answers5

33

The accepted answer suggests rack_session_access. It works by inserting middleware controllers to edit and update the session state, then has capybara visit that page and submit a form with the session data. Very ingenious! But unnecessary if you are using Warden (directly or through Devise).

Warden has a hook on_next_request that gives access to the warden mechanism, which can be used to set session keys directly. I threw this together to bundle it up in rspec:

Create spec/support/inject_session.rb:

module InjectSession
  include Warden::Test::Helpers

  def inject_session(hash)
    Warden.on_next_request do |proxy|
      hash.each do |key, value|
        proxy.raw_session[key] = value
      end
    end
  end
end

In spec/spec_helper.rb include the module in feature specs:

RSpec.configure do |config|
    config.include InjectSession, :type => :feature
end

Then sample use in a spec might be:

   inject_session :magic => 'pixie dust', :color => 'pink' 
   visit shopping_cart_path
   page.should be_all_sparkly_and_pink # or whatever
ronen
  • 2,529
  • 26
  • 23
  • @YossiShasho in what way does it not work? it seems to work fine for me, currently with devise 3.2.4 and warden 1.2.3 – ronen Oct 04 '14 at 10:35
  • I honestly don't remember what went wrong, but i didn't try too hard to resolve it. Just went ahead with the `rack_session_access ` gem suggested above, which worked fine. – Yossi Shasho Oct 05 '14 at 07:49
  • I would have preferred this solution very much. Did not work unfortunately so I also switched to rack_session_access (Ruby 2.2, Rails 4.2) – awenkhh Jan 23 '15 at 13:37
  • This also works for me on Rails 4.2, Devise 3.4.1 etc. – Thibaut Barrère Jun 09 '15 at 08:37
  • Man you make may day better! Working here Devise 4.5.0 and Rails 5.2.1. Thank you! <3 – Washington Botelho Aug 18 '18 at 13:25
  • I just wanted to mention that we need to ask Rails (at least in Rails > 6) to autoload this new folder. We can do this by adding this line in the `rails_helper.rb`: `Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require(f) }` – Gustavo G. Mar 09 '22 at 13:57
27

Just found rack_session_access gem and working as a charm.

fguillen
  • 36,125
  • 23
  • 149
  • 210
4

You can use something like VCR or webmock to stub out the call to the external http resource.

Brice Stacey
  • 350
  • 2
  • 8
4

As the comment by apneadiving recommends, you should fill the form out "directly" using capybara. Testing using Cucumber might look like this for filling in a login form for authentication (from the Capybara github page):

When /I sign in/ do
  within("#session") do
    fill_in 'Login', :with => 'user@example.com'
    fill_in 'Password', :with => 'password'
  end
  click_link 'Sign in'
  ...
end

If you trying to do something different or are having trouble with the normal login process, this SO question may help.

Community
  • 1
  • 1
SnapShot
  • 5,464
  • 5
  • 42
  • 40
  • That won't work. The key issue is that I am using an external authentication system: Shopify. So Shopify is configured to return a successful log-in to a specific URL. Do see the problem? That URL can't be localhost. That's why I need to fake the log in process, even if I am in Integration testing. – Nerian Dec 17 '11 at 20:52
  • 1
    @Nerian see if you can use https://github.com/myronmarston/vcr to record that external request to your local environment, then you can use this method. – Christopher Manning Dec 22 '11 at 07:50
3

I fear I bring bad news, but from Capybara's documentation:

Access to session and request is not possible from the test, Access to response is limited.

So you won't be able to test as you expect.


Just thinking: it would be acceptable that you insert some conditional statement in your controller for test purpose.:

 session[:foo] = User.first.id if Rails.env.test?

A better option would be to monkey patch your controller only for your integration tests.

apneadiving
  • 114,565
  • 26
  • 219
  • 213
  • 3
    This is possible, but feels like a code smell - injecting test code into your production application? It would be preferable to re-write your tests, if you can. – Taryn East Mar 14 '16 at 22:32