I am attempting to create a RSpec controller test for a namespaced controller, but rspec doesn't seem able to detect the nesting and generate the proper path for the post :create action.
This is my spec code:
# for: /app/controllers/admin/crm/report_adjustments_controller.rb
require 'spec_helper'
describe Admin::Crm::ReportAdjustmentsController do
render_views
before(:each) do
signin
end
describe "GET 'index'" do
it "returns http success" do
get :index
response.should be_success
end
end
describe "POST 'create'" do
it "creates with right parameters" do
expect {
post :create, report_adjustment: {distributor_id: #ole_distributor.id, amount: "30.0", date: Date.today }
}.to change(Crm::ReportAdjustment, :count).by(1)
response.should be_success
end
end
end
# routes.rb
namespace :admin do
namespace :crm do
resources :report_adjustments
end
end
For this code, the get :index works just fine, but when post :create is called, the following error is generated: undefined method 'crm_report_adjustment_url'
Why would RSpec be smart enough to figure things out with get :index, but not with post :create? How do I get RSpec to properly load the right route, which is admin_crm_report_adjustments_url?
Thanks in advance.
Try posting to the url instead:
post admin_crm_report_adjustments_url
# or
post "/admin/crm/report_adjustments"
Related
I'm trying to write some rspec tests to check API endpoints for an API-only application.
Testing error
Failure/Error: expect( res ).to be_success
expected 200 to respond to `success?`
But if the same call (with full api url) is made from another application it works fine and returns a response.
Example from other application:
res = RestClient.get "site.io/api/v1/projects/1"
p JSON.parse(res)
Blog example I'm trying to follow: (http://matthewlehner.net/rails-api-testing-guidelines/).
# spec/requests/api/v1/messages_spec.rb
describe "Messages API" do
it 'sends a list of messages' do
FactoryGirl.create_list(:message, 10)
get '/api/v1/messages'
json = JSON.parse(response.body)
# test for the 200 status-code
expect(response).to be_success
# check to make sure the right amount of messages are returned
expect(json['messages'].length).to eq(10)
end
end
My Application
/requests/projects_spec.rb
require 'rails_helper'
RSpec.describe Project do
describe "show_project" do
before do
#project1 = create(:project)
end
it "Checks if responds successfully" do
res = get '/api/v1/projects/1'
expect( res ).to be_success
end
end
end
/factories/projects.rb
FactoryGirl.define do
factory :project do
name "Thing"
key "123123"
end
end
routes.rb
namespace :api, :defaults => { :format => 'json'} do
namespace :v1 do
resources :projects, only: [:create, :show]
end
end
end
I don't have much experience with testing, so if anyone can point me in the correct direction I would really really appreciate it.
When using Rspec Request Specs, your call to get '/api/v1/projects/1' doesn't need to captured by your res variable. Spec Request tests automatically set the value of response when get '/api/v1/projects/1' is run. The example you're following is correct, it just looks like your missing some knowledge about how much Rspec is handling for you behind the scenes. This makes your test simpler:
it "Checks if responds successfully" do
get '/api/v1/projects/1'
expect(response).to be_success
end
In Rspec Request tests, response is automatically setup by the call the get without you needing to do anything extra.
I am trying to test that on the creation of a post, the user is redirected to deployments path. I have added in
config.include Rails.application.routes.url_helpers
to extend rails routes to rspec. But my test still fails with the following error
1) Failure/Error: expect(response).to redirect_to(path)
Expected response to be a redirect to <http://test.host/deployments/new> but was a redirect to <http://test.host/deployments/new.1473>.
Expected "http://test.host/deployments/new" to be === "http://test.host/deployments/new.1473".
# -e:1:in `<main>'
Here is the test:
describe "post create" do
before do
allow(model).to receive(:new).and_return(instance)
end
context "where all is not well" do
before do
allow(instance).to receive(:save).and_return(false)
post :create, params_new_instance
end
sets_flash(:error)
it "should render the new form" do
expect(response).to render_template("projects/new")
end
end
context "where all is well" do
before do
allow(instance).to receive(:save).and_return(true)
post :create, params_new_instance
end
sets_flash(:notice)
it "redirects to new_deployments_path" do
expect(controller.controller_path).to eq(new_deployment_path)
end
end
end
project controller
def create
#project=Project.new(params_project)
if #project.save
record_saved
return redirect_to(new_deployment_path(#project))
else
check_for_errors
return render('/projects/new')
end
end
why is this failing? am i approaching this in the right way?
thanks in advance
Are you sure that new_deployments_path instead of new_deployment_path
This is my first suggestion. Them can be more but not enough information: routes.rb and deployments controller for example
I'm writing tests with rspec for my application controller in my rails app (written in Rails 4) and I'm running into a problem where it doesn't recognize the route for the HTTP request I'm sending. I know there's a way to do this using MyApp::Application.routes but I'm not able to get it working.
#application_controller_spec.rb
require 'spec_helper'
class TestController < ApplicationController
def index; end
end
describe TestController do
before(:each) do
#first_user = FactoryGirl.create(:user)
# this is to ensure that all before_filters are run
controller.stub(:first_time_user)
controller.stub(:current_user)
end
describe 'first_time_user' do
before(:each) do
controller.unstub(:first_time_user)
end
context 'is in db' do
before(:each) do
#user = FactoryGirl.create(:user)
controller.stub(:current_user).and_return(#user)
end
it 'should not redirect' do
get :index
response.should_not be_redirect
end
end
context 'is not in db' do
context 'session[:cas_user] does not exist' do
it 'should return nil' do
get :index
expect(assigns(:current_user)).to eq(nil)
end
end
it "should redirect_to new_user_path" do
controller.stub(:current_user, redirect: true).and_return(nil)
get :index
response.should be_redirect
end
end
end
The error I'm getting right now is
No route matches {:action=>"index", :controller=>"test"}
I would add the test#index route to config/routes.rb, but it doesn't recognize the Test Controller, so I want to do something like
MyApp::Application.routes.append do
controller :test do
get 'test/index' => :index
end
end
but I'm not sure where to add this or if this even works in rspec. Any help would be great!
If you are trying to test your ApplicationController, see this RSpec documentation about it. You will need to define methods like index inside the test, but it works well.
I am using Ruby on Rails 3.2.2, Rspec 2.9.0 and RspecRails 2.9.0. I would like to test the create controller action but I don't know how to make that the "right"/"proper" way. I "scaffolded" model, controller, view, ... files, so in those files I have the common code generated by Ruby on Rails generators; in my spec file I have:
it "assigns #article" do
new_article = FactoryGirl.build(:article)
Article.should_receive(:new).and_return(new_article)
post :create
assigns[:article].should eq(new_article)
end
Maybe, (note: the above code is almost the same as that I use to test the new controller action) a better way to test create controller actions would be to pass some attribute value during the post :create action instead of proceed as I make above, but I don't know how to make that and if it is the "right"/"proper" way to make things.
So, what is the proper way to test 'create' controller actions?
I'm doing it this way:
describe "#create" do
before { post :create, { "my_model"=> { "name"=>"name" } } }
specify("should created one my_model") { change{ MyModel.count }.from(0).to(1) }
end
Aaron Sumner who recently wrote the book Everyday Rails Testing with RSpec have an article at his blog. Where he describes it like this:
describe "POST create" do
context "with valid attributes" do
it "creates a new contact" do
expect{
post :create, contact: Factory.attributes_for(:contact)
}.to change(Contact,:count).by(1)
end
it "redirects to the new contact" do
post :create, contact: Factory.attributes_for(:contact)
response.should redirect_to Contact.last
end
end
context "with invalid attributes" do
it "does not save the new contact" do
expect{
post :create, contact: Factory.attributes_for(:invalid_contact)
}.to_not change(Contact,:count)
end
it "re-renders the new method" do
post :create, contact: Factory.attributes_for(:invalid_contact)
response.should render_template :new
end
end
end
How about:
it "creates article" do
article_params = FactoryGirl.attributes_for(:article)
expect { post :create, :article => article_params }.to change(Article, :count).by(1)
end
The following RSpec 2 test..
describe "GET new" do
describe "gets a report form" do
xhr :get, :new, :post_id => #post
response.should be_success
end
end
gives this nice error:
undefined method xhr for #<Class:0xb5c72404> (NoMethodError)
Any idea what is wrong?
It turns out you have to use an it statement in the describe block. Then the error goes away. If you do not use the right amount of describe and it blocks, then RSpec produces all kinds of weird errors. This is the correct code:
describe "GET new" do
it "gets a report form" do
xhr :get, :new, :post_id => #post
response.should be_success
end
end