Rails 4 Rspec expects {}. Change registration even though the test is working as planned
I am working with Rails 4, RSpec, Capybara and selenium. I ran into an oddity that I can't seem to solve after trying it on the last day or so. I have a fairly simple query specification because the test doesn't register the model change. Here's my spec:
describe "manage pages", :js => true do
before :each do
@fake_page = FactoryGirl.create(:page_with_block, name: "Foobar")
@fake_page2 = FactoryGirl.create(:page_with_block, name: "sdfdf")
visit admin_pages_path
save_page
end
it "should delete an image when link is clicked" do
expect {
within "#page_#{@fake_page.id}" do
click_link 'Destroy'
end
wait = Selenium::WebDriver::Wait.new ignore: Selenium::WebDriver::Error::NoAlertPresentError
alert = wait.until { page.driver.browser.switch_to.alert }
alert.accept
}.to change(Page, :count).by(-1)
expect(page).to have_content "Listing Pages"
expect(page).not_to have_content "Foobar"
save_page
end
end
As you can see, this is the main kill click and validation js alert test. The problem is, it always fails:
......F
Failures:
1) Pages manage pages should delete an image when link is clicked
Failure/Error: expect {
expected #count to have changed by -1, but was changed by 0
# ./spec/requests/admin/pages_spec.rb:116:in `block (3 levels) in <top (required)>'
Finished in 11.74 seconds (files took 3.81 seconds to load)
7 examples, 1 failure
According to the save_page files that I placed in my application earlier and another at the end of the test, when I comment out "wait", everything works as intended, fake pages are created in before the test passes and clicks, destroys and receives a warning. the page is destroyed and the index page is reloaded without it on the content. What I don't understand is why the Change helper doesn't see that it is, in fact, working.
I've read that it may have something to do with my rails_helper.rb file, but everything I've been looking for has a similar, if not precise, setup:
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.infer_spec_type_from_file_location!
config.include Capybara::DSL
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.after(:suite) do
FileUtils.rm_rf(Dir["#{Rails.root}/public/test/system/"])
end
end
Since I can't find any other event of this on google or this site, I should just be doing something wrong. Can anyone point me to a flaw in my code? Thank you in advance.
source to share
I am struggling with the same problem. You expect the logic to be flawed. I've used this approach and it worked well for me.
Copied from this article - basically you need to create a helper:
# spec/support/wait_for_ajax.rb
module WaitForAjax
def wait_for_ajax
Timeout.timeout(Capybara.default_max_wait_time) do
loop until finished_all_ajax_requests?
end
end
def finished_all_ajax_requests?
page.evaluate_script('jQuery.active').zero?
end
end
RSpec.configure do |config|
config.include WaitForAjax, type: :feature
end
Include all support files automatically in spec_helper.rb
spec/support/**/*.rb in our spec_helper.rb
or do it manually like me:
#rails_helper.rb
require_relative 'support/wait_for_ajax'
Now my test is passing!
require 'rails_helper'
RSpec.feature "Call Me Back contact front feature spec >", :type => :feature, js: true do
feature 'valid form' do
scenario "with name and phone" do
visit '/'
execute_script '$("#call-popup").fadeIn(300)'
fill_in 'call_me_back_request_name', with: 'Clark Kent'
fill_in 'call_me_back_request_phone', with: '1234445566'
within '#new_call_me_back_request' do
expect{
find("input[type='submit']").click
wait_for_ajax #<- the magic is here!
}.to change(Request, :count).by(1)
end
end
end
source to share