Capybara isn't checking a checkbox in rspec feature test - ruby-on-rails

I am attempting to create a feature test where a checkbox needs to be checked and for whatever reason Capybara is not checking the box.
I am using:
rspec: 3.0.4 and capybara: 2.4.1
When I print out a snapshot of the view, the checkbox isn't checked.
When I run the checkbox code in pry it returns the string "checked" but when I print a snapshot the checkbox still is not checked and my test does not pass. I'm curious if there is another way to get this checkbox to check.
Here is my current code so far:
Feature Test:
background do
discussion_group
#user2 = FactoryGirl.create(:user)
add_user_to_user_role_for_group(group, #user2)
admin_login
add_user_to_admin_role_for_group(group, #user)
visit groups_path
click_on 'Email Group'
end
scenario 'sending a valid email' do
valid_form
expect(page).to have_content group_email_success_notification
expect_count_of_deliveries_to_be 1
end
Macro:
def valid_form
fill_in 'group_email_subject', with: new_text
fill_in 'group_email_body', with: Faker::Lorem.words(200).join("\s")
check "group_email_#{#user2.id}_"
click_on "Send Email"
end
The output of my test is that I must have 1 user selected meaning that I don't have a user checked. When I run the check line in console here is what I get:
[10] check('group_email_10_')
=> "checked"
Any help is greatly appreciated.

I'd use:
page.check('insert #id, .class, or value')\
for example:
input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes"
page.check('puppy_gooddog') or page.check('puppy[gooddog]')

Related

Rspec System Test passes when run individually, fails when run with entire suite

I have the following test that passes when I run it in isolation:
require 'rails_helper'
RSpec.describe 'deleting a non-recurring user event', js: true do
let(:user) { create(:proofreader_user) }
let(:date) { Date.current.strftime('%Y-%m-%d') }
let(:date_time) { date + ' 00:00'}
it 'deletes the event' do
visit root_path
click_on "Login"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_on "Sign In"
visit calendar_path
expect(current_path).to eq(calendar_path)
expect(page).to have_css("#complete_registration:disabled")
expect(page).to_not have_css("td.fc-event-container")
find("td.fc-day[data-date='#{date}']").click
expect(page).to have_css("div#user-event-modal")
expect(page).to have_select('user_event[title]', :options => UserEvent.titles.keys)
expect(find('input', id: 'user_event_starting').value).to eq date_time
expect(find('input', id: 'user_event_ending').value).to eq date_time
page.execute_script("$('input#user_event_starting').val('#{date} 09:00')")
expect(find('input', id: 'user_event_starting').value).to eq date + ' 09:00'
page.execute_script("$('input#user_event_ending').val('#{date} 12:00')")
expect(find('input', id: 'user_event_ending').value).to eq date + ' 12:00'
click_on 'Save'
expect(page).to have_css("td.fc-event-container a.fc-day-grid-event")
expect(page).to have_css("span.fc-time", text: '9a - 12p')
expect(page).to have_css("span.fc-title", text: 'work')
find("span.fc-time", text: '9a - 12p').click
expect(page).to have_css("div#user-event-modal")
find("#del_one_event").click
within('.swal2-actions') { click_button('Yes') }
wait_for { page }.to_not have_css("div#user-event-modal")
expect(page).to_not have_css("td.fc-event-container")
expect(page).to_not have_css("span.fc-time", text: '10a - 14p')
end
end
However, when I run all of the tests I get the following error:
Failure/Error: within('.swal2-actions') { click_button('Yes') }
Capybara::ElementNotFound:
Unable to find visible css ".swal2-actions"
Why does this test fail when I run it with the other test and how can I fix it so it passes when I run all tests?
Cannot be sure without a lot more information. It would be best if you can create and publish a minimum complete verifiable example.
Based on the information given, I would guess that the test that fails when run with the other tests is not properly isolated. The other examples are changing the state of the application, causing this test to fail. So look at your before and after hooks and make sure you are setting config.use_transactional_fixtures = true in rails_helper.rb
If it is possible for there to be a delay between the time #del_one_event is clicked and .swal2-actions appears, then change
within('.swal2-actions') { click_button('Yes') }
to
find('.swal2-actions').click_button('Yes')
If none of those fix the problem, you might have an issue with browser caching, but that is even harder to debug.
This is hard to answer without seeing the other tests.
But I noticed some points that are worth checking out:
you are creating data by navigating the application, perhaps other tests create data, that prevent data in this test to be created
The command find("#del_one_event").click (one line before) just executes the click, but does not wait until anything happens. With all tests and more data in the db, it might take a while longer until .swal2-actions appears and is not yet present when you execute within('.swal2-actions') { click_button('Yes') }
Another way to get closer to the bug is by making screenshots and comparing them. Check out the gem capybara-screenshot

Rails + Capybara + Braintree—how to feature test BT's Hosted Fields?

TL;DR—How do I access fields within Braintree's Hosted Fields' iframes?
I want to test a UX flow of paying a donation through Braintree. This is my code so far:
require "rails_helper"
RSpec.feature "Donation Module", type: :feature do
scenario "Public visitor creates a new donation" do
#load page
website = create(:website)
Capybara.current_session.driver.header 'Referer', website.website
visit "/donate?t=#{website.public_token}&frame=1"
#verify page loaded
expect(page).not_to have_content("Are you sure you're installing this on the correct website?")
#fill page 1
find("input[value='20']").click
#go to page 2
find("#credit-details").click
#verify page 2 content is loaded
expect(find(".total-cost-text")).to be_visible
#fill page 2
fill_in 'First Name', with: 'Leeroy'
fill_in 'Last Name', with: 'Jenkins'
fill_in 'Email for receipt', with: 'new_donor#email.com'
within_frame('#braintree-hosted-field-number') do
fill_in '#credit-card-number', with: '4111-1111-1111-1111'
end
within_frame('#braintree-hosted-field-expirationDate') do
fill_in '#expiration', with: '09/19'
end
within_frame('#braintree-hosted-field-cvv') do
fill_in '#cvv', with: '123'
end
find('Make payment').click
# expect to make a new user, new donation, new receipt, email receipt
end
end
Currently, it's breaking at the first within_frame saying Capybara::NotSupportedByDriverError:
Capybara::Driver::Base#within_frame
How do I access fields inside BT's iframes?
Well, I am writing here not exactly an answer to this question, but rather corrections to the question, as I was in the similar situation and was facing similar errors such as Selenium::WebDriver::Error::NoSuchFrameError: Unable to locate frame: #braintree-hosted-field-number and Test::Unit::Capybara::ElementNotFound: Unable to find field "#credit-card-number".
The within_frame should have the following format (the #-sign for ID should be removed from both):
within_frame('braintree-hosted-field-number') do
fill_in 'credit-card-number', :with => number
end
And in order to use the selenium driver in Test::Unit, I used the following helper:
def js
Capybara.current_driver = Capybara.javascript_driver
yield
Capybara.current_driver = Capybara.use_default_driver
end
And then wrapped my tests in it:
class SomeTest < ActionDispatch::IntegrationTest
test "should ..." do
js do
within_frame('braintree-hosted-field-number') do
fill_in 'credit-card-number', :with => number
end
# ...
end
end
Hopefully, someone will find it useful while using Unit Tests.
Seems like you're using the rack_test driver? That doesn't support JS or frames so braintree isn't going to work with that. You need to switch to one of the real browser drivers like selenium, capybara-webkit, or poltergeist.

Capybara/Rspec not catching ActionController::UnpermittedParameters error

I was in the processing in adding a field to an ActiveRecord model and the corresponding view. Before I started, I had a full green test run. I started with writing the following test:
scenario "with all correct info" do
create_vendor "vendor.email#example.com", "vendor_passowrd"
create_consumer "consumer.email#example.com", "password"
sign_in_with "consumer.email#example.com", "password"
click_link "New Order"
select 'vendor.email#example.com', from: "Vendor"
fill_in "Order text", with: "my normal order"
click_button "Submit"
expect(page).to have_content "my normal order"
end
I added the field to the model using the proper rails migration and the route entry.
I would have expected the test to fail with a ActionController::UnpermittedParameters because I have not yet updated the controller. However, this is the failure I am getting:
"Failure/Error: expect(page).to have_content "my normal order"
When I test in the browser, I do get the ActionController::UnpermittedParameters, but not in the automated test.
My question is should the test get the ActionController::UnpermittedParameters error?
Capybara simulates a web browser request, so it will get back an error page from Rails. The UnpermittedParameters error will not propagate up to the spec code itself.
This sounds like it's working correctly.

How to test a form Reset button

Googling around and not find a working solution...
Using Rails 3.2.11, RSpec 2.12.2 Capybara 2.0.2 I'm trying to test the "reset button" on a form (which works fine when testing with a browser)
I tried this code
scenario "Fill form then reset it" do
visit contact_path
fill_in 'message_name', :with => 'abc'
fill_in 'message_email', :with => 'abc'
fill_in 'message_subject', :with => 'abc'
click_on 'Reset form'
expect(page).to find_field('message_name').value.should == ''
end
The test fails with this error
expected: ""
got: "abc"
(compared using ==)
It seems the fields are not resetted at all.. (but in a browser they are)
What am I missing ? Something new in this version of Capybara or Rspec ?
Thanks for your help
My fault,
This type of feature/scenario requires js driver.
Selenium is included in the capybara gem but I forgot to activate it in my feature. To have it to work I just had to change the line
scenario "Fill form then reset it" do
to this one
scenario "Fill form then reset it", :js => true do
according the doc https://github.com/jnicklas/capybara#using-capybara-with-rspec. Now all works fine...
Hope it can help someone else ...
Cheers

Capybara detecting CSS ID model ID with find('')

I am currently working on an intranet for work which will include creating invoices.
While writing tests I am using Rspec and Capybara for testing and while running a request test I want to create an invoice and add a couple of items to make sure the vat is calculated correctly.
However I seem to be having an issue where Capybara finds the first #item_price and tries to match that instead of the newly created item.
Below is some of the code in my request test.
...
...
# Laptop for 369.96 inc vat
click_link "Add Item"
fill_in "Quantity", :with => 1
fill_in "Price", :with => 369.96
fill_in "Description", :with => "laptop for 369"
click_button "Create Item"
page.should have_content("Item was successfully created")
find('#item_quantity').should have_content(1)
find('#item_price').should have_content(369.96)
find('#item_description').should have_content("laptop for 369")
find('#item_total').should have_content(369.96)
find('#invoice_subtotal').should have_content(308.30)
find('#invoice_vat').should have_content(61.66)
find('#invoice_total').should have_content(369.96)
# Laptop for 337.53 inc vat
click_link "Add Item"
fill_in "Quantity", :with => 1
fill_in "Price", :with => 337.53
fill_in "Description", :with => "laptop for 337"
click_button "Create Item"
page.should have_content("Item was successfully created")
find('#item_quantity').should have_content(1)
### the offending code below
find('#item_price').should have_content(337.53)
###
find('#item_description').should have_content("laptop for 337")
...
...
I would like to be able to add #item_price_2 where 2 would be the item ID. When doing this and changing find('#item_price').should have_content(337.53) to find('#item_price_#{invoice.id}').should have_content(337.53) I get the exception:
Nokogiri::CSS::SyntaxError:
unexpected '#' after '[#<Nokogiri::CSS::Node:0x007f991889f270 #type=:CONDITIONAL_SELECTOR, #value=[#<Nokogiri::CSS::Node:0x007f991889f3d8 #type=:ELEMENT_NAME, #value=["*"]>, #<Nokogiri::CSS::Node:0x007f991889f9c8 #type=:ID, #value=["#item_price_"]>]>]'
Also changing it to double quotes "#item_price_{invoice.id}" gives me this exception:
undefined local variable or methodinvoice' for #
I'm guessing this is because I'm not using FactoryGirl so invoice isn't set as a method yet. I'm not using FactoryGirl in this occasion because I would like to test how the user would interact with the invoice and items forms.
What would be the best way to fix this problem? Is there a better way of doing what I am trying to do?
Many thanks in advance!
Your guess about invoice not being set yet is correct. After your form is submitted you could set it:
invoice = Invoice.last
Then your specs should pass.

Resources