I have this controller:
class UsersController < ApplicationController
def enable_password_change
respond_to do |format|
format.js {
render :layout => false
}
end
end
end
And the following test:
test "should render js to show the change password form" do
sign_in_user
request_javascript
get :enable_password_change
assert_template :enable_password_change
assert_response :ok
end
And the helper method to set the request headers:
def request_javascript
#request.headers["Accepts"] = "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
end
However my test reports:
Finished tests in 0.942294s, 7.4287 tests/s, 15.9186 assertions/s.
1) Error:
UsersControllerTest#test_should_render_js_to_show_the_change_password_for:
ActionController::UnknownFormat: ActionController::UnknownFormat
app/controllers/users_controller.rb:9:in `enable_password_change'
test/controllers/users_controller_test.rb:14:in `block in <class:UsersControllerTest>'
7 tests, 15 assertions, 0 failures, 1 errors, 0 skips
What am I doing wrong here?
I found the the xml_http_request or alias xhr for that
test "should render js to show the change password form" do
sign_in_user
xhr :get, :enable_password_change
assert_template :enable_password_change
assert_response :ok
assert assigns(:merchant_user)
end
In an instance of TestCase, #get calls #process which calls #request.recycle! which sets #request.headers to an empty hash. To test a js response, I think you'll have to have the test fire up a browser with Selenium or something like that.
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
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
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"] = "..."
I posted a question (Rails XML builder not rendering) regarding rendering XML using XmlBuilder. That particular issue was resolved but I’ve run into another issue testing this controller action.
The issue seems to be with Rspec as because the same test written in Minitest works fine and using cURL works too.
While debugging this, Rspec never tries to render the xml builder template. It just skips over the template and renders a http status 200 with a blank body.
Here are the controller, xml builder, tests, and test results:
controllers/bars_controller.rb
require 'builder'
class BarsController < ApplicationController
def show
#bar = Bar.find(params[:id])
render template: 'bars/show.xml.builder', formats: [:xml]
end
end
/views/bars/show.xml.builder
xml.instruct!
xml.bar do
xml.foo(#bar.foo)
xml.bar(#bar.bar)
end
/test/controllers/bars_controller_test.rb
require 'test_helper'
class BarsControllerTest < ActionController::TestCase
setup do
#bar = Bar.create(foo: 'bar', bar: 'foo')
end
test "should show bar" do
get :show, id: #bar
assert_response :success
assert_match "<bar>", response.body
end
end
/spec/controllers/bars_controller_spec.rb
require_relative '../rails_helper'
describe BarsController do
describe 'a POST to :show' do
before do
#bar = Bar.create(foo: 'bar', bar: 'foo')
post :show, id: #bar
end
it 'should show bar' do
expect(response).to be_success
expect(response.body).to include("<bar>")
end
end
end
Test results
> rake test
Run options: --seed 50688
# Running:
.
Finished in 0.096901s, 10.3198 runs/s, 30.9593 assertions/s.
1 runs, 3 assertions, 0 failures, 0 errors, 0 skips
> rspec spec/controllers/bars_controller_spec.rb
F
Failures:
1) BarsController a POST to :show responds with xml bar
Failure/Error: expect(response.body).to include("<bar>")
expected "" to include "<bar>"
# ./spec/controllers/bars_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
Finished in 0.01726 seconds (files took 1.53 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/controllers/bars_controller_spec.rb:11 # BarsController a POST to :show responds with xml bar
RSpec controller tests do not render views by default. In order to render the views, add render_views to the describe block:
describe 'a POST to :show' do
render_views
before do
#bar = Bar.create(foo: 'bar', bar: 'foo')
post :show, id: #bar
end
it 'should show bar' do
expect(response).to be_success
expect(response.body).to include("<bar>")
end
end
I am attempting to create an API with Rails using BDD with RSpec.
Rails version is 3.1.1, Ruby version is 1.9.2, Devise version is 1.5.3, and rspec version is 2.7.0. I am relatively new to Rails and very new to RSpec.
I have defined a simple RSpec as follows to test a FormsController with essentially no logic.
describe FormsController, " handling GET /forms" do
include Devise::TestHelpers
render_views
before do
user = Factory.create(:user) # Handle Devise authentication
user.confirm!
sign_in user
#form = mock_model(Form)
Form.stub!(:all).and_return([ #form ])
end
it "gets successfully" do
get :index, :format => :json
response.should be_success
end
it "finds all forms" do
Form.should_receive(:all).and_return([#form])
get :index, :format => :json
Rails.logger.info "*** response.body="+response.body
end
end
Form controller code is very simple currently.
class FormsController < ApplicationController
before_filter :authenticate_user!
# GET /forms
# GET /forms.json
def index
#forms = Form.find_all_by_owner_id(current_user.id)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #forms }
end
end
end
When I run the spec, "finds all forms" always fails with
Failure/Error: Form.should_receive(:all).and_return([#form])
(<Form(id: integer, title: string, owner_id: integer, created_at: datetime, updated_at: datetime) (class)>).all(any args)
expected: 1 time
received: 0 times
The output from log/test.log shows:
*** response.body=[]
Why? I feel that the problem stems from Form.stub!(:all).and_return([ #form ]), but I am not sure how to debug.
Thanks in advance.
It would help to post your controller code (that is being tested). The error says that the declaration Form.should_receive(:all).and_return([#form]) has not been satisfied. The declaration says you should have code like this in your controller's action: Form.all.
find_all_by_owner_id is not the same as Form.all. find_all_by_owner_id ends up doing
Form.where(...).all
which doesn't match the expectations you've set. In your particular case I'd tell should_receive that I'm expecting a call to find_all_by_owner_id rather than all.
After much more trial and error, the following solution worked for me.
I migrated from mocking the Form model to using Factory Girl to create the full model
I then updated the test to use to_json to compare the response against the model.
The spec is as follows.
describe FormsController, " handling GET /forms" do
include Devise::TestHelpers
render_views
before do
user = Factory.create(:user) # Handle Devise authentication
user.confirm!
sign_in user
#form1 = Factory.create(:form)
end
it "gets successfully" do
get :index, :format => :json
response.should be_success
end
it "finds all forms" do
get :index, :format => :json
response.body.should == [ #form1 ].to_json
Rails.logger.info "*** response.body="+response.body
end
end