input date into form using factory girl and capybara - ruby-on-rails

I have a Group model that I am testing using Request specs with Capybara and generating the data using Factory Girl
In my groups.rb factory...
FactoryGirl.define do
factory :group do
sequence :name do |n|
"Group#{n}"
end
expiry Date.today + 2.weeks
end
end
And use this in my groups_spec.rb...
describe "Groups" do
describe "GET /groups" do
it "an admin user can create a new group" do
user = Factory.create(:user, :is_admin => true )
group = Factory.build(:group)
visit root_url
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
click_button "Login"
click_link "Groups"
click_link "New Group"
fill_in "Name", :with => group.name
# need to change the below to use the Factory eg select Date.new(group.expiry)
select "2014", :from => "group_expiry_1i"
select "June", :from => "group_expiry_2i"
select "1", :from => "group_expiry_3i"
click_button "Create Group"
page.should have_content("Group was successfully created.")
page.should have_content(group.name)
end
end
end
So you see that this is not a good way to do the test as I'm not using the factory generated expiry. Does anyone know how to input the expiry date into the form properly?

This is just off the cuff without testing in Capybara, but I'd try:
select group.expiry.year.to_s, :from => "group_expiry_1i"
select Date::MONTHNAMES[group.expiry.month], :from => "group_expiry_2i"
select group.expiry.date.to_s, :from => "group_expiry_3i"
As long as those values actually exist in the dropdown it should select them correctly.

You can also use select_date:
select_date('31/12/2014', :from => 'Expiry')

Related

Capybara: ElementNotFound: unable to find field name on a multi-part form

