Rails link_to not found by Capybara - ruby-on-rails-3

_header.html.erb
<header class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<%= link_to "sample app", root_path, id: "logo" %>
<nav>
<ul class="nav pull-right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Users", '#' %></li>
<li id="fat-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", '#' %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
</li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign in", signin_path %></li>
<% end %>
</ul>
</nav>
</div>
</div>
</header>
user_pages_spec.rb
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
The failure is:
1) User pages signup with valid information followed by signout
Failure/Error: before ( click_link "Sign out" )
Capybara::ElementNotFound:
no link with title, id, or text 'Sign out' found
(eval):2:in 'click_link'
./spec/requests/user_pages_spec.rb:63:in 'block (5 levels) in (top (required))'
Following the create user process manually it appears to work. The link is in a drop down menu if maybe that might have something to do with it? This is at the point in the MHartl rails tutorial where he says all tests should pass.

The suspect code apparently needs to be nested inside the inside the previous describe
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end

The before block in the last describe hasn't yet created the user. This is why the user (which doesn't exist yet) isn't currently signed in, thus no "sign out" link.
One possible solution is to click_button 'submit' in the before block. Another is to skip the sign out in the before block altogether, since there is no user signed in at that point.

Yes, it should be nested inside the previous describe. I can confirm this also works for the Rails 4 version of the tutorial.

Related

Rails Tutorial 3 Chapter 9.1: Rspec tests failing when should be passing

