Rspec testing in rails3 - ruby-on-rails-3

I have a Queues controller and and QueueItems controller in my rails
application. In routes I have defined as below
match 'queues/:queue_id/next', :to=> 'queueitems#next'
In my QueueItems Controller I have a next action and it assigns an
instance variable.
def next
#queue = "Regular"
#other stuffs related to regular
end
How do I test this in Rspec. I am pretty very new to Rspec. Please help.
I tried like the below
describe QueuesController do
describe "next " do
it "routes /queues/:queue_id/next" do
{ :get => "/queues/regular_queue/next" }.should route_to(
:controller => "queue_items",
:action => "next",
:queue_id => "regular_queue",
:format => "json"
)
assigns(:queue).should_not be_nil
expect(response).to be_success
end
end
But it is not at all coming inside my next action in controller.
Update #2
spec/controllers/queue_items_controller_spec.rb
require 'spec_helper'
describe QueueItemsController do
describe 'GET next' do
it 'assigns #queue' do
get :next, format: :json
expect(assigns[:queue]).to eq('regular')
end
end
end
queue_items_controller.rb
def next
puts "Inside next action..."
#queue = "regular"
end
routes.rb
get '/queues/:queue_id/next', :to => 'queue_items#next', :format=>'json'
rake routes
GET /queues/:queue_id/next(.:format) queue_items#next {:format=>"json"}
/queues/:queue_id/delete(.:format) queue_items#delete {:method=>:delete, :format=>"json"}
/queues/:queue_id/clear(.:format) queue_items#clear {:format=>"json"}

First of all change match to get or post - it is better to use exactly verb. Let's say it is get.
Action next is in QueueItemsController so test should be in this queue_items_controller_spec.rb file (and in folder spec/controlers).
and test might be similar to
describe QueueItemsController do
describe "GET next " do
it "responses json" do
get :next, format: :json
expect(response).to be_success
end
it "does not response html" do
get :next, format: :html
expect(response).not_to be_success # or define more exactly response
end
it 'assigns #queue' do
get :next, format: :json
expect(assigns[:queue]).to eq('Regular')
end
end
end
if you would like to test your routes you should follow this articles:
https://www.relishapp.com/rspec/rspec-rails/v/2-14/docs/routing-specs
https://www.relishapp.com/rspec/rspec-rails/docs/routing-specs/route-to-matcher

Related

"No route matches" with rspec

I've got a controller test set running where three of the tests succeed and three fail with the same type of error.
For the tests for the edit, update, and destroy actions, I get the associated error saying No route matches {:controller=>"accounts", action=>"edit"}
accounts_controller_spec.rb
describe AccountsController do
before(:each) do
#account_code = FactoryGirl.create(:account)
end
describe "GET 'index'" do
it "returns http success" do
get 'index'
expect(response).to be_success
end
end
describe "GET 'new'" do
it "returns http success" do
get 'new'
expect(response).to be_success
end
end
describe "POST 'create'" do
it "returns http success" do
post 'create'
expect(response).to be_success
end
end
describe "GET 'edit'" do
it "returns http success" do
get 'edit'
expect(response).to be_success
end
end
describe "POST 'update'" do
it "returns http success" do
post 'update'
expect(response).to be_success
end
end
describe "DELETE 'destroy'" do
it "returns http success" do
post 'destroy'
expect(response).to be_success
end
end
end
accounts_controller.rb
class AccountsController < ApplicationController
load_and_authorize_resource
def index
end
def new
end
def create
if #account.save
flash[:success] = "Account created"
redirect_to :action => :index
else
render 'new'
end
end
def update
if #account.update_attributes(params[:account])
flash[:success] = "Account Updated"
redirect_to :action => :index
else
render 'edit'
end
end
def edit
end
def destroy
#account.destroy
flash[:success] = "Account Deleted"
redirect_to accounts_path
end
end
routes.rb
resources :account_codes
I see two errors here
you do not use the correct verbs for destroy and update, you should use 'delete' for destroy and 'put' for update
you do not provide an 'id' for these actions, you should use get :edit, id: 1 , put :update, id: 1 ...
try running rake routes to see your exact routes
PS: I think you would get the same error for a show action as well. If you do not need that action, pass it in as except: :show in your resources on routes.rb

Rails testing, how to specify path for post? (No route matches error)