I'm having difficulty isolating the problem with my attempt at this feature spec.
require 'spec_helper'
feature 'Add Employee', type: :feature do
scenario 'with valid information' do
# visit setup_add_employees_path
visit '/setup/add_employees'
# save_and_open_page
fill_in "First Name", with: 'Test'
fill_in 'Last Name', with: 'Employee'
fill_in 'Email', with: 'testemployee#example.com'
# fill_in , with: 'testemployee#example.com'
# expect(page).to find_field('First Name').value
end
end
This is step 2 of a multi-part form, I have the first step's spec written and its working fine. However in this spec, using fill_in for the form fields does not.
Here are my associated files for this spec:
# add_employees.html.haml
= render "partials/nav_left_setup"
- model_class = Invitation.new.class
#alert_message
.page-header
%h1 Invite Your Employees
%p.lead Now it's time to add your employees to HuddleHR. We'll send an email to your employees when setup is complete. Don't worry, the email will include instructions on how to setup their account and update their personal information.
%p.lead
If you like, you can import your employee list from an
= succeed "." do
%a#show_import_form{ href: "#" } Excel file
= render "partials/setup_import_employees"
= nested_form_for #account, :html => {:class => "invitation"} do |f|
%br/
= f.fields_for :invitations, #invitations do |invitation_form|
= invitation_form.hidden_field :product_id, :value => "1"
= invitation_form.text_field :first_name, :class => "input-small", :placeholder => "First Name", :required => :true
= invitation_form.text_field :last_name, :class => "input-small", :placeholder => "Last Name", :required => :true
%span= invitation_form.email_field :email, :class => "text_field", :placeholder => "Email Address", :required => :true
= invitation_form.collection_select :team_id, #teams, :id, :name
- if invitation_form.object.new_record?
= hidden_field_tag :invitaion_new_record, "new record"
= link_to "Delete", "javascript:void(0);", :class => "btn btn-danger delete_invitation_row_button", :style => "margin-bottom: 12px"
- else
= link_to "Delete", invitation_form.object, :confirm => "Are you sure?", :method => :delete, :remote => true, :class => "btn btn-danger btn-delete destroy_duplicate_nested_form", :style => "margin-bottom: 12px"
= f.link_to_add raw("<i class=\"icon-plus-sign icon-white\"></i> Add An Employee"), :invitations, class: "btn btn-success"
.form-actions
= link_to "Back", #optional_step.prv_link, class: "btn"
= f.submit "Save & Continue", :class => "btn btn-primary"
= link_to "Skip This Step", #optional_step.next_link, class: "btn" if #optional_step.optional == true
# The accounts_controller's create method
def create # TODO we need to document this...
#account = Account.new(params[:account])
if #account.save
# Send the account setup email to the account creator
UserMailer.account_setup_email(current_user).deliver
current_user.add_role!(User::ROLES[0]) # asigning the role roster_admin
current_user.add_role!(User::ROLES[3]) # asigning the role employee
# Sign the account up for Roster and create some inital records like:
# Register Roster as a product the account has subscribed to.
AccountProduct.create!(:account_id => #account.id, :product_id => Product.where(:name => "Roster").first.id)
# Create the account holder's profile
Profile.create!(:user_id => current_user.id, :first_name => #account.account_owner_first_name_input, :last_name => #account.account_owner_last_name_input)
# Create their first default team so they have a place to keep people
Team.create!(name: "Example Team", description: "This is just a placeholder team. You can rename or delete it.", account_id: #account.id, manager_id: current_user.id)
# Create their first job description so they have a place to keep people
JobDescription.create!(title: "Example Job Description", description: "This is just a placeholder job description. You can rename or delete it.", account_id: #account.id)
# Create a first post for the company so they have something on their homepage...
Post.create!(title: "Welcome to HuddleHR", body: "The simple and easy way to manage employee information in the cloud. You can invite employees, setup your org chart, fill out your profile and more.", account_id: #account.id, author_id: current_user.id, scope_id: "1")
# Create the initial employment record
Employment.create!(:user_id => current_user.id, :team_id => Team.find_by_account_id(#account.id).id, :effective_date => Date.today, :comment => "Initial creation of HuddleHR account owner employment record.")
# Set the User.account_id to the created account.id
current_user.update_attributes!(:account_id => #account.id)
setup_steps = #account.product_setup_steps
current_step = ProductSetupStep.where("link =? AND product_id =?", URI(request.referer).path, 1).first # Getting the current step
if current_step
setup_steps << ProductSetupStep.where("link =? AND product_id =?", URI(request.referer).path, 1).first
setup_steps << ProductSetupStep.where("step_number =? AND product_id =?", 1, 1).first
redirect_to current_step.next_link, :notice => 'Your account was successfully created.' if current_step.next_link.present?
redirect_to account_path(#account), :notice => 'Your account was successfully created.' unless current_step.next_link.present?
else
redirect_to account_path(#account), :notice => 'Your account was successfully created.'
end
else
render :action => "new"
end
end
# the imacros file, which I'm told is similar to selenium
' Add Employee
TAG POS=1 TYPE=A ATTR=TXT:Add<SP>An<SP>Employee
TAG POS=1 TYPE=INPUT:TEXT FORM=ID:edit_account_* ATTR=ID:account_invitations_attributes_*_first_name CONTENT=Test
TAG POS=1 TYPE=INPUT:TEXT FORM=ID:edit_account_* ATTR=ID:account_invitations_attributes_*_last_name CONTENT=Employee{{!VAR1}}
TAG POS=1 TYPE=INPUT:EMAIL FORM=ID:edit_account_* ATTR=ID:account_invitations_attributes_*_email CONTENT=testemployee{{!VAR1}}#huddlehr.com
TAG POS=1 TYPE=INPUT:SUBMIT FORM=ID:edit_account_* ATTR=NAME:commit
TAG POS=1 TYPE=INPUT:SUBMIT FORM=ID:edit_account_* ATTR=NAME:commit
TAG POS=1 TYPE=A ATTR=TXT:Send<SP>Invitations<SP>To<SP>These<SP>Employees
TAG POS=1 TYPE=A ATTR=TXT:Finish<SP>Setup
TAG POS=1 TYPE=A ATTR=TXT:Finish
If I had to guess, I would say that the problem lies in my not having a background block to mimic things that would be loaded by step 2 of this form. On step 1 the background block contains a sign_up_with(email, pass). So if I am correct about the background being a reason why fill_in cannot find my form_field id names, what would I need to setup in the step2 feature spec's background block?
BTW, step 1 is a spec named create account and looks like this:
# create_account_spec.rb
require 'spec_helper'
# require 'ruby-debug'
feature 'Create Account', type: :feature do
background do
sign_up_with Faker::Internet.email, '1Password'
end
scenario 'Fill form data' do
# visit '/setup'
visit new_account_path
fill_in 'First Name', with: 'Test'
fill_in 'Last Name', with: 'Owner'
fill_in 'Company Name', with: 'Company'
fill_in :account_addresses_attributes_0_line_one, with: '133 Main St'
fill_in :account_addresses_attributes_0_city, with: 'Columbia'
select 'SC', from: 'State'
fill_in :account_addresses_attributes_0_zip, with: '11111'
fill_in :account_phone_numbers_attributes_0_number, with: '(111) 111-11111'
select '(GMT-05:00) Eastern Time (US & Canada)', from: 'Time zone'
click_button('Save & Continue')
end
end
I've read over the following related resources to better understand Capybara and integration testing:
Undefined method `within' using capybara and rspec
Capybara's README on github
Capybara::ElementNotFound, but it is there
rspec Test Result Capybara::ElementNotFound
Capybara::ElementNotFound: Error
How to solve a Capybara::ElementNotFound Error
Ok, so the issue as I understand it was that I did not properly setup my background to mimic the place in the site where this part2 of the multi-form's integration spec picks up. I solved this by using FactoryGirl to create a user and then used Capybara's fill_in's with user.email && user.password instead of using faker as you see above.
Here is a look at my spec as of now:
# spec/features/add_employee_spec.rb
require 'spec_helper'
feature 'Add Employee', type: :feature do
background do
user = create :user
visit user_session_path
fill_in 'Email', with: user.email
fill_in 'Password', with: user.password
click_button 'Sign In'
expect(page).to have_content('Setup An Account')
end
scenario 'clicks Add A New Employee and fills out the form' do
account = create :account
save_and_open_page
visit setup_add_employees_path
fill_in 'first_name', with: 'Test'
fill_in 'Last Name', with: 'Employee'
fill_in 'Email', with: 'testemployee#example.com'
end
end
When using Faker to generate different usernames for a signup, I was improperly setting up the 'background' block as if I was a user looking to register for the first time.
If there is anything else I'm overlooking, or perhapse some additional tips on improving my integration specs moving forward, I look forward to your comments.

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")?

Testing signup form with rspec, capybara, and stripe

I'm super new to testing, so I'm not really sure what I should be debugging here.
That said, I have two different user types: Authors and Readers, subclassed on Users.
They can both sign up fine in my app, and the tests for Readers works without any problems.
The signup form for Authors includes a stripe payment form - and makes a remote call to Stripe's API before submitting the form.
Here is what the test looks like:
require 'spec_helper'
feature 'Author sign up' do
scenario 'author can see signup form' do
visit root_path
expect(page).to have_css 'form#new_author'
end
scenario 'user signs up and is logged in' do
visit root_path
fill_in 'author[email]', :with => 'author#example.com'
fill_in 'author[password]', :with => '123456'
fill_in 'author[password_confirmation]', :with => '123456'
fill_in 'author[name]', :with => 'joe shmoe'
fill_in 'author[zipcode]', :with => '02021'
fill_in 'card_number', :with => '4242424242424242'
fill_in 'card_code', :with => '123'
select "1 - January", :from => 'card_month'
select "2014", :from => 'card_year'
find('.author_signup_button').click
expect(page).to have_css '.author_menu'
end
end
The only difference between this test and the Reader test are the credit card forms.
The controller which handles this account creation looks like this:
def create
#author = Author.new(params[:author])
if #author.save_with_payment
sign_in #author, :event => :authentication
redirect_to root_path, :notice => "Thanks for signing up!"
else
render :nothing => true
end
end
If I don't have the else in here, the test fails sooner, saying its missing templates. Which means its not passing the "save_with_payment" method, which supports the idea that the form never hits stripe.
The error simply says:
**Failure/Error: expect(page).to have_css '.author_menu'
expected css ".author_menu' to return something**
This worked before I integrated with stripe - so I'm convinced it has to do with the ajax call.
Is there something I should be doing to support ajax?
The answer, was to use :js => true in the test:
scenario 'user signs up and is logged in', :js => true do
This forces the test to run with selenium, and uses the browser.

RSpec-rails-capybara - different failures with :js => true and without

I'm building a setup screen for billing of individuals. The controller/views are in the Admin namespace.
When run the first test without :js => true I get one failure, which I assume is down to the fact that the link does not work as its a helper which uses a js script to build a nested set of fields (Based on Railscasts Single form, multiple tables - Nested Attributes).
Failures:
1) Patient Setup create patient bill heading - with extended details -with valid data
Failure/Error: fill_in "Extended Bill Heading", :with => 'Regular Registration'
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Extended Bill Heading' found
# (eval):2:in `fill_in'
# ./spec/requests/admin/patient_setup_pages_spec.rb:52:in `block (4 levels) in <top (required)>'
Finished in 0.83047 seconds
3 examples, 1 failure, 2 pending
But when I use :js = true, I'm getting a failure which appears to be from the login with Invalid user/password flashing up on the screen when running.
Failures:
1) Patient Setup create patient bill heading - with extended details -with valid data
Failure/Error: click_link 'System'
Capybara::ElementNotFound:
no link with title, id or text 'System' found
# (eval):2:in `click_link'
# ./spec/requests/admin/patient_setup_pages_spec.rb:22:in `block (2 levels) in <top (required)>'
Finished in 6.33 seconds
3 examples, 1 failure, 2 pending
Here is the code that backs all this up.
spec/requests/admin/patient_setup_spec.rb
require 'spec_helper'
feature 'Patient Setup' do
let!(:ci_user) { FactoryGirl.create(:user,
name: "configuration engineer",
password: "password",
password_confirmation: "password"
) }
let!(:admin_role) { FactoryGirl.create(:admin_role) }
let!(:assignment) { FactoryGirl.create(:assignment,
:role => admin_role,
:user => ci_user
) }
before do
visit login_path
fill_in "Name", with: "configuration engineer"
fill_in "Password", with: "password"
click_button "Login"
save_and_open_page
click_link 'System'
click_link 'Patient Setup'
end
describe "create patient bill heading" do
before do
click_link 'New Bill Heading'
fill_in 'Bill heading', :with => 'Consultation'
fill_in 'Abbreviation', :with => "CON"
end
context "- no extended details" do
pending
scenario "- with valid data" do
pending
click_button 'Create Patient bill heading'
page.should have_content('Patient Bill Heading created.')
end
end
context "- with extended details", :js => true do #(without :js => true 1st error)
before do
# save_and_open_page
click_link "Extended Bill Heading"
# save_and_open_page
end
scenario "-with valid data" do
save_and_open_page
fill_in "Extended Bill Heading", :with => 'Regular Registration'
end
end
end
end
Here is my factory setup.
spec/factories.rb
FactoryGirl.define do
# Users, Roles
factory :user do
name "Joesephine Bloggs"
password "testmenow"
password_confirmation "testmenow"
end
factory :admin, :class => User do
sequence(:name) { |n| "Administrator-#{n}" }
password "adminiam"
password_confirmation "adminiam"
after(:create) do |user|
FactoryGirl.create(:assignment, :role => FactoryGirl.create(:admin_role), :user => user )
end
end
factory :role do
description { "Clerical-#{rand(99)}" }
factory :admin_role do
description "Admin"
end
end
factory :assignment do
user
role
end
# Patients Module
factory :patient_bill_heading do
sequence(:bill_heading) { |n| "bill-heading-#{n}" }
sequence(:abbreviation) { |n| "abbreviation-#{n}" }
factory :delete_patient_bill_heading, :class => PatientBillHeading do
bill_heading :bill_heading
abbreviation :abbreviation
end
end
end
Here is the link in my view to call the helper that generates the nested attribute fields.
<p>
<%= link_to_add_fields "Extended Bill Heading", f, :patient_extended_bill_headings %>
</p>
And here is the helper.
helpers/application_helper.rb
def link_to_add_fields(name, f, association, options={})
defaults = {
:partial_name => nil
}
options = defaults.merge(options)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
if options[:partial_name].nil?
render(association.to_s.singularize + "_fields", f: builder)
else
render(options[:partial_name], f: builder)
end
end
link_to("#{name} <i class='icon-plus icon-white'></i>".html_safe,
'#',
class: "btn btn-success add_fields",
data: {id: id, fields: fields.gsub("\n", "")}
)
end
I'm trying to improve my RSpec testing knowledge, as I have successfully built this working in my application after an hour trying to figure out why I was getting test failures. So in the app it works, but I want to understand how to make my test pass.
Is my assertion that one error is due to using js to create the link, and capybara is not running it as I don't use the :js => true option?
Can anybody see what I'm doing wrong when using the :js => true option?
You probably have config.use_transactional_fixtures = true in your spec_helper.rb. It doesn't work with Capybara javascript specs because the server and the browser client run on separate threads. Due to the fact that database transactions on the server are not visible to the client, the client has no clue about the user you created in the let!(), therefore the user cannot login to the system.
You need to turn off transactional fixtures and clean your database before/after each run (consider the gem database_cleaner) for your js specs.
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.clean_with :truncation
end
config.before(:each) do
if example.metadata[:js]
DatabaseCleaner.strategy = :truncation
else
DatabaseCleaner.strategy = :transaction
end
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
The above code snippet is taken from the contact manager app readme and slightly modified

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?

Resources