15

I have a Groups Controller with a method def inbox.

If the user is a group member then inbox returns a JSON object.

If the user is not a member, then inbox should redirect thanks to CanCan permissions.

How do I write an rspec to test these two use cases?

Current spec:

require 'spec_helper'

describe GroupsController do
  include Devise::TestHelpers

  before (:each) do
    @user1 = Factory.create(:user)
    @user1.confirm!
    sign_in @user1
    @group = Factory(:group)
    @permission_user_1 = Factory.create(:permission, :user => @user1, :creator_id => @user1.id, :group => @group)
  end

  describe "GET inbox" do
    it "should be successful" do
      get inbox_group_path(@group.id), :format => :json
      response.should be_success
    end
  end
end

Routes:

inbox_group GET /groups/:id/inbox(.:format) {:controller=>"groups", :action=>"inbox"}

Routes File:

resources :groups do
  member do
    get 'vcard', 'inbox'
  end
  ....
end
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

5 Answers5

37

This is how I do this:

describe "GET index" do
  it "returns correct JSON" do
    # @groups.should have(2).items
    get :index, :format => :json
    response.should be_success
    body = JSON.parse(response.body)
    body.should include('group')
    groups = body['group']
    groups.should have(2).items
    groups.all? {|group| group.key?('customers_count')}.should be_true
    groups.any? {|group| group.key?('customer_ids')}.should be_false
  end
end

I'm not using cancan, therefore I cannot help with this part.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Roman
  • 13,100
  • 2
  • 47
  • 63
  • Thanks Tried that but I get an error: "Failure/Error: get :inbox, :format => :json ActionController::RoutingError: No route matches {:controller=>"groups", :format=>:json, :action=>"inbox"} # ./controllers/groups_controller_spec.rb:19 " Which is strange considering rake routes yields: inbox_group GET /groups/:id/inbox(.:format) {:controller=>"groups", :action=>"inbox"} – AnApprentice May 13 '11 at 23:28
  • 1
    try to provide the path to get with url_for - http://apidock.com/rails/ActionDispatch/Integration/RequestHelpers/get – Roman May 13 '11 at 23:36
  • Strange. Sorry, not sure what I'm doing wrong. "Failures: 1) GroupsController GET index should be successful Failure/Error: get inbox_group_path(@group.id), :format => :json ActionController::RoutingError: No route matches {:controller=>"groups", :format=>:json, :action=>"/groups/33/inbox"} # ./controllers/groups_controller_spec.rb:16 " – AnApprentice May 13 '11 at 23:49
  • Hmm.. it looks more like a Rails' bug now :) – Roman May 13 '11 at 23:54
  • The controller method ends with: render :json => {:convlist => @convList } Could that be the issue? – AnApprentice May 13 '11 at 23:59
  • I guess that it's a bug somewhere between rspec and Rails' ActionDispatch::Integration::RequestHelpers. It does figure out the controller somehow (rspec?) – Roman May 14 '11 at 00:02
  • I think it's CanCan, if I comment out load_and_authorize_resource in the controller it works – AnApprentice May 14 '11 at 00:11
  • Does rspec need the csrt value? On dev, when my browser hits the controller I see the following in the logs: "Parameters: {"id"=>"173", "_"=>"1305334260963"}" but in rspec in the test logs I only see: Parameters: {"id"=>126} – AnApprentice May 14 '11 at 00:51
  • Afaik - no. And the underscore is probably jquery cache busting. – Roman May 14 '11 at 07:26
  • Please keep me posted if you find out how to work-around the cancan issue. I'm curious. – Roman May 14 '11 at 22:53
  • I have the same routing error problem, anyone found a solution? – Flov Jun 25 '12 at 09:36
4

Sometimes it might be good enough to verify if response contains valid JSON and to show actual response otherwise, here is an example:

it 'responds with JSON' do
  expect {
    JSON.parse(response.body)
  }.to_not raise_error, response.body
end
wik
  • 2,462
  • 1
  • 24
  • 29
2

Try this:

_expected = {:order => order.details}.to_json
response.body.should == _expected
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Gaurav Saini
  • 137
  • 1
  • 12
1

I think the first thing you want to do is to check that the response is of the correct type, i.e. that it has the Content-Type header set to application/json, something along the lines of:

it 'returns JSON' do
  expect(response.content_type).to eq(Mime::JSON)
end

Then, depending on your case, you might want to check whether the response can be parsed as JSON, like wik suggested:

it 'responds with JSON' do
  expect {
    JSON.parse(response.body)
  }.to_not raise_error
end

And you could merge the above two into a single test if you feel like two tests for checking JSON response validity are too much.

Community
  • 1
  • 1
Jarno Lamberg
  • 1,530
  • 12
  • 12
0

To assert JSON you can do this too:

ActiveSupport::JSON.decode(response.body).should == ActiveSupport::JSON.decode(
  {"error" => " An email address is required "}.to_json
)

This blog gives some more ideas.

Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
jawspeak
  • 855
  • 9
  • 17