Hey guys can anyone find where i've gone wrong? Ive created an API end point that expects to be called from another website with parameters. From those parameters i'm meant to find a user in my app and update an attribute of that user. This is how my controller looks:
class Vodacom::Api::V1::SmsReceiverController < ApplicationController
protect_from_forgery :except => [:suspend_account]
def suspend_account
logger.info "PARAMS: #{params.inspect}"
#user = User.find_by(guardian_number: localize_number(vodacom_params[:num]), cell_number: vodacom_params[:mesg])
begin
#user.update(guardian_verified: false) if #user.older_than_18? == false
render status: :ok, json: { message: "Account Deactivated" }
rescue
render status: :ok, json: { message: "Couldn't find user" }
end
end
def localize_number(num)
num = num.sub(/^../, '0')
end
private
def vodacom_params
params.permit(:num, :mesg, :prem, :tonum, :id)
end
end
My route looks like this:
namespace :vodacom do
namespace :api do
namespace :v1 do
get "/suspend_account", to: "sms_receiver#suspend_account"
end
end
end
My specs for this functionality look like this:
require 'rails_helper'
RSpec.describe Vodacom::Api::V1::SmsReceiverController, :type => :controller do
describe "When the correct parameters are sent to the SMS receiver controller" do
let(:user){ create(:user, guardian_number: "0798900606", cell_number: "0798900606")}
let(:params){ {prem: "30911", mesg: "0798900606", num: "27798900606", tonum: "082007005922721", id: "1122365"} }
it "should receive a query string with attributes" do
expect(suspend_user_account.request.env['QUERY_STRING']).to eq("id=1122365&mesg=0798900606&num=27798900606&prem=30911&tonum=082007005922721")
end
it "should find and disable the user's account " do
get :suspend_account, params
user.reload
expect(user.guardian_verified).to eq(false)
end
end
end
The Api should find the user with the corresponding cellphone number and change their "guardian verified" attribute to "false". However, when I run the spec it throws this error in the test logs:
Processing by Vodacom::Api::V1::SmsReceiverController#suspend_account as HTML
Parameters: {"prem"=>"30911", "mesg"=>"0798900606", "num"=>"27798900606", "tonum"=>"082007005922721", "id"=>"1122365"}
Completed 401 Unauthorized in 6ms (ActiveRecord: 0.0ms)
Rendered text template (0.0ms)
However, the functionality itself works, but the spec doesnt. Anybody know why?
Before you send the request you have to add authorization headers into the request.
Example:
request.headers["Authorization"] = "..."
request.headers["X-Api-Key"] = "..."
request.headers["Content-Type"] = "..."
Related
I've written a test to test the 404 page
pages_controller_spec.rb
RSpec.describe PagesController, type: :controller do
before :all do
Rails.application.config.action_dispatch.show_exceptions = true
Rails.application.config.consider_all_request_local = false
end
describe "status 404" do
it "respond with 404 if page is not found" do
get :help, params: { id: "foobar" }
expect(response.status).to eq(404)
end
end
end
The pages controller is simple and functions to render the static pages "/help" and "/about"
class PagesController < ApplicationController
def help
end
def about
end
end
The error handling is set up as follows
application_controller.rb
def not_found
raise ActionController::RoutingError.new("Not Found")
rescue
render_404
end
def render_404
render file: "#{Rails.root}/public/404", status: :not_found
end
The test result is
expected: 404
got: 200
Which I do not understand since "/help/foobar" does render the 404 page when I try it myself in the browser. I guess the problem could be that my "get" action in the test is formatted wrong but I'm not sure.
EDIT
config/routes.rb as requested
get "/about", to: "pages#about"
get "/help", to: "pages#help"
EDIT 2
Updated the test with the syntax from https://relishapp.com/rspec/rspec-rails/v/3-4/docs/routing-specs/route-to-matcher
The test now looks like this
RSpec.describe PagesController, type: :controller do
before :all do
Rails.application.config.action_dispatch.show_exceptions = true
Rails.application.config.consider_all_request_local = false
end
describe "status 404" do
it "respond with 404 if page is not found" do
expect(get("/foobar")).to route_to("application#not_found")
end
end
end
Unfortuenly this raises another error
ActionController::UrlGenerationError:
No route matches {:action=>"/foobar", :controller=>"pages"}
No route is matching which is kind of the point but the "not_found" method is being used for some reason
Change your routes to make your call work from the browser:
get "/help/:id", to: "pages#help"
If the test returns a 200, it's because it calls directly the help method from your controller without using the config/routes.rb file.
EDIT
Here is how you test your routing: https://relishapp.com/rspec/rspec-rails/v/3-4/docs/routing-specs/route-to-matcher
I am upgrading a legacy project to rails 5 and among the rspec tests that are failing I have one that says:
Failure/Error: expect(response).to be_redirect
expected `#<ActionDispatch::TestResponse:0x00007fbe5fde51f0 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Thread::...ch::Http::Headers:0x00007fbe5fdde9e0 #req=#<ActionController::TestRequest:0x00007fbe5fde5358 ...>>>>.redirect?` to return true, got false
# ./spec/controllers/search_controller_spec.rb:86:in `block (3 levels) in <top (required)>'
I am using devise gem to authenticate clients.
The tests are as follows:
describe SearchController do
before(:each) do
#client = FactoryGirl.create(:client)
end
describe "authenticated search" do
# a bunch of tests
end
describe "unauthenticated search" do
it "requires a user to be authenticated" do
get :search, params: { q: "tec" }, format: :json
expect(response).to be_redirect # FAILING HERE
end
end
end
If I run the test manually and go to /search?q=tec I get redirected to the sign_in page. The search_controller.rb has a before_action :authenticate_client!
I tried adding sign_out #client before the search but it didn't work.
Also tried current_client.reload but didn't recognize current_client.
In the authenticated search tests there is a call to stub_authenticate_client that has the following code:
def stub_authenticate_client(client)
allow(request.env['warden']).to receive(:authenticate!) { client }
allow(controller).to receive(:current_client) { client }
end
in case that is useful to solve this issue.
I also tried creating a stub_logout_client method like this:
def stub_logout_client(client)
allow(request.env['warden']).to receive(:authenticate!) { nil }
allow(controller).to receive(:current_client) { nil }
end
and calling it at the beginning of the test, but it is still passing the before_action authenticate_client!
Also tried what it was suggested here, but didn't work
The search controller that is being tested:
class SearchController < ClientApplicationController
before_action :authenticate_client!
def search
limit = params[:limit] ? params[:limit].to_i : 10
query = params[:q].to_s.downcase.strip
results = {}
if params[:report]
results[:this_report] = Report.where("SOME QUERY")
end
render json: results
end
end
Thank you!
The problem is related to the be_redirect check. Changed the test to check for content in the response and that solved it, like this:
describe "unauthenticated search" do
it "requires a user to be authenticated" do
get :search, params: { q: "tec" }, format: :json
expect(response.body).to have_content("content from the page I render")
end
end
Hi guys i have a controller code with the following :
class FeedbacksController < ApplicationController
def create
#feedback = Feedback.create(feedback_params)
if #feedback.errors.any?
flash[:error] = #feedback.errors
render 'new'
else
redirect_to :back
end
end
test spec
require "rails_helper"
RSpec.describe FeedbacksController do
describe "POST create" do
context 'when param[:name] is present' do
it 'should redirect to homepage' do
#feedback = Feedback.create(:name => "Hah")
#feedback.save
is_expected.to redirect_to new_feedback_path
debugger
end
end
end
end
However when i run localhost, the output is exactly what i want but as of the unit test, it's not passing but returning me
"Expected response to be a m was was <200> ."
May i know why is it so and how should i pass my test case ?
You are missing the actual post request to your controller.
Please read this: rspec documentation
So this:
#feedback = Feedback.create(:name => "Hah")
#feedback.save
Should not be there. The second line is superfluous anyway, create already saves the object.
You are looking for code like this:
it 'should redirect to homepage' do
post feedback_path, params: { name: 'hah' }
expect(response).to redirect_to(new_feedback_path)
end
Hi I am new to rspec (and unit testing in general) and want to test the following method:
class HelloController < ApplicationController
def hello_world
user = User.find(4)
#subscription = 10.00
render :text => "Done."
end
end
I am trying to use Rspec like so:
Describe HelloController, :type => :controller do
describe "get hello_world" do
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
end
I would like to simply test that the method works properly and renders the test "done". I get the following error when I run the test:
Failure/Error: user = User.find(4)
ActiveRecord::RecordNotFound:
Couldn't find User with 'id'=4
But how do I properly create a user with that id before executing it? I have tried the following based on other tutorials and questions but it doesn't work:
describe "get hello_world" do
let(:user) {User.create(id: 4)}
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
Thank you in advance.
Hey so really no action (e.g. def hello_world) should rely on a specific id. So a simple alternative could be to use user = User.last or to find the user by name user = User.find_by(name: "name"). Then in the test you would create any user if you using User.last in the action.
describe "get hello_world" do
let(:user) {User.create!}
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
or if you are searching by name you can make a user with that name;
describe "get hello_world" do
let(:user) {User.create!(name: "name")}
it "should render the text 'done'" do
get :hello_world
expect(response.body).to include_text("Done.")
end
end
Hope this helps, questions welcome.
Do you really mean to use 'user = User.find(4)'? If you really meant to do that, you should stub the User's find method and return a user object.
it "should render the text 'done'" do
u = User.new #a new user, your test database is empty, so there's no user with id 4
User.stub(find: u) #stub the User's find method to return that new user
get :hello_world
expect(response.body).to include_text("Done.")
end
Another option is to send the user_id via params
it "should render the text 'done'" do
u = User.create(.... your user params)
get :hello_world, user_id: u.id
expect(response.body).to include_text("Done.")
end
and
def hello_world
user = User.find(params[:user_id])
#subscription = 10.00
render :text => "Done."
end
Anyway, I don't think you should be doing that, a hardcoded id is a bad sign. If you need to control users registrations and logins you can use something like Devise, and you may need to create an login a user before the spec.
i am new about rails and respect, so i hope found the answer here,
i have some models here, and all of it have many to many relations
user -- role_user -- role -- role_feature -- feature
role_user and role_feature is the middle table to connect the many to many relations, I have completed all the controller crud and the model relations table, and also tested both of it with rspec and it is 100% coverage, so dont worry about it. and i haven't do anything about views, just model, controller and rspect.
Now I want to create privilege/permissions for each user in accessing existing features, so each user has a role and the role has many features,
in the file seeds.rb
RoleUser.where(role_id: 1, user_id:1).first_or_create;
Role.where(holding_company_id: 1, name: 'Area Index').first_or_create;
RoleFeature.where(role_id: 1, feature_id:1).first_or_create;
Feature.where(name: 'Area Index', key: 'area_index').first_or_create;
Feature.where(name: 'Area Create', key: 'area_create').first_or_create;
in the file area.rb (i take example area)
class AreasController < ApplicationController
before_filter :check_access
def index
if params[:per_page].blank? && params[:page].blank?
areas = Area.where(holding_company_id: current_holding_company.id)
else
areas = Area.where(holding_company_id: current_holding_company.id).paginate(page: params[:page], per_page: params[:per_page])
end
respond_to do |format|
format.json { render json: areas.to_json, status: 200 }
end
end
def create
end
def update
end
def show
end
def destroy
end
protected
def check_access
case params[:action]
when 'index'
unless current_user.roles.features.include? (area_index)
render nothing: true, status: 200
end
end
end
end
and the spec is
require 'spec_helper'
describe AreasController, :type => :controller do
before(:each) do
#token = FactoryGirl.create(:token)
#area = FactoryGirl.create(:area_1)
FactoryGirl.create(:area_2)
FactoryGirl.create(:area_3)
end
describe "GET 'index'" do
it "returns http success for json without pagination" do
get 'index', token: #token.token_string, format: :json
expect(response.status).to eq(200)
expect(JSON.parse(response.body).count).to eq(3)
expect(Area.count).to eq(3)
end
it "returns http success for json with pagination" do
get 'index', token: #token.token_string, format: :json, page: 1, per_page: 2
expect(response.status).to eq(200)
expect(JSON.parse(response.body).count).to eq(2)
end
end
describe "POST 'create'" do
end
describe "PUT 'update'" do
end
describe "GET 'show'" do
end
describe "DELETE 'destroy'" do
end
end
and the problem is there is an error/failure while testing it with rspec, its said undefined method role, i try to fix it , i spent hours just for browse it on internet, but it's useless. so i hope this is the final chance for me, i need your help guys...