Capybara/Rspec not catching ActionController::UnpermittedParameters error - ruby-on-rails

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.

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

Rspec feature test: Cannot visit a path

I have rspec features tests that are all failing because i cannot visit the indicated path. They all seems to be stuck at the root path after logging in. A screenshot shows that the page still remains on the root path. The test steps work on the browser, which means that the routing is correct. Any ideas?
I am getting the below error message for the test:
Failure/Error: page.evaluate_script('jQuery.active').zero?
Extract of my feature spec test:
describe 'follow users' do
let!(:user) { FactoryGirl.create(:user) }
let!(:other_user) { FactoryGirl.create(:friend) }
describe "Managing received friend request", js: true do
let!(:request) { Friendship.create(user_id: other_user.id, friend_id: user.id, accepted: false) }
before do
login_as(user, :scope => :user)
visit followers_path
end
it 'friend request disappear once user clicks accept' do
click_on "Accept"
wait_for_ajax
expect(current_path).to eq(followers_path)
expect(page).to have_css(".pending-requests", text: "You have 0 pending friend requests")
expect(page).to_not have_css(".pending-requests", text: other_user.name)
expect(page).to_not have_link("Accept")
expect(page).to_not have_link("Decline")
end
end
end
The issue here is you're calling 'wait_for_ajax' either on a page that doesn't include jQuery or at a time when it hasn't yet been loaded. The solution is to stop using wait_for_ajax and instead use the Capybara expectations/matchers as designed. There are very very few cases where wait_for_ajax is actually needed and even then it's usually a sign of bad UI decisions (no indication to the user something is happening). You should also not be using the eq matcher with current_path and should be using the Capybara provided have_current_path matcher instead since it has waiting/retrying behavior like all of the Capybara provided matchers.
it 'friend request disappear once user clicks accept' do
click_on "Accept"
expect(page).to have_current_path(followers_path)
expect(page).to have_css(".pending-requests", text: "You have 0 pending friend requests")
expect(page).to_not have_css(".pending-requests", text: other_user.name)
expect(page).to_not have_link("Accept")
expect(page).to_not have_link("Decline")
end
If that doesn't work for you, then either the button click isn't actually triggering page changes (check your test log), your Capybara.default_max_wait_time isn't set high enough for the hardware you're testing on, your login_as statement isn't actually logging in the user (although then I would expect the click on the accept button to fail), or you have a bug in your app.
If it's that login_as isn't actually logging in then make sure the server being used to run the AUT is running in the same process as the tests, if you're using puma that means making sure in the output it doesn't say it' s running in clustered mode.
Try to this approach to wait for all the ajax requests to finish:
def wait_for_ajax
Timeout.timeout(Capybara.default_wait_time) do
active = page.evaluate_script('jQuery.active')
until active == 0
active = page.evaluate_script('jQuery.active')
end
end
end
Taken from: Wait for ajax with capybara 2.0

Rspec/Capybara not finding inputs

Capybara is acting really strange.
It wasn't finding any input fields at all, ID, name or label. So I changed the test to just check what was rendering and get a huge sass error.
feature "new users are not admin" do
scenario "user signs up" do
visit new_user_registration_path
#fill_in "Username", :with => "newuser"
#fill_in "Email", with: "newuser#example.com"
#fill_in "Password", with: "newuserpassword"
#fill_in "Password Confirmation", with: "newuserpassword"
#click_button "Sign up"
expect(page).to have_content("Sign Up")
end
end
And then this:
Failure/Error: expect(page).to have_content("Sign Up")
expected to find text "Sign Up" in "Sass::SyntaxError at /users/sign_up =================================== > Invalid CSS after \"\": expected selector, was \"===============...\" (in app/assets/stylesheets/application.css) app/views/layouts/application.html.erb, line 5 ---------------------------------------------- ``` ruby 1 2 3 4 > 5 true %> 6 true %> 7 8 9 10 ```
Which is actually a lot more, and seems to be the contents of the error page rails produces (better_errors), but only in tests, not when visiting the actual application. This is also only when the fill_in/click_button is commented out, otherwise it will be "could not find field 'username' etc.
The sass error has "============" in it which is part of how I split my css in sections with a large comment block e.g.
/*=============
Styles
==============*/
But this is all commented out. I don't see what it would cause a problem.
I have no idea what's going on. Any help is appreciated.
Fixed this, it was, for some reason, an un-commented section in bootstrap.css (that for some reason doesn't render an error except via tests).
Works as intended now

Capybara isn't checking a checkbox in rspec feature test

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]')

created data did not appear when testing

hye, I'm new to BDD testing and testing particularly. I'm using rspec, factory_girl_rails, selenium and capybara gem. I want to test for editing a data and save it like so :
it "edit consultant" do
# c = FactoryGirl.create(:consultant)
c = Consultant.create(
orgorcom: "xyz",
year_id: 8,
bidang: "IT & Networking",
project: "E-Sw",
professional_fee: "1000000",
role: "Database Architect",
user_id: 19,
nopkj: "075899 "
)
visit "/consultants?year=#{Time.now.year}"
string = "#consultant#{c.id}"
page.find(string).click_link('Edit')
fill_in "Organization / Company" , :with => c.orgorcom + "aaa"
fill_in "Field", :with => c.bidang + "aaa"
fill_in "Project" , :with => c.project + "aaa"
fill_in "Role", :with => c.role + "aaa"
fill_in "Professional fee", :with => c.professional_fee + 111
click_button "Save"
expect(page).to have_content "Data updated."
sleep 10
# c.destroy
# find('a[href="/consultants/6144/edit?year=2013"]').click
end
But the data I created did not appear & I get this message
1) the consultation edit consultant
Failure/Error: page.find(string).click_link('Edit')
Capybara::ElementNotFound:
Unable to find css "#consultant6157"
when I tried click on existing data like below, it passed.
page.find("#consultant6144").click_link('Edit')
I am able to print out the consultant id but still the record mysteriously did not appear before the test ends (which the db will rollback).
This is a known issue if you're using Selenium for browser testing, with transactional fixtures configured in your spec_helper. Selenium will run in a different thread and with a different database connection than the one being used by Rspec to create your database objects inside transactions, therefore the Selenium thread won't be able to see them.
For these kind of specs, you will need to not use transactional fixtures and use something like database_cleaner to create objects at the start of your specs and truncate/delete them afterwards.
Your problem doesn't seem related to FactoryGirl. The error message thrown by Capybara indicates that the object's id was properly concatenated into the string, but the corresponding CSS wasn't found in the page.
I would recommend you install the launchy gem by inserting this into your Gemfile:
group :development, :test do
gem 'launchy'
end
That will enable you to use the save_and_open_page method in your feature specs. Then insert this method right before the line that's provoking the error, like so:
# ...
save_and_open_page
page.find(string).click_link('Edit')
# ...
When save_and_open_page is called, your default browser will open at the same page. Then you can manually inspect the page's HTML and find out if it does, in fact, have the element you're looking for and, if it doesn't, why that happens.

Resources