# Respec APIs Testing Notes ## Folders Structure ``` spec |--- apis #do not put into controllers folder. |--- your_api_test_spec.rb |--- controllers |--- models |--- factories |--- views |--- helpers |--- supports |--- api_helper.rb |--- authentication_helper.rb |--- spec_helper.rb ``` *note: do not put your apis folder underneath controllers folder, otherwise, it will inherited with controller ``ActionController::TestCase::Behavior``, ``Rake::Test::Methods`` cannot be apply accordingly. ## Custom Rspec Helper for Rake::Test::Methods for api scopes. ```ruby @spec/supports/api_helper.rb module ApiHelper include Rack::Test::Methods def app Rails.application end end RSpec.configure do |config| config.include ApiHelper, :type=>:api #apply to all spec for apis folder end ``` ## Enable Spec_helper supports ```ruby @spec/spec_helper.rb Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} ``` ## API Test Spec make sure your sample test group has type: api, then it will include Rake::Test::Methods for (``get,post,put,delete``) requests ```ruby @spec/apis/authentication_spec.rb require "spec_helper" describe "API authentication" , :type => :api do let!(:user) { FactoryGirl.create(:user) } it "making a request without cookie token " do get "/api/v1/items/1",:formate =>:json last_response.status.should eql(401) error = {:error=>'You need to sign in or sign up before continuing.'} last_response.body.should eql(error.to_json) end end ```ruby ## ``ActionController::TestCase::Behavior`` v.s. ``Rack::Test::Methods`` Rspec-Rails includes ``ActionController::TestCase::Behavior`` for simulating controller requests. so you could do ```ruby require "spec_helper" describe Api::V1::SessionsController , :type => :api do let!(:user) { FactoryGirl.create(:user) } it "making a request without cookie token " do get :index response.status.should eql(401) error = {:error=>'You need to sign in or sign up before continuing.'} response.body.should eql(error.to_json) end end ``` ### Points of differents: * ``Rake::Test::Methods`` could query the url "/api/v1/xxxx", but ``ActionController::TestCase::Behavior`` only execute actions within current controller scope. * the reponse in ``Rake::Test::Methods`` called: last_response, in ``ActionController::TestCase::Behavior`` called: response. *Notes, if you change your spec/apis folder to api, you will find out the ``last_repsonse`` is not working any more. That's because the :type=> :api scope got mixed with default ActionController behavior. # A Setp Further ## Reusable Sign in Helper. ```ruby @spec/supports/authentication_helper.rb module AuthenticationHelper def sign_in_as_a_valid_user @user ||= FactoryGirl.create(:user) @user.reset_authentication_token! unless @user.authentication_token set_cookie "authentication_token=#{@user.authentication_token}" end end RSpec.configure do |config| config.include AuthenticationHelper, :type=>:api end ``` *Notes: The Example above used token based cookie authentication. So you could change to base-authen or token-based auth based on your own needs. ## Created a signed in user in your Test use before_each or before_all block or include the helper method into your assertion block ```ruby require "spec_helper" describe "API Items Controller", :type => :api do before :each do sign_in_as_a_valid_user end it "fetch all items" do #or include the helper method here sign_in_as_a_valid_user ... end end ```