Cucumber + Capybara - Difficulty filling a form - Element not found - testing

I am doing my hello world test application in an already completed project and am experiencing some scenarios and am puzzled by what I am seen is happening.
I am using:
Capybara
Cucumber
And selinium web driver for when we need Javascript
All of this on a Sinatra app
RSpec separately, but that is not the interest.
Problem:
When running cucumber tests as cucumber features/#{feature_name}.feature, and given that I am on a specific page. I can find elements by CSS ID but can't click on them.
When(/^I log in with email "(.*?)" and password "(.*?)"$/) do |email, password|
step %{I am on login page}
expect(page).to have_css('#login-form')
expect(page).to have_css('#login-button')
within("#login-form") do
fill_in '#username', with: email
fill_in '#password', with: password
click_button 'dfalkjsdfalsdkfja dflkjasdf alkdsjfasd lfkjsf s' # Which should fail, but odesn't :'(
end
click_button 'Sign In'
# click_button '#login-button' # This fails
end
The following test will pass even if I use a completely random non existent ID for #login-form. And as you see I have a button with some silly text. Also if I give it as an ID, no difference. The test passes.
But when I use them alone without the within block, the the elements are not found.
But above you see expect(page).to statements find them.
The above is some what similar to the example I see in the Capybara repo.
My Questions:
Can I use CSS selectors to target ex: #login-form
Should using a non existing selector in the within block fail? My case it doesn't.
Why is some thing like fill_in '#password', with: 'password' fail saying element not found while the above assertion seems to find it?
I am a newby, so a suggestion where things might have gone wrong in terms of setting up. Example link would also be great.
PS:
Forgot to ask, considering the example in the repo, what is 'Email' in the following fill_in block. Doesn't seem to be a id of the element.
fill_in 'Email', :with => 'user#example.com'
Update
After some playing around, I find the following working (finding the element and filling/clicking it). But the within block doesn't fill in the form. Can any config effect the within block as I explain.
When(/^I log in with email "(.*?)" and password "(.*?)"$/) do |email, password|
step %{I am on login page}
find('form#login-form').find('input#username').set email
find('form#login-form').find('input#password').set password
find('form#login-form').find('#login').click
within("form#login-form") do
fill_in 'input#username', with: email
fill_in 'input#password', with: password
click_button '#login'
end
end

Related

Rails testing button functionality with capybara.

I have this code, I am trying to click on the button to test its functionality using guard and capybara. I get an undefined method error on guard when I have it written like this. It comes back with no errors if I comment out the click_button line. It should render a response that the import was successful as well which is being displayed by an index page.
require 'rails_helper'
require 'spec_helper'
RSpec.describe "Imports", type: :request do
it "checks the import page." do
get '/imports'
click_button "submit"
end
end
how long does the it take to load the element? if > 2 seconds (capybara default wait time is 2s) then it's most likely you will get the undefined method error...
Try increasing capybara's timeout or do it for that element only:
click_button "submit", wait: 10
If that doesn't solve your issue then assure "submit" is the correct path to your element...
By default Capybara::DSL is only included in tests of type :feature, are you also including it in type :request?

How can I click_link a specific row with Capybara

I'm trying to write all my Capybara code to not use any CSS or funny matchers. For acceptance test purposes, I'm using Capybara to navigate only by button and link text that is visible to the user.
So I have a really simple test that asserts that an administrator can edit any user:
it 'allows an administrator to edit any user' do
user = login_admin_user
user1 = FactoryGirl.create(:user)
click_link "Users"
current_path.should eq(users_path)
click_link "Edit" # This is the problem
current_path.should eq(edit_user_path(user1))
fill_in "Last name", with: "Myxzptlk"
click_button "Update User"
page.should have_content("Myxzptlk")
end
Of course the problem line above is not specific enough; there will be 2 lines in the table (user and user1). I'm pretty new to TDD, so how do I use Capybara to select the correct link using only visible text?
I'm not sure why you're avoiding 'CSS or funny matchers'. If you don't want to put them in your test, abstract them away into helper methods.
In my specs I have a helper method like this:
module FeatureHelper
def within_row(text, &block)
within :xpath, "//table//tr[td[contains(.,\"#{text}\")]]" do
yield
end
end
end
And then in my specs I can call it like:
within_row(user1.name) do
click_link 'Edit'
end
The helper module goes inside the spec/support folder, and then gets loaded into my specs by doing:
config.include FeatureHelper, type: :feature
in my spec_helper.rb.