I try to test one of my REST api controllers which is placed at "controllers/api/v1/bookings_controller.rb". The controller only responds_to json at the moment as you can see here:
class Api::V1::BookingsController < ApplicationController
respond_to :json
before_filter :authenticate_user!
before_filter :get_user
def create
...
end
end
My functional test is located at "test/functional/api/v1/bookings_controller_test.rb" and looks like following:
require 'test_helper'
class Api::V1::BookingsControllerTest < ActionController::TestCase
include Devise::TestHelpers
setup do
#booking = bookings(:one)
#user = users(:one)
sign_in #user
end
test "should return a bad request" do
post :create, :booking => { }, :format => 'json'
assert_response :bad_request
end
end
The post path for creating a booking looks like this (and works, tested with HTTP Client):
api_v1_user_bookings
GET /api/v1/users/:user_id/bookings(.:format) api/v1/bookings#index
POST /api/v1/users/:user_id/bookings(.:format) api/v1/bookings#create
However when I run the test it seems that it uses some default route (see error message below), how can i specify the correct route in my test? Or is there some other mistake I do not see here?
test_should_return_a_bad_request(Api::V1::BookingsControllerTest):
ActionController::RoutingError: No route matches {:booking=>{}, :format=>"js
on", :controller=>"api/v1/bookings", :action=>"create"}
Your route expects a user_id parameter. Add it to your post:
post :create, :user_id => #user.id, :booking => {}, :format => :json
Ok, I think I figured it out now. I just had to add the user-id, otherwise it seems that rails does not select the right route. So the correct test method looks like this:
test "should return a bad request" do
post :create, :user_id => #user.id, :booking => { }, :format => 'json'
assert_response :bad_request
end

Need help Rspec test

I'm trying to learn RSpec and writing test for CRUD actions. Here is my controller:
class ArticlesController < ApplicationController
respond_to :html, :json
before_filter :authenticate_user!
# GET /articles
# GET /articles.json
def index
#articles = current_user.articles.all
respond_with(#articles)
end
# GET /articles/1
# GET /articles/1.json
def show
#article = current_user.articles.find(params[:id])
respond_with #article
end
# GET /articles/new
# GET /articles/new.json
def new
#article = current_user.articles.build
respond_with #article
end
# GET /articles/1/edit
def edit
#article = get_article(params[:id])
end
# POST /articles
# POST /articles.json
def create
#article = current_user.articles.build(params[:article])
flash[:notice] = "Article was successfully created!" if #article.save
respond_with(#article, location: articles_path)
end
# PUT /articles/1
# PUT /articles/1.json
def update
#article = get_article(params[:id])
if #article.update_attributes(params[:article])
flash[:notice] = "Article was successfully updated."
end
respond_with #article
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
#article = get_article(params[:id])
#article.destroy
respond_with #article
end
private
def get_article(article_id)
current_user.articles.find(article_id)
end
end
And my articles rspec:
describe ArticlesController do
def valid_attributes
{
:title => "Introducting Node.js",
:content => "Node.js is an event-driven...."
}
end
let(:article) do
build(:article, valid_attributes)
end
describe "PUT 'update'" do
before(:each) do
controller.stub_chain(:current_user, :articles, :build) { article }
end
context "success" do
before(:each) do
article.should_receive(:update_attributes).and_return(true)
put :update, id: article.id
end
it "sets notice" do
flash[:notice].should eq("Article was successfully updated!")
end
end
end
describe "POST 'create'" do
before(:each) do
controller.stub_chain(:current_user, :articles, :build) { article }
end
context "success" do
before(:each) do
article.should_receive(:save).and_return(true)
post :create
end
it "sets notice" do
flash[:notice].should eq("Article was successfully created!")
end
it "should redirect to article path" do
response.should redirect_to(articles_path)
end
end
context "failure" do
before(:each) do
article.should_receive(:save).and_return(false).as_null_object
post :create
end
it "assigns #article" do
assigns(:article).should == article
end
end
end
end
My question is when I run rspec on PUT UPDATE test is failed. But POST test is passed. I don't have any idea what is going on. I'm using Rails 3.1.1 with omniauth. I'm not using Devise. Here is the test result. Why? Please help me guys?
Failures:
1) ArticlesController PUT 'update' success sets notice
Failure/Error: put :update, id: article.id
NoMethodError:
undefined method `find' for #<Object:0xa3cfd20>
# ./app/controllers/articles_controller.rb:61:in `get_article'
# ./app/controllers/articles_controller.rb:44:in `update'
# ./spec/controllers/articles_controller_spec.rb:46:in `block (4 levels) in <top (required)>'
Finished in 24.09 seconds
5 examples, 1 failure
Here's the thing.
When you're stubbing, you're just saying "if this method chain is called, return this." There are two issues with that. 1) the code doesn't ever call build, and 2) there's no actual associations.
I believe you'd need to stub current_user.articles to return an article collection. The problem is that AR associations aren't actual arrays, they're proxies.
See this SO post and this SO post for more details. A regular array won't treat the find method like the AR method it really is, and you're not returning a single article.
Since you have the article ID, you could just return that particular article, but your goal is to return that article from within the user's articles to avoid updating someone else's (I assume).
This SO post may also help, and this.
In other words, you may want a real user there, with real associated objects, so things like find will work w/o hackery.
(I fully recognize this isn't a real answer; I've never done this via stubbing, I've used factories/etc.)

rails rspec controller test ActionController::RoutingError

My routes looks like this
resources :stores, :except => [:destroy] do
resources :toys, :member => {:destroy => :delete}
end
my objects controller spec look like this
require 'spec_helper'
describe ToysController do
describe "GET index" do
it "assigns all toys as #toys" do
toy11 = Factory(:toy, :is_shiny => true)
toy12 = Factory(:toy,:is_shiny => false)
get :index
assigns(:toys).should eq([toy12,toy11 ])
end
end
end
end
I got the following error
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"toys"}
Since the toys resource is nested under stores resources its not able to get toys_path route so i think so the spec is failing.
How do i pass the spec?
Thanks
The error is due to not sending store_id to tyos index.
Had i sent
:store_id => #store.id in get :index
it would have passed.

RSpec and weird tests results

I'm trying to make a simple app. When Im testing it in browser everytyhing works just fine. Howerver, when I try to run some tests with RSpec (2.5) it fails when it comes to :create test for controller.
Here's my create method:
def create
#website = Website.new(params[:website])
if #website.save
flash[:notice] = "Website created."
redirect_to(:action => 'list')
else
render('new')
end
end
The controller test:
describe WebsitesController do
render_views
.
.
.
describe "POST 'create'" do
before(:each) do
#attr = { :adres => "www.excc.pl", :opis => "aaa "*22, :tagi => "aaa aaa aaa",
:preview => File.new(Rails.root + 'spec/fixtures/rails.png'),
:preview_mini => File.new(Rails.root + 'spec/fixtures/rails.png')}
end
describe "success" do
it "should have the right title" do
response.should have_selector("title", :content=>"Lista witryn w portfolio")
end
end
.
.
.
The result of this test:
1) WebsitesController POST 'create' should have the right title
Failure/Error: response.should have_selector("title", :content=>"Lista witryn w portfolio")
expected following output to contain a <title>Lista witryn w portfolio</title> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# ./spec/controllers/websites_controller_spec.rb:34:in `block (4 levels) in
websites_controller_spec.rb:34 refers to create method
However, this test is passed correctly (for incorrect data it should be redirected back to 'new' site with specified title):
it "should have the right title" do
post :create, :website => #attr.merge(:adres => "")
response.should have_selector("title", :content=>"Dodaj stronÄ™ WWW")
end
The second problem is...
There was a time when I've got a test result like this:
<html><body>You are being redire cted.</body></html>
... which was causing me to pull my hair out for some time until I've done sth (I don't really know what) and it was gone. Yet, it makes me scared like hell when I think that it can come back in future an ruin my happiness.
Any thoughts on this would be greatly appreciated.
It's hard to know what is being asked here, but I believe the issue is that you are not setting the conditions for success/failure. If I understand correctly, when you pass in an blank :adres attribute, the save should fail and the page should render the list action. So you want to stub the create method and return true or false depending on the expected result:
it "succeeds" do
#website = mock_model(Website,:save=>true)
Website.stub(:new) { #website }
post :create, :website => {}
# redirects
response.should have_selector("etc etc")
end
it "fails" do
#website = mock_model(Website,:save=>false)
Website.stub(:new) { #website }
post :create, :website => {}
# renders 'new'
response.should_not have_selector("etc etc")
end
Testing of the validity of the parameters should be performed in the model spec:
#website = Website.new(:adres=>"")
#website.should_not be_valid