I'm doing the exercises for Michael Hartls Rails tutorial, chapter 7, section 7.6. I am attempting to make tests for "after submission," but get the error:
Failure/Error: before { click_button submit }
NameError:
undefined local variable or method `submit' for #<RSpec::Core::ExampleGroup::Nested_4::Nested_4:0x007f8289dede70>
I don't know how to fix this. I have capybara installed, and all of my other tests work.
Any suggestions?
Here is a link to the chapter
and my code for rspec:
require 'spec_helper'
describe "UserPages" do
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
it { should have_content(user.name) }
it { should have_title(user.name) }
end
describe "signup page" do
before { visit signup_path }
it { should have_content('Sign up') }
it { should have_title(full_title('Sign up'))}
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
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
end
end
describe "after submission" do
before { visit signup_path }
before { click_button submit }
it { should have_title('Sign up') }
it { should have_content('error') }
end
end
Per other questions about this stretch of Hartl's book, are you missing a
let(:submit) { "Sign up" }
?
And you should not be learning Rails by learning Capybara -> Cucumber, but that's the fashion these days...
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am going through the Rails tutorial and I have an issue that seems to be causing a lot of other tests to fail. There are 23 errors and most of them explain that there is a missing field called "Name". When I run the command
bundle exec rspec spec/requests/user_pages_spec.rb
I get the following errors (that seem to change order every time I run it):
1) User pages edit with valid information
Failure/Error: fill_in "Name", with: new_name
Capybara::ElementNotFound:
Unable to find field "Name"
# ./spec/requests/user_pages_spec.rb:136:in `block (4 levels) in '
As a result, many other cases seem to fail. What app file would cause this issue? sessions_helper.rb?
Here is my spec/requests/user_pages_spec.rb: require 'spec_helper'
describe "User pages" do
subject { page }
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit users_path
end
it { should have_title('All users') }
it { should have_content('All users') }
describe "pagination" do
before(:all) { 30.times { FactoryGirl.create(:user) } }
after(:all) { User.delete_all }
it { should have_selector('div.pagination') }
it "should list each user" do
User.paginate(page: 1).each do |user|
expect(page).to have_selector('li', text: user.name)
end
end
end
describe "delete links" do
it { should_not have_link('delete') }
describe "as an admin user" do
let(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
visit users_path
end
it { should have_link('delete', href: user_path(User.first)) }
it "should be able to delete another user" do
expect do
click_link('delete', match: :first)
end.to change(User, :count).by(-1)
end
it { should_not have_link('delete', href: user_path(admin)) }
end
end
end
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") }
let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") }
before { visit user_path(user) }
it { should have_content(user.name) }
it { should have_title(user.name) }
describe "microposts" do
it { should have_content(m1.content) }
it { should have_content(m2.content) }
it { should have_content(user.microposts.count) }
end
end
describe "signup page" do
before { visit signup_path }
it { should have_content('Sign up') }
it { should have_title(full_title('Sign up')) }
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 }
signup_errors
end
end
describe "with valid information" do
before { valid_signup }
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_link('Sign out') }
it { should have_title(user.name) }
it { should have_welcome_message( 'Welcome')}
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
end
end
describe "edit" do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
visit edit_user_path(user)
end
describe "page" do
it { should have_content("Update your profile") }
it { should have_title("Edit user") }
it { should have_link('change', href: 'http://gravatar.com/emails') }
end
describe "with valid information" do
let(:new_name) { "New Name" }
let(:new_email) { "new#example.com" }
before do
fill_in "Name", with: new_name
fill_in "Email", with: new_email
fill_in "Password", with: user.password
fill_in "Confirm Password", with: user.password
click_button "Save changes"
end
it { should have_title(new_name) }
it { should have_selector('div.alert.alert-success') }
it { should have_link('Sign out', href: signout_path) }
specify { expect(user.reload.name).to eq new_name }
specify { expect(user.reload.email).to eq new_email }
end
end
end
The error you receive when running your spec suggests that Capybara expects a field called "Name" to fill (because you ask it to at line fill_in "Name", with: new_name).
If for some reason, after sign-in you don't get to the user form, or the user form is missing the "Name" field - that would explain your failures.
In your comment you say that you get no form after sign-up, so that would definitely explain that.
To verify that, you can add a test to describe "page" like this:
it { should have_field("Name") }
If that fails - you can't expect any of the tests counting on that field to pass...
In my authentication spec i have
require 'spec_helper'
describe "Authentication" do
subject { page }
describe "Signup page" do
before { visit new_user_registration_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_content('Sign up') }
it { should have_content('error') }
end
end
describe "with valid information" do
before do
fill_in "First name", with: "Example"
fill_in "Last name", with: "Lastname"
fill_in "Username", with: "exampleguy"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar1234"
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_title(user.first_name) }
#it { should have_selector('div.flash_success', text: 'Welcome') }
# end
end
it { should have_content('Sign up') }
end
describe "Signin page" do
before { visit new_user_session_path }
describe "with invalid information" do
before { click_button "Sign in" }
it { should have_content('Sign in') }
it { should have_selector('div.flash_alert', text: "Invalid") }
end
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_not have_selector('a', text: 'Sign up')}
it { should_not have_selector('a', text: 'Sign in')}
it { should have_selector('a', text: 'Profile') }
it { should have_selector('a', text: 'Sign Out') }
it { should have_selector('div.flash_notice', text: "Signed in successfully.") }
end
it { should have_content('Sign in') }
end
end
And in factories.rb
FactoryGirl.define do
factory :user do
first_name "Example"
last_name "User"
username "exampleuser"
email "user#example.com"
password "foobar1234"
end
end
Every test is working apart from the sign in -with valid information set of tests. I have no clue as to why, and its working normally in the browser. Has anyone come across a problem like this?
If you're using the devise confirmable module, you have to add user.confirm! to your sign in method.
Put this in support/utilities.rb
def sign_in(user)
user.confirm!
visit new_user_session_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
In your describe block "with valid information" change this
before do
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
to this.
before { sign_in(user) }
I have a failing Rspec test, _pages_spec.rb. I am following Micheal Hartl's Rails Tutorial.
When I have the second "end" at line 83, all tests pass but one:
Failures:
1) User pages signup edit with valid information
←[31mFailure/Error:←[0m ←[31mit { should have_selector('div.alert.alert-suc
cess') }←[0m
←[31mexpected css "div.alert.alert-success" to return something←[0m
←[36m # ./spec/requests/user_pages_spec.rb:77:in `block (5 levels) in <top (
required)>'←[0m
Finished in 1.28 seconds
←[31m60 examples, 1 failure←[0m
Failed examples:
←[31mrspec ./spec/requests/user_pages_spec.rb:77←[0m ←[36m# User pages signup ed
it with valid information ←[0m
Here is the code:
require 'spec_helper'
describe "User pages" do
subject { page }
let (:base_title) {"Tom Gong's Sample App"}
describe "profile page" do
let(:user) { FactoryGirl.create(: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 page" do
before { visit signup_path }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', content: "#{base_title} | Sign up") }
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') }
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_selector('a', href: 'http://gravatar.com/emails') }
end
describe "with invalid information" do
before { click_button "Save changes" }
it { should have_content('error') }
end
describe "with valid information" do
let(:new_name) { "New Name" }
let(:new_email) { "new#example.com" }
before do
fill_in "Name", with: new_name
fill_in "Email", with: new_email
fill_in "Password", with: user.password
fill_in "Confirm Password", with: user.password
click_button "Save changes"
end
it { should have_selector('title', text: new_name) }
it { should have_selector('div.alert.alert-success') }
it { should have_link('Sign out', href: signout_path) }
specify { user.reload.name.should == new_name }
specify { user.reload.email.should == new_email }
end
end
end
end
Can anyone find the problem?
User pages signup edit with valid information
Here's how it looks like:
User pages
|- signup
|- edit
|- with valid information
It should be
User pages edit with valid information
i.e.
User pages
|- edit
|- with valid information
Currently edit is described under signup. That's not quite right.
I have the second "end" at line 83
It should be right after the line 53 rather than 83. i.e. right before describe "edit" do.
With consistent indentation you don't need to guess where to put matching end, it should be obvious from code.
The error message is telling you that the page does not have the selector 'div.alert.alert-success'. It looks like the error is related to this line:
it { should have_selector('div.alert.alert-success', text:'Welcome') }`
Capybara has a nifty method called save_and_open_page that lets you inspect the HTML file that Capybara parses. Call this method and view the source to inspect the selector that is not working for you. If you are still having trouble, paste the HTML that corresponds to the selector in your question.
You should clean up the formatting of your code because it is very hard to read with the inconsistent spacing and indentation.
I'm a newbie working through Michael Hartl's Tuby on Rails Tutorial and I have a couple of failed items in a test in Chapter 9.
Running RSPEC test returns:
sis-macbook-pro:sample_app Lagaspi$ bundle exec rspec spec/
...................................FF................................
Failures:
1) Authentication authorization in the Users controller visiting the edit page
Failure/Error: before { visit edit_user_path(user) }
NameError:
undefined local variable or method `user' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_3::Nested_2::Nested_1:0x007fca6433d3b8>
# ./spec/requests/authentication_pages_spec.rb:72:in `block (5 levels) in <top (required)>'
2) Authentication authorization in the Users controller submitting to the update action
Failure/Error: before { put user_path(user) }
NameError:
undefined local variable or method `user' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_3::Nested_2::Nested_2:0x007fca6434db50>
# ./spec/requests/authentication_pages_spec.rb:77:in `block (5 levels) in <top (required)>'
Finished in 1.85 seconds
69 examples, 2 failures
Failed examples:
rspec ./spec/requests/authentication_pages_spec.rb:73 # Authentication authorization in the Users controller visiting the edit page
rspec ./spec/requests/authentication_pages_spec.rb:78 # Authentication authorization in the Users controller submitting to the update action
My 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') }
describe "after visiting another page" do
before { click_link "Home" }
it { should_not have_selector('div.alert.alert-error') }
end
end
describe "with valid information" do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
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 have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Users', href: users_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
end
describe "authorization" do
describe "for non-signed-in users" do
let(:user) { FactoryGirl.create(:user) }
describe "when attempting to visit a protected page" do
before do
visit edit_user_path(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
describe "after signing in" do
it "should render the desired protected page" do
page.should have_selector('title', text: 'Edit user')
end
end
end
end
describe "in the Users controller" do
describe "visiting the edit page" do
before { visit edit_user_path(user) }
it { should have_selector('title', text: 'Sign in') }
end
describe "submitting to the update action" do
before { put user_path(user) }
specify { response.should redirect_to(signin_path) }
end
end
end
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong#example.com") }
before { sign_in user }
describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_selector('title', text: full_title('Edit user')) }
end
describe "submitting a PUT request to the Users#update action" do
before { put user_path(wrong_user) }
specify { response.should redirect_to(root_path) }
end
end
end
Here's line 73 from above
it { should have_selector('title', text: 'Sign in') }
And line 78 from above
specify { response.should redirect_to(signin_path) }
Any ideas? I'm really stuck as to what this means.Thanks Si.
On line 50 you have
let(:user) { FactoryGirl.create(:user) }
But :user is no longer available by the time you reach line 73 because you close off the describe block that :user is defined within in line 68. Same thing on line 77 where you try to use it again.
My recommendation is to move the let(:user) to the top of the spec so you only need to define it once instead of including it throughout the spec. Failing that, define it again on line 71 (the line after describe "in the Users controller" do)
Potential solution is defining let(:user)..... at the top so you only need to define user once instead of in each block
require 'spec_helper'
describe "authentication" do
subject { page }
let(:user) { FactoryGirl.create(:user) }
...
When I run
bundle exec rspec spec/requests/user_pages_spec.rb -e "edit page"
Terminal returns:
sis-macbook-pro:sample_app Lagaspi$ bundle exec rspec spec/requests/user_pages_spec.rb -e "edit page"
/Users/Lagaspi/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rspec-core-2.10.1/lib/rspec/core/configuration.rb:746:in `load': /Users/Lagaspi/rails_projects/sample_app/spec/requests/user_pages_spec.rb:66: syntax error, unexpected $end, expecting keyword_end (SyntaxError)
from /Users/Lagaspi/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rspec-core-2.10.1/lib/rspec/core/configuration.rb:746:in `block in load_spec_files'
from /Users/Lagaspi/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rspec-core-2.10.1/lib/rspec/core/configuration.rb:746:in `map'
from /Users/Lagaspi/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rspec-core-2.10.1/lib/rspec/core/configuration.rb:746:in `load_spec_files'
from /Users/Lagaspi/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rspec-core-2.10.1/lib/rspec/core/command_line.rb:22:in `run'
from /Users/Lagaspi/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rspec-core-2.10.1/lib/rspec/core/runner.rb:69:in `run'
from /Users/Lagaspi/.rvm/gems/ruby-1.9.3-p194#rails3tutorial2ndEd/gems/rspec-core-2.10.1/lib/rspec/core/runner.rb:10:in `block in autorun'
I really do not know how to tackle this problem, but here is my spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before { visit user_path(user) }
describe "signup" do
before { visit signup_path }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', text: full_title('Sign up')) }
end
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
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 }
it { should have_link('Sign out') }
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
Thanks in advance
If this is the exact code then you're missing two more end at the bottom. Add that and try again.
I cut/pasted your code into vim and did auto-indent to find the culprit.
Update:
Plus, your original error says missing end. The first one is on line 66 while the next error you listed here in the comments says line 67. These are exactly the lines where your end are missing.