I am trying to work through the Rails tutorial at railstutorial.org and am stuck at this problem. My user_path in the test is supposed to go to the individual user's profile page, but is instead going to users/index (which I haven't created yet, on purpose).
/* My test code */
describe "profile page" do
#let(user) { FactoryGirl.create(:user) }
#user = User.new(name: "Example User", email: "user#example.com",
password: "foobar", password_confirmation: "foobar")
before { visit user_path(#user) }
it { should have_content(user.name) }
it { shoult have_title(user.name) }
end
/* Failures: */
1) UserPages profile page
←[31mFailure/Error:←[0m ←[31mbefore { visit user_path(#user) }←[0m
←[31mActionView::MissingTemplate←[0m:
←[31mMissing template users/index, application/index with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffe
}. Searched in:←[0m
←[31m * "C:/Users/rajeshch/Documents/Projects/sample_app/app/views"←[0m
[36m # C:in `find_template'←[0m
[36m # ./spec/requests/user_pages_spec.rb:19:in `block (3 levels) in <top (required)>'←[0m
The routes file shows that user_path should give me users/{id} or so
> rake routes
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show <<<------
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
root GET / static_pages#home
signup GET /signup(.:format) users#new
help GET /help(.:format) static_pages#help
about GET /about(.:format) static_pages#about
contact GET /contact(.:format) static_pages#contact
/* users_controller.rb*/
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
end
end
/* config/routes.rb */
SampleApp::Application.routes.draw do
resources :users
root 'static_pages#home'
match '/signup', to: 'users#new', via: 'get'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
end
You should save the User first with #user.save! before calling visit user_path(#user)
Because until you save the user it wont persist in the database and will not have any id.
describe "profile page" do
#let(user) { FactoryGirl.create(:user) }
#user = User.new(name: "Example User", email: "user#example.com",
password: "foobar", password_confirmation: "foobar")
# Add this to your code ..
#user.save!
before { visit user_path(#user) }
it { should have_content(user.name) }
it { shoult have_title(user.name) }
end
Have you checked if #user has a value?
user_path(#user) will go to /users/<#user.id> but if #user is nil, it will try to go /users/. Given you haven't created the index method and views yet, that will probably be why it fails.
Thanks for the test code. Firstly your user is not in the database - change the .new to .create or add a #user.save. Secondly your params[:id] is not populated in the test code so the find will fail (add controller.params[:id] = #user.id to your test). (Thirdly you have a typo shoult instead of should in the last test.)
It doesn't seem like you included your test code, which would be immensely helpful in figuring out this problem. Most likely, you have #user set as nil in the test, fixing that will solve the problem.
Related
I'm trying to rewrite my tests in Rspec and am stuck on trying to make an update to a user.
I'm sure this is a silly thing I'm overlooking, but I've looked everywhere and can't find an answer.
Here's myspec file:
require 'spec_helper'
describe UsersController, type: [:request, :controller] do
before(:each) { host! 'localhost:3000/' }
describe "#update" do
it "doesn't update user" do
form_params = {
params: {
id: 1,
email: "hello#example",
name: "hello"
}
}
patch :update, params: form_params
end
end
end
It seems like the :update portion is wrong but as far as I can see in my routes, there's no other way to call it.
Here's the error:
ActionController::RoutingError: No route matches [PATCH] "/update"
Here's my routes:
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
Here's my old test:
test "should redirect update when not logged in" do
patch user_path(#user), params: { user: { name: #user.name, email: #user.email } }
assert_not flash.empty?
assert_redirected_to login_url
end
And if you guys possibly know - how do I convert assert_not flash.empty? to Rspec?
Thanks so much in advance!
At first, you can't to use multiple types in type: [:request, :controller]. If you want to write request specs you have to specify named route (user_path) or url ("/users/:id")
require 'spec_helper'
describe UsersController, type: :request do
describe "#update" do
let(:user) { create :user } # or use fixtures here
# I'm just a bit confused here, why it should not update?
it "doesn't update user" do
patch user_path(user), email: "hello#example", name: "hello"
expect(flash.empty?).to eq false
expect(response).to redirect_to login_path
end
end
end
I'm getting two different test errors in Chapter 8.2.1 of Michael Hartl's Ruby on Rails Tutorial. I'm new to Rails, but I have triple checked for syntax errors and anything else I could find. Any help is very much appreciated.
Error Message 1:
ERROR["test_should_get_new", Minitest::Result, 0.9693643249993329]
test_should_get_new#Minitest::Result (0.97s)
NameError: NameError: undefined local variable or method users_new_url' for #<UsersControllerTest:0x00000006e953f8>
test/controllers/users_controller_test.rb:5:inblock in '
Error Message 2:
ERROR["test_invalid_signup_information", Minitest::Result, 0.8977870759990765]
test_invalid_signup_information#Minitest::Result (0.90s)
ActionController::RoutingError: ActionController::RoutingError: No route matches [POST] "/signup"
test/integration/users_signup_test.rb:8:in block (2 levels) in <class:UsersSignupTest>'
test/integration/users_signup_test.rb:7:inblock in '
Routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users
end
Sessions Controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
# Log the user in and redirect to the user's show page.
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
end
end
Users Controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = "Welcome to your new profile!"
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
Users controller test
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get users_new_url
assert_response :success
end
end
Users Signup Test
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user#invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.field_with_errors'
assert_select 'form[action="/signup"]'
end
test "valid signup information" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: { name: "Example User",
email: "user#example.com",
password: "password",
password_confirmation: "password" } }
end
follow_redirect!
assert_template 'users/show'
assert_not flash.nil?
end
end
In your users_controller_test, the code doesn't know what users_new_url is. This is probably because that route doesn't exist. You will most likely have to do something like get new_user_path, but you can find out by typing rake routes and getting the list of your available routes.
Here's an example of what rake routes will output:
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
You can reference a named path by appending _path to the name. i.e. users_path will map to the "users#index"controller and method.
rake routes will also help for your second problem, which is that you do not have a route defined for POST /signup -- you have a GET /signup.
So, you'll need to add a line like:
post '/signup', to: 'users#create'
This route will map to your UsersController's #create method, which I see you have in your code.
I have started working on Chapter 8 of the famous Rails tutorial. I think I followed the instructions closely and defined the following routes:
SampleApp::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
root 'static_pages#home'
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
The session controller (/controllers/sessions_controller.rb) is defined as follows:
class SessionsController < ApplicationController
def new
end
def create
end
def destroy
end
end
In spec/requests/authentication_pages_spec.rb I have created the following test:
require 'spec_helper'
describe "Authentication" do
subject {page}
describe "signin page" do
before { visit signin_path}
it { should have_content('Sign in')}
it { should have_title('Sign in')}
end
end
The test causes the following errors:
Failures:
1) Authentication signin page
Failure/Error: before { visit signin_path}
NameError:
undefined local variable or method `signin_path' for #
<RSpec::Core::ExampleGroup::Nested_2::Nested_1:0x007f98dec05fe8>
# ./spec/requests/authentication_pages_spec.rb:7:in `block (3 levels) in <top (required)>'
2) Authentication signin page
Failure/Error: before { visit signin_path}
NameError:
undefined local variable or method `signin_path' for #
<RSpec::Core::ExampleGroup::Nested_2::Nested_1:0x007f98dec5cf50>
# ./spec/requests/authentication_pages_spec.rb:7:in `block (3 levels) in <top (required)>'
It seems the signin_path named route is not recognised even though it is defined in routes.rb. I replaced that named route with one of the others (signup_path) and the problem disappeared. So, it is something about this particular named route. Can you tell what the problem is?
rake routes produces the following output:
sb7904313:sample_app nnikolo$ rake routes
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
sessions POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
session DELETE /sessions/:id(.:format) sessions#destroy
root GET / static_pages#home
signup GET /signup(.:format) users#new
signin GET /signin(.:format) sessions#new
signout DELETE /signout(.:format) sessions#destroy
help GET /help(.:format) static_pages#help
about GET /about(.:format) static_pages#about
contact GET /contact(.:format) static_pages#contact
I also re-started the server and it did not solve the problem (I made a post to the contrary but I was wrong).
Try this instead. You can access your route names by the command rake routes. Since it's coming from your sessions controller, by default the route is probably something like new_session_path. To change it, you need to specify what you what to change it to in your routes with as: new_name
match '/signin', to: 'sessions#new', via: 'get', as: 'signin'
Try:--
get "signin" => "sessions#new", :as => "signin"
resources :sessions
Use the route as new_session_path or signin_path
See this thread: undefined method `visit' when using RSpec and Capybara in rails
You possibly did not have the line config.include Capybara:DSL in your spec_helper.rb and something about putting the tests inside rspec/features/ due to the latest changes in Capybara.
I was wrong about the re-start solving the problem so retract this post.
==EDIT I found the culprit for this erratic behaviour of rspec: rails does not seem to empty the cache between tests (which is, in my opinion, a scary bug). By default it fails to re-read the files and thus may ignore changes that have occurred. I put more details here: Rails tutorial: Rails tutorial: undefined method
I am running a test that is failing with the following message:
1) User pages profile page
Failure/Error: before { visit user_path(user) }
ActionView::Template::Error:
undefined local variable or method `new_key_path' for #<#<Class:0x007fa775c4bc50>:0x007fa775c48910>
# ./app/views/users/show.html.erb:21:in `_app_views_users_show_html_erb__4517315841728073114_70178605538620'
# ./spec/requests/user_pages_spec.rb:58:in `block (3 levels) in <top (required)>'
However, when I look at the page and follow the link manually, it works as it should. This is the test's code:
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
# let!(:key1) { FactoryGirl.create(:key) }
let!(:key1) { user.keys.build(name: "test", description: "test description", is_public: false) }
before { visit user_path(user) }
it { should have_content(user.name) }
it { should have_title(user.name) }
describe "keys" do
it { should have_content(key1.name) }
it { should have_content(key1.description) }
end
end
The 'show' page in question is:
<div class="row">
<div class="span12">
<% if #user.keys.any? %>
<h3>My Keys (<%= #user.keys.count %>)</h3>
<ol class="microposts">
<%= render #keys %>
</ol>
<%= will_paginate #keys %>
<% end %>
<%= link_to "New Key", new_key_path,
class: "btn btn-large" %>
Any idea what is causing the test to fail?
On a somewhat unrelated note, you might have noticed that I am not using a factory for :key1. This is because I kept getting this error when using it:
1) User pages profile page
Failure/Error: let!(:key1) { FactoryGirl.create(:key) }
ArgumentError:
Factory not registered: key
# ./spec/requests/user_pages_spec.rb:55:in `block (3 levels) in <top (required)>'
Despite my factories.rb file having :key in it:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
factory :key do
name "Test Key"
description "This is a test key"
is_public false
user
end
end
Any help would be much appreciated. Thanks.
EDIT: Added routes
SampleApp::Application.routes.draw do
get "keys/new"
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :keys, only: [:index, :new, :destroy, :create]
root to: 'static_pages#home'
match '/signup', to: 'users#new', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
match '/help', to: 'static_pages#help', via: 'get'
match '/about', to: 'static_pages#about', via: 'get'
match '/contact', to: 'static_pages#contact', via: 'get'
end
Result of rake routes:
Prefix Verb URI Pattern Controller#Action
keys_new GET /keys/new(.:format) keys#new
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
sessions POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
session DELETE /sessions/:id(.:format) sessions#destroy
keys GET /keys(.:format) keys#index
POST /keys(.:format) keys#create
new_key GET /keys/new(.:format) keys#new
key DELETE /keys/:id(.:format) keys#destroy
root GET / static_pages#home
signup GET /signup(.:format) users#new
signin GET /signin(.:format) sessions#new
signout DELETE /signout(.:format) sessions#destroy
help GET /help(.:format) static_pages#help
about GET /about(.:format) static_pages#about
contact GET /contact(.:format) static_pages#contact
Given that it worked after restarting spork, you've likely encountered one of the cases where spork does not pick up changes you've made. See Spork/Autotest not picking up changes automatically for discussion and the highest voted answer for workarounds.
You're probably able to see the page when you manually go to it in your browser, but upon visiting "New Key", you should have problems seeing the "New Key" page, because new_key_path doesn't exist.
If key is meant to be a child of user, then it should be new_user_key_path instead, assuming your routes are properly set up:
resources :users do
resources :keys
...
end
Try using new_user_key_path instead of:
<%= link_to "New Key", new_key_path,
class: "btn btn-large" %>
In your show.
Otherwise, if key is not meant to be a child of user,
Your factory for key1 isn't registering because you need to define a separate FactoryGirl factory for it.
FactoryGirl.define do
factory :key do
...
end
end
It is currently being treated as a child of user. If you properly indent your code, you'll realize you left it out:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
# Missing end
# Missing FactoryGirl.define do
factory :key do
name "Test Key"
description "This is a test key"
is_public false
user
end
end
I feel like I have everything I need in my routes.rb, my controller, and my controller spec, but for some reason I'm still getting a routing error (ActionController::RoutingError). Here's my controller:
class HunchController < ActionController::Base
protect_from_forgery
def results
auth_token_key = params[:auth_token_key]
user_id = params[:user_id]
#user = User.create!
#user.auth_token = #user.get_auth_token(auth_token_key, user_id)
#recommended_books = #user.get_recommended_books(#user.auth_token)
end
end
Here's my controller spec:
require 'spec_helper'
describe HunchController do
describe "POST 'results'" do
before do
#params = {
:auth_token_key => "my auth token",
:user_id => "my user id"
}
end
it "succeeds" do
post :results, #params
response.should be_success
end
end
end
And here's my routes.rb:
MyApplicationName::Application.routes.draw do
root :to => 'hunch#index'
resources :users
post 'hunch/results' => "hunch#results"
match '/results' => 'hunch#results'
end
EDIT: Here's my rake routes output:
root / {:controller=>"pages", :action=>"index"}
hunch_results POST /hunch/results(.:format) {:controller=>"hunch", :action=>"results"}
results /results(.:format) {:controller=>"hunch", :action=>"results"}
users GET /users(.:format) {:action=>"index", :controller=>"users"}
POST /users(.:format) {:action=>"create", :controller=>"users"}
new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
PUT /users/:id(.:format) {:action=>"update", :controller=>"users"}
EDIT #2: I'm getting this error with my users#show test too. Here's the actual error:
1) UsersController#show succeeds
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"users", :action=>"show"}
# ./spec/controllers/users_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
Ok, I got the same problem when gem journey was updated to the latest version. And find that if you got a route like this:
user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
which have a param (id in this case), you necessarily need to render a link in template or use a user_path/user_url variables in controller with param too, so in your templates try to find:
<%= link_to "linkname", user_path %>
and replace by
<%= link_to "linkname", user_path(#user) %>
or search in any controller for the user_path/user_url usage and replace them by user_path(#user)/user_url(#user) accordingly.