开发者

Devise, cucumber, and capybara not authenticating on JSON request

开发者 https://www.devze.com 2023-03-12 08:42 出处:网络
I am using backbone.js with rails.My controller accepts and returns JSON.I had all my tests working fine until I added in devise authentication.I cannot get cucumber to stay authenticated.

I am using backbone.js with rails. My controller accepts and returns JSON. I had all my tests working fine until I added in devise authentication. I cannot get cucumber to stay authenticated.

I have tried everything mentioned on:

  • devise wiki
  • here - standard login (go to page, fill in form, click button), setting cookie and having a special application before filter, doing the latter but in rack (couldn't get this to even run)
  • doing the above cookie/before_filter using this set_cookie method

All to no avail. The login returns fine (200), but when I send my request I get a 401 response.

Here is my controller code:

class ContactsController < ApplicationController
  before_filter :authenticate_user!

  ### backbone
  def index
    render :json => current_user.person.contacts
  end

  def show
    render :json =>  current_user.person.contacts.find(params[:id])
  end

  def create
    contact = current_user.person.contacts.create! params
    render :json => contact
  end

  def update
    contact =  current_user.person.contacts.find(params[:id])
    contact.update_attributes! params
    render :json => contact
  end

 def destroy
    contact =  current_user.person.contacts.find(params[:id]) 
    contact.destroy
    render :json => contact  #TODO: change to render nothing
  end

Here is one cucumber feature:

Scenario: View contacts
Given I am logged in as "testy@testing.com"
And I send and accept JSON
And the following contacts:
  |name|
  |name 1|
  |name 2|
  |name 3|
  |name 4|
When I send a GET request for "/contacts"
Then the response should be "200"
And the JSON response should be an array with 4 "name" elements
And I should get the following contacts:
  |name|
  |name 1|
  |name 2|
  |name 3|
  |name 4|

The JSON methods are using Rack directly. I suspect this is where my problems lie, but I don't know how to get past it.

Here are the cuke JSON steps:

World(Rack::Test::Methods)

Given /^I send and accept JSON$/ do
  header 'Accept', 'application/json'
  header 'Content-Type', 'application/json'
end

When /^I send a GET request for "([^\"]*)"$/ do |path|
  get path
end

When /^I send a POST request to "([^\"]*)" with the following:$/ do |path, table|
  params = table.hashes.flatten[0].to_json
  post path, params
end

When /^I send a PUT request to "([^\"]*)" with the following:$/ do |path, table|
  params = table.hashes.flatten[0].to_json
  put path, params
end

When /^I send 开发者_如何学Pythona DELETE request to "([^\"]*)"$/ do |path|
  delete path
end

Then /^the response should be "([^\"]*)"$/ do |status|
  last_response.status.should == status.to_i
end

Then /^the JSON response should have 1 "([^\"]*)" element$/ do |name|
  page = JSON.parse(last_response.body)
  page[name].should be
end

Then /^the JSON response should be an array with (\d+) "([^\"]*)" elements$/ do |number_of_children, name|
  page = JSON.parse(last_response.body)
  page.map { |d| d[name] }.length.should == number_of_children.to_i
end


Your Cuke looks like a RSpec test really... Since you're not actually rendering anything except direct output from the controller, I usually skip the heavier Cuke tests for more nimble RSpec tests. Cuke is left for integration usually testing controller and view in a sequence of scenarios that drive a business outcome.

The key issue may be with:

Given I am logged in as "testy@testing.com"

I'm not sure what that does. If it simply displays a login form and does nothing with it, you'll get a 200. If you want to solve that bit, step through the logged in step and make sure that you have a user_session by the time you hit the post/get calls.

user_signed_in?.should be_true
current_user.should_not be_nil
user_session.should_not be_nil

If you want to just simply test the direct results of a single controller action, try using RSpec.

Here's a sample spec for a controller that I have in RSpec: (smallest one I could find w/ auth)

require "spec_helper"

describe GuestsController do
  include Devise::TestHelpers

  let(:user) { Factory(:user) }

  context "#create" do
    it "should create an anonymous user" do
      User.should_receive(:anonymous!).and_return(user)

      post :create

      response.should redirect_to(meals_path)
    end

    it "should not create a user" do
      User.should_not_receive(:anonymous!)

      sign_in user
      post :create

      response.should redirect_to(meals_path)
    end
  end
end

You can even stub out authentication if you don't want to call sign_in

before do
  request.env['warden'] = mock(Warden, authenticate: mock_user,
                                       authenticate!: mock_user)
end

Good luck. debugger is your friend!

0

精彩评论

暂无评论...
验证码 换一张
取 消