Simple rspec test failing - ruby-on-rails

I would have thought this test would have passed. Any ideas why it isnt?
it 'should create an account' do
visit new_user_registration_path
fill_in 'user_email', with: 'newtest#test.com'
fill_in 'user_password', with: 'testing123'
fill_in 'user_password_confirmation', with: 'testing123'
expect{
click_button 'Sign Up'
}.to change{User.count}.by(1)
end
I just get
result should have been changed by 1, but was changed by 0

It is a counter cache problem, see this:
Rails counter_cache not updating correctly

Silly mistake. I had a validation on user for name!

Related

Capybara Rspec Rails get ID for path

Using capybara/rspec to test rails. Want to check current path is generated correctly with the id but cant access the created Contact id.
Example expectation:
localhost:3000/contacts/27
Example recieved:
localhost:3000/contacts/
Code base:
feature 'contacts' do
before do
visit '/'
click_link 'Sign up'
fill_in 'Email', with: 'test#test.com'
fill_in 'Password', with: '123456'
fill_in 'Password confirmation', with: '123456'
click_button 'Sign up'
click_link 'Add a contact'
fill_in 'Firstname', with: 'John'
fill_in 'Surname', with: 'Jones'
fill_in 'Email', with: 'test#test.com'
fill_in 'Phone', with: '223344'
attach_file('contact[image]', Rails.root + 'spec/mouse1.jpeg')
click_button 'Create Contact'
end
context 'view a contact' do
scenario 'click contact to view details' do
click_link('Mouse1')
expect(page).to have_content 'John Jones 223344 test#test.com'
expect(page).to have_xpath("//img[contains(#src, \/html/body/a[2]/img\)]")
expect(page).to have_current_path(contact_path("#{#contact.id}"))
end
end
Surprised the interpolation hasn't worked and throws error undefined method 'id' for NilClass using the below. Clearly it cant access the id.
expect(page).to have_current_path(contact_path("#{#contact.id}"))
Also tried swapping it out with #p = Contact.find_by_id(params[:id]) then passing in the #p in the interpolation. But throws error undefined local variable or method params
Any ideas/thoughts?
You can't access your controllers instance variables from within a feature test. You can however access the database, and since you've only created one contact in this test first or last should work -
expect(page).to have_current_path(contact_path("#{Contact.last.id}"))
That being said, signing up a user and creating the contact through the UI when your test is only checking that an existing contact can be viewed doesn't make a lot of sense when you could just create the database records for your feature tests. You probably want to look into something along the line of FactoryGirl for building your feature test objects.

Within a feature spec, how to test that a Devise mailer is called successfully?

I have a feature test for user registration. How do I test that Devise confirmation instructions are sent correctly? I don't need to test the content of the email, only that the mailer has been called.
I am sending mails in the background.
#user.rb
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
I have tried a few approaches that work for other mailers, including
it "sends the confirmation email" do
expect(Devise.mailer.deliveries.count).to eq 1
end
and
it "sends the confirmation email" do
message_delivery = instance_double(ActionMailer::MessageDelivery)
expect(Devise::Mailer).to receive(:confirmation_instructions).and_return(message_delivery)
expect(message_delivery).to receive(:deliver_later)
end
none of which are working as expected for Devise messages.
What am I doing wrong?
Edit
The feature spec looks like this:
feature "User signs up" do
before :each do
visit '/'
click_link 'Sign up'
fill_in 'user_email', with: valid_attributes[:email]
fill_in 'user_password', with: valid_attributes[:password]
fill_in 'user_password_confirmation', with: valid_attributes[:password]
click_button 'Sign up'
end
it "sends the confirmation email" ...
end
Since you're doing a high level feature spec, I would wager that as a result of clicking the 'Sign up' button, what you want to confirm is that an email job has been added to the queue.
In order to do that, you may have to slightly change your spec set up:
feature "User signs up" do
before :each do
visit '/'
click_link 'Sign up'
fill_in 'user_email', with: valid_attributes[:email]
fill_in 'user_password', with: valid_attributes[:password]
fill_in 'user_password_confirmation', with: valid_attributes[:password]
end
it "queues up a confirmation email job" do
expect { click_button 'Sign up' }.to \
have_enqueued_job(ActionMailer::DeliveryJob)
end
end
You can have a look at the have_enqueued_job matcher for more options if the above one doesn't quite suit your use case.

Failure/Error: expect { click_button submit }