Why isn't my tests working for this form?

In Firefox, if I try to submit a post without a title, I get: 1 error prohibited this post from being saved.
But when I run my test. It's a different story.
My Post model has validates_presence_of :title. My test looks like:
require 'spec_helper'
describe 'Users' do
it 'registered users should not be able to post without a title', :js => true do
user = Factory(:user)
visit new_post_path
current_path.should eq(new_post_path)
fill_in 'post[markdown_description]', :with => 'Bar'
click_on 'Submit your post'
page.should have_content('error')
end
end
By the way, I am using Selenium (:js => true), because my submit button is actually an anchor link with some JS. Basically, when the link is clicked, JS triggers the form to be submitted.
Rspec returns:
Running: spec/requests/users_spec.rb
F
Failures:
1) Users registered users should be able to post
Failure/Error: page.should have_content('error')
expected there to be content "error" in ""
# ./spec/requests/users_spec.rb:13:in `block (2 levels) in <top (required)>'
Finished in 7.9 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/requests/users_spec.rb:4 # Users registered users should be able to post
The request may not make it to the controller action if you have before_filters. Check the log to make sure that the correct parameters are posting and that the action is not redirecting.
Another option is to include this in your spec:
click_on 'Submit your post'
save_and_open_page
which opens the current page in the browser so you can see what is actually being rendered.

Failing to test Devise with Capybara

