I was writing tests for my app using responders gem.
Here are my routes:
resources :sites do
resources :pages, shallow: true
end
My PagesController chunk of code:
def create
respond_with(#page = #site.pages.create(page_params))
end
def find_site
#site = current_user.sites.find(params[:site_id])
end
And tests that are failing:
sign_in_user
let(:user_2) { create(:user) }
let(:site) { create(:site, user: #user) }
let(:page) { create(:page, site: site, user: #user) }
describe 'POST #create' do
context 'with valid attributes' do
it 'associates new page with the site' do
expect { post :create, params: { page: attributes_for(:page), site_id: site } }.to change(site.pages, :count).by(1)
end
it 'redirects to show view' do
post :create, params: { page: attributes_for(:page), site_id: site }
expect(response).to redirect_to page_path(assigns(:page))
end
end
Errors are following:
1) PagesController POST #create with valid attributes associates new page with the site
Failure/Error: expect { post :create, params: { page: attributes_for(:page), site_id: site } }.to change(site.pages, :count).by(1)
expected #count to have changed by 1, but was changed by 0
# ./spec/controllers/pages_controller_spec.rb:37:in `block (4 levels) in <top (required)>'
2) PagesController POST #create with valid attributes redirects to show view
Failure/Error: expect(response).to redirect_to page_path(assigns(:page))
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"pages", :id=>nil}, missing required keys: [:id]
# ./spec/controllers/pages_controller_spec.rb:42:in `block (4 levels) in <top (required)>'
If I change site.pages in first test to Page - it's actually working.
So I am really confused how to fix this tests and where is the mistake.
Solved
Problem was with my PagesController, method create should look like this
def create
#page = #site.pages.build(page_params)
#page.user = current_user
#page.save
respond_with(#page)
end
Problem was with my PagesController, method create should look like this
def create
#page = #site.pages.build(page_params)
#page.user = current_user
#page.save
respond_with(#page)
end
Related
I am trying to validate that the current_user's organization matches that of the organization they are trying to view.
Here's the part of the controller that's failing this test (#organization is being defined in an earlier method):
if current_user.organization != #organization
redirect_to root_path, notice: "Not authorized to edit this organization"
end
Here's the failing test:
require 'rails_helper'
RSpec.describe Admin::PagesController, :type => :controller do
describe 'GET #home' do
login_user
before do
#organization = FactoryGirl.create(:organization)
end
context "valid params" do
it "renders the home template and returns http 200" do
get :home, name: #organization.name
expect(response).to render_template("home")
expect(response.status).to eq(200)
end
end
end
Here's my factory:
factory :user do
email { Faker::Internet.email }
organization_id 1
password "foobarfoobar"
password_confirmation { |u| u.password }
end
...And here's where login_user is being defined:
module ControllerMacros
def login_user
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in user
end
end
Stacktrace:
1) Admin::PagesController GET #home valid params renders the home template and returns http 200
Failure/Error: it "renders the home template and returns http 200" do
expecting <"home"> but rendering with <[]>
# ./spec/controllers/admin/pages_controller_spec.rb:15:in `block (4 levels) in <top (required)>'
However:
[2] pry(#<RSpec::ExampleGroups::AdminPagesController::GETHome::ValidParams>)> subject.current_user.organization == #organization
=> true
Not sure what is going wrong here, seems like pretty standard stuff. Any ideas?
Turns out the issue was that I was sending in the wrong parameter - should have been sending #organization.subdomain, not #organization.name. :(
I`ve got these errors while testing ratings_controller.
1) RatingsController create action creates a rating if validations pass
Failure/Error: post :create, rating: {value: 4, user_id: user, hotel_id: hotel}
ActiveRecord::RecordNotFound:
Couldn't find Hotel without an ID
# ./app/controllers/ratings_controller.rb:6:in `create'
# ./spec/controllers/ratings_controller_spec.rb:12:in `block (4 levels) in <top (required)>'
# ./spec/controllers/ratings_controller_spec.rb:11:in `block (3 levels) in <top (required)>'
2) RatingsController create action does not create rating if validations fail
Failure/Error: post :create, rating: {value: 3}
ActiveRecord::RecordNotFound:
Couldn't find Hotel without an ID
# ./app/controllers/ratings_controller.rb:6:in `create'
# ./spec/controllers/ratings_controller_spec.rb:17:in `block (3 levels) in <top (required)>'
3) RatingsController update action updates rating if validations ok
Failure/Error: patch :update, value: 3, user_id: user.id, hotel_id: hotel.id
ActionController::UrlGenerationError:
No route matches {:action=>"update", :controller=>"ratings", :hotel_id=>"1", :user_id=>"2", :value=>"3"}
# ./spec/controllers/ratings_controller_spec.rb:25:in `block (3 levels) in <top (required)>'
I dont know where they come from. Help me please if you can.
My ratings_controller:
class RatingsController < ApplicationController
#before_action :signed_in_user
before_filter :authenticate_user!
def create
#hotel = Hotel.find(params[:hotel_id])
#rating = Rating.new(params[:rating])
#rating.hotel_id = #hotel.id
#rating.user_id = current_user.id
if #rating.save
redirect_to hotel_path(#hotel), :notice => "Your rating has been saved"
end
end
def update
#hotel = Hotel.find(params[:hotel_id])
##rating = current_user.ratings.find(#hotel.id)
#rating = Rating.find_by_hotel_id(#hotel.id)
if #rating.update_attributes(params[:rating])
redirect_to hotel_path(#hotel), :notice => "Your rating has been updated"
end
end
end
My ratings_controller_spec.rb:
require "spec_helper"
describe RatingsController do
let(:rating) { FactoryGirl.create(:rating) }
let(:user) { FactoryGirl.create(:user) }
let(:hotel) { FactoryGirl.create(:hotel) }
describe "create action" do
before { sign_in rating.user }
it "creates a rating if validations pass" do
expect {
post :create, rating: {value: 4, user_id: user, hotel_id: hotel}
}.to change(Rating, :count).by(1)
end
it "does not create rating if validations fail" do
post :create, rating: {value: 3}
expect(response).to redirect_to(hotel_path(hotel))
end
end
describe "update action" do
before { sign_in hotel.user }
it "updates rating if validations ok" do
patch :update, value: 3, user_id: user.id, hotel_id: hotel.id
rating.reload
expect(rating.value).to eq(3);
end
it "updates rating if validations fail" do
end
end
end
Especially third error confusing me because rake routes shows me avaible route to ratings update action.
PATCH /hotels/:id(.:format) hotels#update
PUT /hotels/:id(.:format) hotels#update
Thanks!
Rails - 4.0.8
Ruby - 1.9.3p551
UPDATE 1:
Sorry about routes. My mystake. Just copied the wrong lines.
rating PATCH /ratings/:id(.:format) ratings#update
PUT /ratings/:id(.:format) ratings#update
Seems ok to me and works fine if I start server and test it manually.
About the id problem:
#hotel = Hotel.find(params[:hotel_id]) expects the params hash to have a top-level hotel_id key. When you call the create method from the test, you nest the hotel_id inside the ratings key:
post :create, rating: {value: 4, user_id: user, hotel_id: hotel}
Thus params[:hotel_id] is nil. You need to add the hotel_id as a top-level key:
post :create, rating: {value: 4, user_id: user, hotel_id: hotel}, hotel_id: hotel
Alternatively, you can pass the nested hotel_id directly to the find method:
#hotel = Hotel.find(params[:rating][:hotel_id])
About the route problem:
Your route is mapped to HotelsController (as seen in the rake routes output as hotels#update), but you are testing the RatingsController, so you get the
No route matches {:action=>"update", :controller=>"ratings", :hotel_id=>"1", :user_id=>"2", :value=>"3"}.
Update your routes to route to the RatingsController's update method instead of HotelsController, so you would have a ratings#update route.
Update:
In this case, the route is expecting an id parameter in the url: /ratings/:id, which you are not providing:
patch :update, value: 3, user_id: user.id, hotel_id: hotel.id
Either provide a specific rating id you want to update, or change your routes not to require the id parameter since you are finding the rating through the hotel anyway, so they will look like
patch '/ratings', to 'ratings#update'
instead of
patch '/ratings/:id', to 'ratings#update'.
If you defined your routes with resources :ratings, you can put the specific route above it, so it will be hit first by the router. A good idea would be to exclude it too: resources :ratings, except: :update. Or just use collection routes. See this question for some more info.
I am following Michael Hartl's tutorial, and trying to implement the reply twitter-like functionality, ie. "#122-john-smith: hello there" should be a reply to user 122.
I first tried filtering the "#XXX-AAA-AAA" part using a before_filter, but I decided to try it first in the very same Micropost#create action. So far I've got this MicropostController:
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
before_filter :correct_user, only: [:destroy]
#before_filter :reply_to_user, only: [:create]
def index
end
def create
#micropost=current_user.microposts.build(params[:micropost])
#Rails.logger.info "hoooola"
regex=/\A#(\d)+(\w|\-|\.)+/i
message=#micropost.content.dup
isResponse=message.match(regex)[0].match(/\d+/)[0]
#micropost.response=isResponse
if #micropost.save
flash[:success]="Micropost created!"
redirect_to root_path
else
#feed_items=[]
render 'static_pages/home'
end
end
def destroy
#micropost.destroy
redirect_to root_path
end
private
def correct_user
#micropost = current_user.microposts.find_by_id(params[:id])
redirect_to root_path if #micropost.nil?
end
def reply_to_user
regex=/\A#(\d)+(\w|\-|\.)+/i
#I use [0] cause the output of match is a MatchData class with lots of bs
mtch=params[:micropost][:content].match(regex)[0]
#puts mtch
##micropost=current_user.microposts.build(params[:micropost])
if mtch != nil
user_id=mtch.match(/\d+/)[0]
#replied_user=User.find(user_id)
#micropost.response=user_id unless #replied_user.nil?
end
end
end
And this is the snippet test I'm trying to pass:
require 'spec_helper'
describe "MicropostPages" do
subject { page }
let(:user) { FactoryGirl.create(:user) }
before { valid_signin user }
describe "micropost creation" do
before { visit root_path }
describe "with invalid information" do
it "should not create a micropost" do
expect { click_button "Post" }.should_not change(Micropost,
:count)
end
describe "error messages" do
before { click_button "Post" }
it { should have_content('error') }
end
end
describe "with valid information" do
before { fill_in 'micropost_content', with: "Lorem ipsum" }
it "should create a micropost" do
expect { click_button "Post" }.should change(Micropost,
:count).by(1)
end
end
end
...
end
If I run these tests I get the follwing error:
Failures:
1) MicropostPages micropost creation with invalid information should not create a micropost
Failure/Error: expect { click_button "Post" }.should_not change(Micropost, :count)
NoMethodError:
undefined method `[]' for nil:NilClass
# ./app/controllers/microposts_controller.rb:14:in `create'
# (eval):2:in `click_button'
# ./spec/requests/micropost_pages_spec.rb:11:in `block (5 levels) in <top (required)>'
# ./spec/requests/micropost_pages_spec.rb:11:in `block (4 levels) in <top (required)>'
2) MicropostPages micropost creation with invalid information error messages
Failure/Error: before { click_button "Post" }
NoMethodError:
undefined method `[]' for nil:NilClass
# ./app/controllers/microposts_controller.rb:14:in `create'
# (eval):2:in `click_button'
# ./spec/requests/micropost_pages_spec.rb:14:in `block (5 levels) in <top (required)>'
However if I modify the tests and comment out all the #XXX filtering in the Micropost#create action:
def create
#micropost=current_user.microposts.build(params[:micropost])
#Rails.logger.info "hoooola"
#regex=/\A#(\d)+(\w|\-|\.)+/i
#message=#micropost.content.dup
#isResponse=message.match(regex)[0].match(/\d+/)[0]
##micropost.response=isResponse
if #micropost.save
flash[:success]="Micropost created!"
redirect_to root_path
else
#feed_items=[]
render 'static_pages/home'
end
end
The tests pass just fine and the new Micropost is not a Nil object.
It can't seem to find an explanation here.
The error comes from this line:
isResponse=message.match(regex)[0].match(/\d+/)[0]
Check if your two match calls actually match correctly. If the pattern is not found in your string, nil is returned and the [0] call is made on nil. There's two instances in this line alone where this could happen.
Try to spread it out over several lines and check the return values of your matches or extend your Regex to properly check the pattern in one go.
There is a method "sign_up" in controller
# controller/v3/users_controller
# POST api/v3/users/sign_up
def sign_up
user = User.new(params[:user])
if user.save && user.update_attribute(:channel, "user_#{user.id}")
render json: { Auth: { message: t(:sign_up_ok), user_id: user.id, channel: user.channel } }, status: 201
else
render json: { errors: Oj.load(user.errors.to_json) }, status: 400
end
end
route.rb
api_version(module: 'V3', path: 'api/v3') do
resources :users, only: [:index, :show, :destroy] do
collection do
post 'sign_up'
post 'sign_in'
end
end
I am trying to test it:
require 'spec_helper'
describe V3::UsersController do
describe "POST 'sign_up'" do
it "should be successful" do
post '/api/v3/users/sign_up'
assert_response 200
end
end
end
Get an error:
V3::UsersController POST 'sign_up' should be successful
Failure/Error: post '/api/v3/users/sign_up'
ActionController::RoutingError:
No route matches {:controller=>"v3/users", :action=>"/api/v3/users/sign_up"}
# ./spec/controllers/v3/user_controller_spec.rb:7:in `block (3 levels) in <top (required)>'
rake routes
sign_up_api_v3_users POST /api/v3/users/sign_up(.:format) V3/users#sign_up
Please, give me advice how to test this method?
ruby-1.9.3
rails-3.2.12
The action is not supposed to include the full path, just the name of the action.
post :sign_up
RSpec infers the rest of the path based on the controller your using. As you can see in the error message, it figured out the controller was v3/users, and it took your action, which is not a valid action.
I have following route:
GET /confirm/:token(.:format) Confirmations#confirm
Controller:
class ConfirmationsController < ApplicationController
# GET /confirm/<token>
def confirm
#user = User.find_by_email_token(params[:token])
if #user
#user.confirmed = true
#user.email_token = nil
#user.save!
sign_in #user
redirect_to root_url, flash: { success: "Welcome <#{#user.email}>, your address has been verified." }
elsif
redirect_to root_url, flash: { error: "Error: could not find matching user record." }
end
end
end
And this simple confirmations_controller_spec.rb:
require 'spec_helper'
describe ConfirmationsController do
let(:user) { FactoryGirl.create(:user, email_token: "some_token") }
describe "Get confirm" do
it "confirms user with valid email_token" do
get :confirm, token: "some_token"
assigns(:user).should eq(user)
user.reload.email_token.should be_nil
end
it "does not confirm user with invalid email_token"
end
end
but it fails:
1) ConfirmationsController Get confirm confirms user with valid email_token
Failure/Error: get :confirm, token: "some_token"
ActionController::RoutingError:
No route matches {:token=>"some_token", :controller=>"confirmations", :action=>"confirm"}
# ./spec/controllers/confirmations_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Anyone see what (could be multiple things) I screwed up?
BTW- I'm using a get request here (as opposed to put) because it's being initiated from a text based email so we can't, to my understanding, use a put request...
In your rake routes, Confirmations should not have a capital letter.
Can you define the route like so in config/routes.rb:
match '/confirm/:token' => 'confirmations#confirm'