I testing with rspec, Im still learning, I guess I'm on the right way... but when I test my rspec file I got this error:
Failures:
1) UsersController 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
# ./spec/controllers/user_controller_spec.rb:31
Finished in 1.16 seconds
2 examples, 1 failures
I know what this mean, but I don't know how to fix it, can anyone help me with this trouble please...Also I put my rspec file
require 'spec_helper'
describe UsersController do
describe "signup" do
before { visit new_user_registration_path }
let(:submit) { "Sign up" }
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 "Email", :with=> "user#example.com"
fill_in "Password", :with=> "foobar"
#fill_in "password_confirmation", :with=> "foobar"
end
(here is that the error appears...below line)
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
end
end
end
thanks for your attention
So, you have a failing spec. The spec itself looks ok. So I would check on
is the implementation in place? You can try out the scenario in your browser. Does it work there? If not, you have a failing test (which is good) and need to add the implementation.
if the implementation works, check the spec again carefully. Is the provided information
fill_in "Email", :with=> "user#example.com"
fill_in "Password", :with=> "foobar"
sufficient to create a user?
if you still haven't found the cause, you could use capybaras save_and_open_page (install launchy gem for that) and peek at the page during your test.
ADDITION:
ok, as I said, this should be an integration test - move it from the spec/controllers to the spec/requests folder (and do change the first line, as you're not describing the UsersController! but that should not lead to the problem).

RSpec doesn't remove DB record so it fails the second time it runs

This is from Michael Hartl's book, section 8.4. RSpec is testing a successful signup but is fails because the email address isn't unique. So if I go into the code and update the email address in the spec, it works the first time I run it but not the second time. I have confirmed this because I can make the test pass by changing the email address or otherwise running rake db:test:clone.
Any thoughts on how to overcome this would be appreciated.
Code:
require 'spec_helper'
describe "Users" do
describe "signup" do
describe "failure" do
it "should not make a new user" do
lambda do
visit signup_path
fill_in :user_name, :with => "" #you can use CSS id instead of label, which is probably better
fill_in "Email", :with => ""
fill_in "Password", :with => ""
fill_in "Password confirmation", :with => ""
click_button
response.should render_template('users/new')
response.should have_selector("div#error_explanation")
end.should_not change(User, :count)
end
end
describe "success" do
it "should make a new user" do
lambda do
visit signup_path
fill_in "Name", :with => "Example User"
fill_in "Email", :with => "alex#example.com"
fill_in "Password", :with => "foobar"
fill_in "Password confirmation", :with => "foobar"
click_button
response.should have_selector("div.flash.success", :content => "Welcome")
response.should render_template('users/show')
end.should change(User, :count).by(1)
end
end
end
end
What does your spec/spec_helper.rb file look like? Do you have transactions turned on?
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
This runs each of your specs within a database transaction, returning it back to its original state after each test run.
Once your spec helper looks something like that, run:
rake db:test:prepare
And try again. If that doesn't work, can you provide any more information? Which version of RSpec? Which version of Rails?

Maintaining Session with Capybara and Rails 3

I have two capybara tests, the first of which signs in a user, and the second which is intended to test functions only available to a logged in user.
However, I am not able to get the second test working as the session is not being maintained across tests (as, apparently, it should be).
require 'integration_test_helper'
class SignupTest < ActionController::IntegrationTest
test 'sign up' do
visit '/'
click_link 'Sign Up!'
fill_in 'Email', :with => 'bob#wagonlabs.com'
click_button 'Sign up'
assert page.has_content?("Password can't be blank")
fill_in 'Email', :with => 'bob#wagonlabs.com'
fill_in 'Password', :with => 'password'
fill_in 'Password confirmation', :with => 'password'
click_button 'Sign up'
assert page.has_content?("You have signed up successfully.")
end
test 'create a product' do
visit '/admin'
save_and_open_page
end
end
The page generated by the save_and_open_page call is the global login screen, not the admin homepage as I would expect (the signup logs you in). What am I doing wrong here?
The reason this is happening is that tests are transactional, so you lose your state between tests. To get around this you need to replicate the login functionality in a function, and then call it again:
def login
visit '/'
fill_in 'Email', :with => 'bob#wagonlabs.com'
fill_in 'Password', :with => 'password'
fill_in 'Password confirmation', :with => 'password'
click_button 'Sign up'
end
test 'sign up' do
...
login
assert page.has_content?("You have signed up successfully.")
end
test 'create a product' do
login
visit '/admin'
save_and_open_page
end
Each test is run in a clean environment. If you wish to do common setup and teardown tasks, define setup and teardown methods as described in the Rails guides.

Resources