I am trying to do Exercise 2 of chapter 8.5 in the Michael Hartl Ruby on Rails Tutorial . The exercise is as follows:
Following the example in Section 8.3.3, review the specifications for user request and authentication (that is, the files currently in the spec / requests directory) and define the utility functions in spec / support / utilities.rb to separate the tests from the implementation. Extra credit. Organize the support code into separate files and modules and get everything to work by including the modules correctly in the auxiliary spec file.
Example 8.3.3: utilities.rb
include ApplicationHelper def valid_signin(user) fill_in "Email", with: user.email fill_in "Password", with: user.password click_button "Sign in" end RSpec::Matchers.define :have_error_message do |message| match do |page| page.should have_selector('div.alert.alert-error', text: message) end end
The defined valid_signin(user) function is used in the next authentication_pages_spec.rb block and works fine.
describe "with valid information" do let(:user){FactoryGirl.create(:user)} before { valid_signin(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_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
So, in this example, I started creating my own valid_signup(user) name:
def valid_signup(user) fill_in "Name", with: user.name fill_in "Email", with: user.email fill_in "Password", with: user.password fill_in "Confirmation", with: user.password_confirmation end
I use this block in user_pages_spec.rb as follows:
describe "with valid information" do let(:user){FactoryGirl.create(:user)} before { valid_signup(user) } 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.email) } 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
This does not work. Spork / Guard reports these errors:
Failures: 1) UserPages signup with valid information should create a user Failure/Error: expect { click_button submit }.to change(User, :count).by(1) count should have been changed by 1, but was changed by 0
Errors seem to indicate that user.name in my valid_signup(user) function in utilities.rb not defined, but I see no reason. I restarted Guard several times and did rake db:test:prepare to make sure db testing (using postgresql) was ok.
Here is my factories.rb for completeness:
FactoryGirl.define do factory :user do name "Example User" email "user@example.com" password "foobar" password_confirmation "foobar" end end
Before I try to separate more from the test suite, I would really like to solve this error and, more importantly, understand the reason for this.
EDIT
I tried your tips and edited the function in user_pages_spec.rb as follows:
describe "with valid information" do before { valid_signup(user) } 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
Since I removed let(:user){FactoryGirl.create(:user)} from the function I guessed, the function no longer had a user, so I had to define valid_signup(user) , since the user variable for valid_signup bigger FactoryGirl didn't populate:
def valid_signup(user) fill_in "Name", with: "Example User" fill_in "Email", with: "user@example.com" fill_in "Password", with: "foobar" fill_in "Confirmation", with: "foobar" end
This did not work and gave me the following errors:
Failures:
1) UserPages signup with valid information should create a user Failure/Error: before { valid_signup(user) } NameError: undefined local variable or method user' for #<RSpec::Core::ExampleGroup::Nested_5::Nested_3::Nested_2:0x007fdafc5088c0> # ./spec/requests/user_pages_spec.rb:42:in block (4 levels) in '
2) /: { _ ('title', text: user.name)} NoMethodError: undefined name' for nil:NilClass # ./spec/requests/user_pages_spec.rb:52:in (5 ) '
I also tried to run the test with valid_signup(user) in the way I used it before (with user.name, user.email, user.password, user.password_confirmation , which also did not work) with errors:
Failures: 1) UserPages signup with valid information should create a user Failure/Error: before { valid_signup(user) } NameError: undefined local variable or method `user' for # # ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in ' 2) UserPages signup with valid information after saving the user Failure/Error: it { should have_selector('title', text: user.name) } NoMethodError: undefined method `name' for nil:NilClass
Then I tried to run it without passing variables to user_pages_spec.rb : before { valid_signup() } and without a variable in a function in utilities.rb :
def valid_signup() fill_in "Name", with: "Example User" fill_in "Email", with: "user@example.com" fill_in "Password", with: "foobar" fill_in "Confirmation", with: "foobar" end
This returns:
Failures: 1) UserPages signup with valid information should create a user Failure/Error: before { valid_signup(user) } NameError: undefined local variable or method `user' for # # ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in ' 2) UserPages signup with valid information after saving the user Failure/Error: it { should have_selector('title', text: user.name) } NoMethodError: undefined method `name' for nil:NilClass
Still no closer to the answer. I could have missed something simple. I don’t know what. I got what I did wrong at first: I just thought FactoryGirl was a way to create variables, and I did not know that it really did something with my test database.