How do I assert the unexistance of a model in Cucumber? - ruby-on-rails

How do I assert that a user was not created while using Cucumber? In RSpec, I would use the following block, which I can not translate to Cucumber:
...
describe "with invalid information" do
it "should not create a new user" do
expect { click_button submit }.not_to change(User, :count)
end
end
# Cucumber equivalent
When /^he submits invalid information$/ do
click_button "Sign up"
end
Then /^an account should not be created$/ do
# not sure how to translate the expect block
end

In this example, you'll know the email that the user would use, so you could:
Then /^an account should not be created$/ do
User.where(email: "youremail#example.com").first.should be_nil
end

You could also do
Given I have 3 users
When I submit with invalid information
Then I should have 3 users

You can use a lambda to directly translate your RSpec test, rather than rely on a workaround.
Then /^an account should not be created$/ do
save = lambda { click_button :submit }
expect(save).not_to change(User, :count)
end

Related

Writing multiple feature spec expectations from a single action

So I'm writing my feature test and it goes something like this, note the [[place_holder]]
feature 'Accounts' do
scenario 'creating an account' do
# visit and fill form
expect {
click_button 'Create Account'
}.to [[place_holder]]
success_message = 'Your account has been successfully created.'
expect(page).to have_content(success_message)
end
end
Now I want to somehow place 2 expecations for this block, these expectations are
change(User, :count).by(1)
change(Account, :count).by(1)
Is there a way I could like chain these two exectations into one, yea I know I could just do a test for each in it's scenario, but that code is too WET, no need for duplications, and the feature specs are slow to begin with, no need to make my test suite slower.
Any suggestions/alternatives are appriceated
From rspec 3.1, you can use compound matcher expressions with block expectations.
expect {
click_button 'Create Account'
}.to change(User, :count).by(1).and change(Account, :count).by(1)
http://rspec.info/blog/2014/09/rspec-3-1-has-been-released/#expectations-block-matchers-can-now-be-used-in-compound-expressions
Since the data will presumably be cleared between each test run, you could just check the absolute value, e.g.
expect(User.count).to eq(1)
expect(Account.count).to eq(1)
I think this is more readable.

Rspec: sign_in using capybara doesn't work in controller spec

I'm working on exercise 9 from chapter 9 in Rails Tutorial: http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-users#fnref-9_9
"Modify the destroy action to prevent admin users from destroying themselves. (Write a test first.)"
I started with creating test:
users_controller_spec.rb
require 'spec_helper'
describe UsersController do
describe "admins-userscontroller" do
let(:admin) { FactoryGirl.create(:admin) }
let(:non_admin) { FactoryGirl.create(:user) }
it "should not be able to delete themself" do
sign_in admin
expect { delete :destroy, :id => admin.id }.not_to change(User, :count)
end
end
end
however, noticed that even if logic for prohibiting admin to delete himself is not implemented, test passes unless I change line
sign_in admin
to
sign_in admin, no_copybara: true
after this change test fails (as expected)
sign_in is in support\utilities.rb file and looks like this:
def sign_in(user, options={})
if options[:no_capybara]
# Sign in when not using Capybara.
remember_token = User.new_remember_token
cookies[:remember_token] = remember_token
user.update_attribute(:remember_token, User.hash(remember_token))
else
visit signin_path
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
end
Does anyone know why it doesn't work with capybara? It looks like the "else" section of the above code fails/doesn't execute when using capybara but it doesn't return any error (e.g. that "Email" field is not found, so it looks like it's rendered)...
Other problem is that if I remove non_admin instead of admin:
expect { delete :destroy, :id => non_admin.id }.not_to change(User, :count)
test passes which means non_admin isn't deleted... why does it work for admin and not non_admin?
Question 2:
capybara is not supposed to work in request spec as of 2.0+, but Im using capybara 2.1 and rspec-rails 2.13.1 and it works just fine in request specs (actually that's even what tutorial tells us to do), doesn't even output any warning...

Rpsec check existence and value of a record

I want to test a existence of a User model attribute.
So I write like this.
describe "Authentications" do
it "sign up with twitter" do
visit new_user_session_path
expect { click_link "Sign up with Twitter"}.to change(User, :count).by(1)
end
describe "new user" do
let(:new_user) { User.last }
it "should have slug" do
#new_user its(:slug) { should eq("foo") }
new_user.slug should exist
end
end
end
First test passes, but second test fails with error like this.
1) Authentications new user should have slug
Failure/Error: new_user.slug should exist
NoMethodError:
"new user" does not respond to either #exist? or #exists?
# ./spec/features/autentication_spec.rb:13:in `block (3 levels) in <top (required)>'
I think I'm calling method wrong way. How should I use it?
After all I want to check not only existence of it but also the value of it. But it fails also.
If you want to validate presence of a value you should use the method present? that Rails provides.
expect(new_user.slug).to be_present should work for what you want.
First of all, the failing expectation you have is equivalent to:
new_user.slug(subject.should(exist))
This is why your failure message refers to "new user", which is the description of our example and thus the implicit value of subject.
Presumably, you intended the should to have been applied to new_user.slug, in which case, you should have written:
new_user.slug.should exist
However, that will only exist if the value of new_user.slug has an exist? method defined on it (per https://www.relishapp.com/rspec/rspec-expectations/v/2-99/docs/built-in-matchers/exist-matcher), which strings do not.
If you want to test whether something is simply truthy, then you can use:
new_user.slug.should be
If you want to exclude false as a value, then you can use:
new_user.slug.should_not be_nil
The rest of this answer deals with a separate matter, which may or may not impact your test depending on whether or not you have a User in your database prior to the overall describe block being invoked.
Assuming you're operating with transactions on, the user created in your initial it block does not exist in the body of your subsequent describe, so User.first is going to return nil, which explains your errors.
If you want to check that your sign in changes the user count by one and use that sign in with a separate test, you can use a let expression as in the following:
describe "Authentications" do
let(:sign_in) do
visit new_user_session_path
click_link "Sign up with Twitter"
end
it "sign up with twitter" do
expect { sign_in }.to change(User, :count).by(1)
end
describe "new user" do
let(:new_user) { User.last }
before { sign_in }
it "should have slug" do
#new_user its(:slug) { should eq("foo") }
new_user.slug should exist
end
end
end
If you want to combine these tests for purposes of understanding the slug failure, you can do so as follows:
describe "Authentications" do
it "sign up with twitter" do
visit new_user_session_path
expect { click_link "Sign up with Twitter" }.to change(User, :count).by(1)
User.last.slug should exist
end
end

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).