I'm building a Rails 3 app using Devise, with Capybara for UI testing. The following test is failing:
class AuthenticationTest < ActionController::IntegrationTest
def setup
#user = User.create!(:email => 'test#example.com',
:password => 'testtest',
:password_confirmation => 'testtest')
#user.save!
Capybara.reset_sessions!
end
test "sign_in" do
# this proves the user exists in the database ...
assert_equal 1, User.count
assert_equal 'test#example.com', User.first.email
# ... but we still can't log in ...
visit '/users/sign_in'
assert page.has_content?('Sign in')
fill_in :user_email, :with => 'test#example.com'
fill_in :user_password, :with => 'testtest'
click_button('user_submit')
# ... because this test fails
assert page.has_content?('Signed in successfully.')
end
end
... but I have no idea why. As you can see from the code, the user is being created in the database; I'm using the same approach to create the user as I did in seeds.rb.
If I run the test through the debugger, I can see the user in the database and verify that the page is loading. But still the authentication fails; I can verify this because if I change the assertion to test for the failure case, the test passes:
# verify that the authentication actually failed
assert page.has_content?('Invalid email or password.')
I'm used to Rails 2, & using Selenium for this sort of testing, so I suspect I'm doing something daft. Could someone please point me in the right direction here?
I was having the same issue and found a thread with a solution:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
For the DatabaseCleaner stuff to work you'll need to include the database_cleaner gem. If you haven't used it before, you may need to rake db:test:prepare before rerunning your tests. I hope this works for you, too!
I've run into a similar problem before. Setting the password directly has some weird effects because it's supposed to be encrypted and stored with a salt--sometimes it works for me and other times it doesn't. I have a hard time remembering which specific cases were problematic. I'd recommend the following, in this order (for simplicity)
Verify that the password field is getting filled in properly and passed as the right param (not necessary if you're using Devise's autogenerated view and haven't touched it)
if your site can run in development mode (i.e. no log in bugs), then just boot it up and log in manually
If not, insert debugger as the first line in your sessions_controller. Then check params and make sure the password is correct and in params[:user][:password].
If you didn't override Devise's sessions_controller, then you can find your Devise path with bundle show devise. Then look for the create action within (devise path)/app/controllers/devise/sessions_controller.rb
Change your test setup to create a user through the web interface, to ensure the password gets set properly, then try running your test again
I had the same issue with a setup fairly similar to yours. In my case, switching to ActiveRecord sessions in the initializer solved the problem.
Additionally, make sure you call #user.skip_confirmation! if you are using the "confirmable" module in devise.

Few questions about capybara

I've got a few questions about Capybara. And I might as well ask here since the RDOC in the github page for Capybara is great to get it set up and running. But where is the API or list of available methods??
First. Per *_spec.rb file, should scenario only exist once? Or is it fine to have multiple scenario's in one file?
For example, in spec/request/user_spec.rb:
require 'spec_helper'
feature 'User actions' do
background do
data = {
:first_name => 'foo',
:last_name => 'bar',
...
}
user = User.new(data, :as => :user)
user.save
end
scenario 'User can browse home page' do
visit root_path
page.should have_content('Homepage')
end
scenario 'User should not be able to visit the dashboard' do
visit dashboard_root_path
page.should have_content('You are not authorized to access this page.')
end
end
If there is anything wrong with the code structure above, or if there is room for improvement. I am open feedback.
Second. I notice with the code above. If I have config.use_transactional_fixtures = false in spec/spec_helper.rb, it saves the user twice. This means, in my test database / user table, I would have 2 users named 'foo bar'. Is this normal?
Third. I have a form that has an HTML button. When user clicks on this button, jQuery submits the form. How would I test this with Capybara? I don't think click_button "Add" will do the trick.
Fourth. How would I sign in users in Capybara? I am using Devise. Would sign_in User.first do the trick? And would I be able to access current_user in Capybara?
Lastly, if anyone knows any "Getting Started" guides / tutorials on Rspec + Capybara. Please do mention.
I've also switched over to writing request specs ever since i decided that I was no longer liking Cucumber.
ONE) Having multiple scenarios is indeed fine. You get to use all the other great features of rspec, so I would suggest also using contexts as in the code at the bottom.
TWO) This can probably be solved by using the Rspec Set Gem And the Database Cleaner Gem. Also: The Original Rationale for Set
Warning: make sure you set up DatabaseCleaner correctly when you use set. My own setup (which may be a little overkill but is working for me):
config.before(:suite) do
DatabaseCleaner.clean_with :truncation
end
config.before(:all) do
DatabaseCleaner.clean_with :truncation
end
config.after(:all) do
DatabaseCleaner.clean_with :truncation
end
config.after(:suite) do
DatabaseCleaner.clean_with :truncation
end
THREE) yep! click_button "Add" should work! The complete capybara API is useful but took me a while to grok. Of most relevant importance are the actions and rspec matchers.
example:
click_button "Add"
page.should have_content("Successfully Added")
you can narrow the scope with element finders.
FOURTH) Devise provides helpers. there is a sign_in helper. read the dox :). Here's a demo:
feature 'User actions' do
background do
data = {
:first_name => 'foo',
:last_name => 'bar',
...
}
#user = User.new(data, :as => :user)
#user.save
end
context "no user is signed in" do
scenario 'User can browse home page' do
visit root_path
page.should have_content('Homepage')
end
scenario 'User should not be able to visit the dashboard' do
visit dashboard_root_path
page.should have_content('You are not authorized to access this page.')
end
end
context "user is signed in" do
before :each do
sign_in #user
end
[more scenarios]
end
end
ultimately of course, you'd prolly want to split this up into more specific features. Probably have a "Public Navigation" Feature for all the tests that are about guests seeing content, and then a separate feature for a user signing in, etc.
I am not aware of capybara, but a full list of available methods can be found here:
http://rubydoc.info/github/jnicklas/capybara/master#
hope, that helps