I'm a rails noob and have been working through Michael Hartl's awesome Rails 3 tutorial with great success. So far all my tests have worked when they should have (per the book). However, I'm at the beginning of chapter 9 and am failing rspec tests that should be passing - i.e. functionality in the browser is perfect.
I've checked everything and even looked at the sample app's github repo but still can't figure out how to cure my rspec woes. Any help is greatly appreciated.
The Errors in Question
1) Authentication signin with valid information
Failure/Error: it { should have_selector('a', 'Sign out', href: signout_path) }
expected css "Sign out" to return something
# ./spec/requests/authentication_pages_spec.rb:34:in `block (4 levels) in <top (required)>'
2) Authentication signin with valid information
Failure/Error: it { should have_selector('title', text: user.name) }
expected css "title" with text "Example User" to return something
# ./spec/requests/authentication_pages_spec.rb:33:in `block (4 levels) in <top (required)>'
3) User pages signup edit page
Failure/Error: it { should have_selector('title', text: "Edit User" ) }
expected css "title" with text "Edit User" to return something
# ./spec/requests/user_pages_spec.rb:72:in `block (5 levels) in <top (required)>'
Other App Files
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "signin page" do
before { visit signin_path }
it { should have_selector('h1', text: 'Sign in') }
it { should have_selector('title', text: 'Sign in') }
end
describe "signin" do
before { visit signin_path }
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_selector('title', text: 'Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
end
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email.upcase
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_selector('title', text: user.name) }
it { should have_selector('a', 'Sign out', href: signout_path) }
end
end
end
spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before { visit signup_path }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', text: full_title('Sign up')) }
end
describe "profile page" do
let (:user) { FactoryGirl.create(:user) } #Using factory girl to create the test user
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
end
describe "signup" do
before { visit signup_path }
let(:submit) { "Create my account" }
describe "with invalid information" do
it "should not create a user" do
expect { click_button submit }.not_to change(User, :count)
end
describe "after submission" do
before { click_button submit }
it { should have_selector('title', text: 'Sign up') }
it { should have_content('error') }
end
end
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email('user#example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before { visit edit_user_path(user) }
describe "page" do
it { should have_selector('h1', text: "Update your profile") }
it { should have_selector('title', text: "Edit User" ) }
it { should have_link('change', href: 'http://gravatar.com/emails') }
end
describe "with invalid information" do
before { click_button "Save changes" }
it { should have_content('error') }
end
end
end
end
app/views/layouts/_header.html.erb
<header class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<div class="container">
<%= link_to "sample app", root_path, id: "logo" %>
<nav>
<ul class="nav pull-right">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Users", '#' %></li>
<li id="fat-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"> Account <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<li><%= link_to "Settings", '#' %></li>
<li class="divider"></li>
<li>
<%= link_to "Sign out", signout_path, method: "delete" %>
</li>
</ul>
</li>
<% else %>
<li><%= link_to "Sign in", signin_path %></li>
<% end %>
</ul>
</nav>
</div>
</div>
</header>
app/views/users/edit.html.erb
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
<%= gravatar_for #user %>
change
</div>
</div>
Solved Update!
Thanks for the comments guys. I ended up getting the tests to pass by doing a combination of a couple things:
Restarted Rails
Continued following the book until the end of 9.2.1
After doing both of these things the test suite turned green as expected. Hopefully this can help out someone stuck in the same situation.

Confused about how my routes are interacting with each other

Ok, I'm gonna try to get as specific as I can. Here's my code:
routes.rb
root to: "users#index"
match "/users/:id/about", to: "users#about", as: :about
match "/users/:id/blog", to: "users#blog", as: :blog
match "users/:id/contact", to: "users#contact", as: :user_contact
match "/contact", to: "static_pages#contact", as: :static_contact
resources :sessions, only: [:new, :create, :destroy]
resources :users do
resources :portfolios do
resources :pictures
end
end
Here's my navigation bar with all the links on my main page:
<nav>
<ul class="sf-menu" id="nav">
<li class="<%= "selected" if current_page?(root_path) %>"><%= link_to "home", root_path %></li>
<li class="<%= "selected" if current_page?(about_path) %>"><%= link_to "about me", about_path %></li>
<li><%= link_to "my portfolio" %>
<ul>
<% #user.portfolios.each do |portfolio| %>
<li><%= link_to portfolio.name, user_portfolio_path(#user, portfolio) %></li>
<% end %>
</ul>
</li>
<li class="<%= "selected" if current_page?(blog_path) %>"><%= link_to "blog", blog_path %></li>
<li class="<%= "selected" if current_page?(user_contact_path) %>"><%= link_to "contact", user_contact_path %></li>
</ul>
</nav>
When I link from any link (home, about me, blog, contact) to any other link everything works fine. For example when I'm on the about me page (/users/8/about) I can link to the contact page(users/8/contact). The problem is when I land on the portfolio page (/users/8/portfolios/31) and try to link to the about me page, for example, the url becomes this: /users/31/about instead of back to /users/8/about. User 31 doesn't exist but portfolio 31 exists.

Login form doesn't start user session

I'm using Devise and Bootstrap in my Rails app
In the Bootstrap navbar i have this login form:
<form class="navbar-form pull-right">
<% if current_user %>
<b><%= link_to current_user.name, current_user %></b>
<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
<% else %>
<input class="span2" type="text" placeholder="Email">
<input class="span2" type="password" placeholder="Password">
<button type="submit" class="btn"><%= link_to "Sign in", new_user_session_path %></button>
<button type="submit" class="btn"><%= link_to "Register", new_user_registration_path %></button>
<% end %>
</form>
If I enter the email/pass and hit "sign in", then the page refreshes, but the user session doesn't start (the user hasn't been logged in). Am I doing something wrong in this form?
I can sign in using the Devise /sign_in page but i want to be able to do so aswell in my nav bar :)
Your form isn't posting to anything, those link_to tags aren't really doing anything.
Links aren't the same as inputs.
Instead you need a form like this:
<% if current_user %>
<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
<% else %>
<%= form_for("user", :url => new_user_session_path, :html => { :class => "navbar-form pull-right"}) do |f|%>
<%= f.text_field :email, :class=>"span2"%>
<%= f.text_field :password, :class=>"span2"%>
<%= f.submit "Sign in", :class => "btn"%>
<% end %>
<%= link_to "Register", new_user_registration_path, :class => "btn" %>
<% end %>
You'll need a separate form for registration, I suggest simply linking to another registration page.

How can I use "Form_tag" as opposed to "Form_for" in this file