How does RSpec's expect work in ROR

While going through Ruby On Rails Tutorial by Michael Hartl,in the section where the author writes integration test to validate his Signup page, he has used code spinet bellow. I got what the code does but couldn't get my head around the 'how' part i.e. couldn't understand order of execution.
expect { click_button "Create my account" }.not_to change(User, :count)
Can someone please explain the semantics of the above chain of methods and blocks and how they fit together?
You'd use expect ... change to verify that a particular method call changes -- or does not change -- some other value. In this case:
expect { click_button "Create my account" }.not_to change(User, :count)
will cause rspec to do the following:
Run User.count and note the value returned. (This can be specified as a receiver and a method name, like (User, :count) in your example, or as an arbitrary block of code, like { User.count }.
Run click_button "Create my account" which is a Capybara method that simulates a mouse click on a link.
Run User.count again.
Compare the results of #1 and #3. If they differ, the example fails. If they're the same, it passes.
Other ways to use expect ... change:
expect { thing.destroy }.to change(Thing, :count).from(1).to(0)
expect { thing.tax = 5 }.to change { thing.total_price }.by(5)
expect { thing.save! }.to raise_error
expect { thing.symbolize_name }.to change { thing.name }.from(String).to(Symbol)
Some docs are here.
How it does this is a bit arcane, and it's not at all necessary to understand how it works in order to use it. A call to expect is defining a structure for rspec to execute, using rspec's own custom DSL and system of "matchers." Gary Bernhardt has a rather neat screencast in which he argues that the mystery of rspec actually falls out naturally from a dynamic language like ruby. It's not a good introduction to using rspec, but if you're curious about how it all works, you might find it interesting.
UPDATE
After seeing your comment on another answer, I'll add a bit about the order of operations. The unintuitive trick is that it's the matcher (change in this case) that executes all of the blocks. expect has a lambda, not_to is an alias for should_not whose job is to pass the lambda on to the matcher. The matcher in this case is change which knows to execute its own argument once, then execute the lambda that it was passed (the one from expect), then run its own argument again to see if things changed. It's tricky because the line looks like it should execute left to right, but since most of the pieces are just passing around blocks of code, they can and do shuffle them into whatever order makes the most sense to the matcher.
I'm not an expert on the rspec internals, but that's my understanding of the basic idea.
Here's an excerpt from from Ryan Bates Railscast on Request Specs and Capybara
require 'spec_helper'
describe "Tasks" do
describe "GET /tasks" do
it "displays tasks" do
Task.create!(:name => "paint fence")
visit tasks_path
page.should have_content("paint fence")
end
end
describe "POST /tasks" do
it "creates a task" do
visit tasks_path
fill_in "Name", :with => "mow lawn"
click_button "Add"
page.should have_content("Successfully added task.")
page.should have_content("mow lawn")
end
end
end
And here's an excerpt from the docs on RSPec Expectations
describe Counter, "#increment" do
it "should increment the count" do
expect{Counter.increment}.to change{Counter.count}.from(0).to(1)
end
# deliberate failure
it "should increment the count by 2" do
expect{Counter.increment}.to change{Counter.count}.by(2)
end
end
So basically, the
expect { click_button "Create my account" }.not_to change(User, :count)
is part RSpec:
expect {...}.not_to change(User, :count)
and part Capybara
click_button "Create my account"
(Here's a link to the Capyabara DSL -- you can search for click_button)
It sounds like you're looking for an overall example with them both. This isn't a perfect example, but it could look something like this:
describe "Tasks" do
describe "GET /tasks" do
it "displays tasks" do
expect { click_button "Create my account" }.not_to change(User, :count)
end
end
end

Resources