Capybara Rspec Rails get ID for path - ruby-on-rails

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.

Related

Testing Stripe works with js: true, but it makes other components work incorrectly

Testing the stripe framework requires Javascript to be turned on, but when I send js: true in it method, the other components like visit, fill_in stop working in the way they were working before.
Here is my code:
def sign_up(subdomain)
visit root_url(subdomain: false)
visit new_account_path
fill_in 'Name', with: 'Ryan'
fill_in 'Email', with: 'test#test.com'
fill_in 'Password', with: 'password'
fill_in 'Password confirmation', with: 'password'
fill_in 'Subdomain', with: subdomain
click_button 'Create Account'
end
In the sign_up method, visit new_account_path was working before js: true, but now it doesn't.
I'm turning js: true in the following method:
it 'shows the user can upgrade his account with valid card number, expiration and CVC', js: true do
fill_in "card_number", :with => "4242424242424242"
fill_in "card_expiry_month", :with => "05"
fill_in "card_expiry_year", :with => "2015"
fill_in "card_cvc", :with => "123"
click_button 'Upgrade Your Account'
expect(page).to have_content "Update Your Payment Information"
end
I've been searching the solution for quite a long time, but so far unable to resolve this.
As per your comment, you're getting an error from stripe's API: Stripe::InvalidRequestError.
According to their API (https://stripe.com/docs/api#errors):
Invalid request errors arise when your request has invalid
parameters.
I would wager that there is something actually wrong with your request to Stripe rather than the Capybara (?) spec you wrote.
I've written a blog post about writing acceptance tests with RSpec and Capybara for Stripe. You can view it here

Rspec/Capybara test cases are not working for multiple 'it' blocks

I am writing some integration test cases for an existing application. My test works fine if there is only one 'it' block. However, If I add more than one 'it' block it throws an error. Below is my code that works:
require 'spec_helper'
describe 'Group' do
before do
visit 'http://groups.caremonkey.com/users/sign_in'
fill_in "Email", :with => "email#example.com"
fill_in "Password", :with => "password"
click_button "Login"
page.should have_link('Account')
end
it 'Should check all the links and functionality of groups' do
#add new subgroup with valid data should save a new group
find("#group-squares").click_link("Add")
fill_in "Group Name", :with => "Melbourne futsal"
click_on("Save")
page.should_not have_content("can't be blank")
page.execute_script("parent.$.fancybox.close();")
page.should have_link('Account')
#test edit group: should be able to update group info provided valid data are given
first(".actual img").click
page.should have_content("Group")
page.should have_link("Cancel")
fill_in "Group name", :with => "Futsal club"
page.execute_script("$('#sub-group-color-options').find('.color23').click()")
click_button "Save"
click_on("Cancel")
page.should have_link('Account')
end
end
It works perfectly fine when I put all the 'it' block together in a single 'it' block. But when I split them in different 'it' block, it stops working. For example if I split this ("test edit group: should be able to update group info provided valid data are given") test case into separate 'it' block as follows
require 'spec_helper'
describe 'Group' do
before do
visit 'http://groups.caremonkey.com/users/sign_in'
fill_in "Email", :with => "email#example.com"
fill_in "Password", :with => "password"
click_button "Login"
page.should have_link('Account')
end
it 'add new subgroup with valid data should save a new group' do
find("#group-squares").click_link("Add")
fill_in "Group Name", :with => "Melbourne futsal"
click_on("Save")
page.should_not have_content("can't be blank")
page.execute_script("parent.$.fancybox.close();")
page.should have_link('Account')
end
it 'should be able to update group info provided valid data are given' do
first(".actual img").click
page.should have_content("Group")
page.should have_link("Cancel")
fill_in "Group name", :with => "Futsal club"
page.execute_script("$('#sub-group-color-options').find('.color23').click()")
click_button "Save"
click_on("Cancel")
page.should have_link('Account')
end
end
then rspec fails, it passes the first test, however second test gets failed throwing following error.
Failure/Error: visit 'http://groups.caremonkey.com/users/sign_in'
ActionController::RoutingError:
No route matches [GET] "/users/sign_in"
One more thing, I have to test all the features in remote(url: http://groups.caremonkey.com/). Because, I am writing integration tests for an existing application. In addition, I need to login to the system before I test rest of the features of my application. Thanks in advance for your help.
Have you followed the Capybara documentation for calling remote servers? It says you should have the following:
Capybara.current_driver = :selenium # Or anything but rack_test, probably
Capybara.run_server = false # Don't run your app in-process
Capybara.app_host = 'http://groups.caremonkey.com/'
My guess is that when you have visited the site once, future visit calls are trying to use relative routes, which then is routed to the default server. I can't think why you would get a ActionController::RoutingError if you don't have some kind of Rack server running. Are you running these tests in some other Rails application?
I guess something like this:
require 'spec_helper'
describe 'Group' do
before do
visit 'http://groups.caremonkey.com/users/sign_in'
fill_in "Email", :with => "email#example.com"
fill_in "Password", :with => "password"
click_button "Login"
page.should have_link('Account')
find("#group-squares").click_link("Add") #apperently both specs are "scoped" to this page
end
it 'Should check all the links and functionality of groups' do
fill_in "Group Name", :with => "Melbourne futsal"
click_on("Save")
page.should_not have_content("can't be blank")
page.execute_script("parent.$.fancybox.close();")
page.should have_link('Account')
end
it "test edit group: should be able to update group info provided valid data are given"
first(".actual img").click
page.should have_content("Group")
page.should have_link("Cancel")
fill_in "Group name", :with => "Futsal club"
page.execute_script("$('#sub-group-color-options').find('.color23').click()")
click_button "Save"
click_on("Cancel")
page.should have_link('Account')
end
end
My gut feeling tells me both test need the follow this: find("#group-squares").click_link("Add") so I added it to the before block This test however is cryptic, what is first(".actual img")?

Simple rspec test failing

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!

Cucumber + Webrat doesn't submit forms?

I'm new to Cucumber and totally lost as to why this integration test is failing. I have the following scenarios:
Scenario: User changes profile
Given I have an account
When I change my profile
Then my profile should be saved
Scenario: User changes login
Given I have an account
When I change my login information
Then my account should be changed
And these step definitions:
Given /^I have an account$/ do
#user = Factory.create(:user)
visit login_path
fill_in "Email", :with => #user.email
fill_in "Password", :with => 'secret'
click_button "Sign in"
end
When /^I change my profile$/ do
visit edit_user_profile_path(#user)
fill_in "First name", :with => "John"
fill_in "Last name", :with => "Doe"
click_button "Update Profile"
end
Then /^my profile should be saved$/ do
#user.profile.first_name.should == "John"
#user.profile.last_name.should == "Doe"
end
When /^I change my login information$/ do
visit edit_user_path(#user)
fill_in "Email", :with => "foo#example.com"
click_button "Update Login Information"
end
Then /^my account should be changed$/ do
#user.email.should == "foo#example.com"
end
And I fail the "Then" condition on both scenarios with this message:
# Scenario 1
expected: "John"
got: "Test1" (using ==) (RSpec::Expectations::ExpectationNotMetError)
# Scenario 1
expected: "foo#example.com"
got: "test2#example.com" (using ==) (RSpec::Expectations::ExpectationNotMetError)
So, in both cases the factory information is still present after submitting the form to update the user login or profile. However, if I test this in a real browser it works perfectly. So, why is this test failing???
Thanks for the help!
#user is just a variable which lives inside your cucumber code block. It will not be changed. What will be changed in the test is the database record. To check that it was changed indeed you have to visit some page where user name is displayed.
(Just as you do in your real life test)

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