I am new to Ruby on Rails and have been helped immensely by Michael Hartl's excellent book: Ruby on Rails Tutorial. I have gotten to Chapter 8 and am now on the exercises in that chapter. I am having ( I assume a typical "newbie") problem with exercise 1. In this exercise it is asked "1.Refactor the signin form to use form_tag in place of form_for." I have tried to searching for assistance with this in Stackoverflow, Google, Railscast, and many other "web searches" for two days now and I do not seem to find the assistance that I need to answer this problem. The file I am trying to modify with form_tag is below:
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
I am using Rails 3.2.3 in this application. Can anybody point me in the correct direction? Can anyone help me with this problem? I would be most appreciative.
This is the implementation that uses form_tag:
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_tag( url: sessions_path ) do %>
<%= label_tag :email %>
<%= text_field_tag :email %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
I am using Rspec 2.9.0 and below are the failing tests:
describe "signin page" do
before { visit signin_path }
it { should have_selector('h1', text: 'Sign in') }
it { should have_selector('title', text: 'Sign in') }
end
and
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_selector('title', text: 'Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
end
and
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
Here's my routes file:
SampleApp::Application.routes.draw do
resources :users
resources :sessions, only: [:new, :create, :destroy]
get "users/new"
root to: 'static_pages#home'
match '/signup', to: 'users#new'
match '/signin', to: 'sessions#new'
match '/signout', to: 'sessions#destroy', via: :delete
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
end
I have just completed this exercise as well, so I am by no means an expert; however, this is the code that has worked for me and passed all the tests:
../app/views/sessions/new.html.erb
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span 6 offset 3">
<%= form_tag sessions_path do %>
<%= label_tag :email %>
<%= text_field_tag :email, params[:email] %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New User?<%= link_to "Sign Up Now", signup_path %> </p>
</div>
</div>
I also needed to change the ../app/controllers/sessions_contoller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user] = user.id
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
sign_out
redirect_to root_path
end
end
Whilst this works, I'm not entirely sure why it does; if someone could explain why the changes in the controller are required it would be much appreciated. I know that this could be posed a s a separate question but it is closely related to OP and I'm sure we would both find it extremely useful in understanding not just how to get this to work but why it works this way. The following are the original view and controller files:
Original 'form_for' new.html.erb:
<% provide(:title, "Sign in") %>
<h1>Sign in</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Sign in", class: "btn btn-large btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
and the original sessions_controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to user
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
sign_out
redirect_to root_path
end
end
I am working on the same step of the tutorial, and your question helped me finding my way.
The use of label and text_field, instead of label_tag and text_field_tag is working fine, and you don't have to change the controller code (this produce the same HTML code as with the original form_for method).
<%= form_tag(sessions_path) do %>
<%= label :session, :email %>
<%= text_field :session, :email %>
<%= label :session, :password %>
<%= password_field :session, :password %>
<%= submit_tag("Sign in", class: "btn btn-large btn-primary") %>
<% end %>
You can read details in http://guides.rubyonrails.org/form_helpers.html#dealing-with-model-objects
The RoR guides go over how form_tag works.
http://guides.rubyonrails.org/form_helpers.html
I got caught not naming the the fields right. When you view source of the original, it shows you the naming scheme.
<%= form_tag(sessions_path) do %>
<%= label_tag 'session_email', 'Email' %>
<%= text_field_tag 'session[email]' %>
<%= label_tag 'session_password', 'Password' %>
<%= password_field_tag 'session[password]' %>
<%= submit_tag "Sign in", class: "btn btn-large btn-primary" %>
<% end -%>
You have a Session_Helper that you aren't using in your implementation.
EDIT your helper methods.
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
session[:user_id] = user.id
end
def sign_out
cookies.delete(:remember_token)
session[:user_id] = nil
end
Then you can simply use the appropriate methods in your session controller. This is a neater implementation that follows the modular approach to design. There also seems to be issues with rspec.
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before do
fill_in "Email", with: user.email.upcase
fill_in "Password", with: user.password
click_button "Sign in"
end
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
Even though everything is correct when you visit the page these tests are flagged. My guess is that you need to change before do because if it was doing what you want it to do the tests would pass.
Anyways, I'm curious to what the problem is with rspec if anyone has an idea!
I think that problem is with user.email.upcase. You don't need .upcase, when you remove it tests will pass.

capybara current path

I'm trying to make a simple login example test in capybara where you use the user email and password to login, and it redirects to root_url with a notice "logged in"
For some reason capybara reports that I am at login_path "/login" after I use click_on log in, but when I run it rails s I am at root_path "/" with my notice.
What have I missed in either capybara or my test app?
All relevant code should be below.
controllers/sessions_controller.rb
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: "logged in"
else
redirect_to login_path, notice: "Email or password incorrect"
end
end
view/sessions/new.html.erb
<h1>Sessions Log In</h1>
<%= form_tag sessions_path do %>
<div class="field">
<%= label_tag :email %><br />
<%= text_field_tag :email, params[:email] %>
</div>
<div class="field">
<%= label_tag :password %><br />
<%= password_field_tag :password %>
</div>
<div class="actions"><%= submit_tag "log in" %> </div>
<% end %>
login_spec.rb
it "should let you login with correct password" do
user = Factory.build(:user)
visit login_path
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
click_on "log in"
current_path.should == root_path
page.should have_content("logged in")
end
routes.rb
...
get 'login', to: 'sessions#new', as: 'login'
...
Factories.rb
Factory.define :user do |f|
f.sequence(:email) {|n| "a#{}#a.a"}
f.password "a"
end
Can you verify that you are actually logged in?
Try placing page.should have_content("logged in") before asserting current_path.
And why are you only building a user instead of creating/saving it. I hope you realise Factory.build(:user) functions different than Factory(:user) and it doesn't actually save the user.