Why does adding sleep 1 in an after hook cause this Rspec/Capybara test to pass?
I suspect that it's possible in your application for the comment to disappear from the page (which is the last thing you're asserting) before it's deleted from the database. That means that the test can clean up before the deletion happens. If this is the case you can fix it by waiting for the actual deletion to happen at the end of the test. I have this method around (a reimplementation of a method that was removed from Capybara 2 but is still sometimes necessary)
def wait_until(delay = 1)
seconds_waited = 0
while ! yield && seconds_waited < Capybara.default_wait_time
sleep delay
seconds_waited += 1
end
raise "Waited for #{Capybara.default_wait_time} seconds but condition did not become true" unless yield
end
so I can do
wait_until { Comment.count == 0 }
in tests.
Another approach is to add Rack middleware that blocks requests made after the test ends. This approach is described in detail here: http://www.salsify.com/blog/tearing-capybara-ajax-tests I saw it do a very good job of addressing data leakage in a good-sized suite of RSpec feature specs.
Why is this capybara test failing when running programmatically, but passing when done manually?
When you say "fails to click", I'm assuming you don't mean you're getting an error from the page.find("svg", class: "fa-times").click(wait: 5)
but rather that the line is proceeding just fine and your expect(page).to have_css(".fa-bars")
is what's actually failing.
Given that, your description tells me that Capybara is actually clicking just fine, but it's happening before the menu is ready to interpret the click as meaning to close. When you add a binding.pry you're giving the menu time to finish opening. The thing you need to understand about passing the wait
parameter is that it sets the maximum amount of time Capybara will wait for the element to exist. If the element exists before that time Capybara will move on, so setting wait: 10
when wait: 5
didn't error on that line will make no difference (condition was met already - allowing it to wait longer is meaningless). You can confirm this by just putting a sleep(2)
before the find/click line to delay the find and click long enough for the menu to open before the click happens to close it. The proper fix for your tests is to either disable animation in your testing environment (so the menu opens instantly) or add an extra expectation for some state of the menu that indicates it is actually fully open and ready to receive a click that closes it.
Record Deletion testing failure using Capybara with Selenium
First, best practices is to have all of your scenarios be independent so they can be run in any order. You have opted to ignore best practices here and made scenarios order dependent - hopefully you have a really good reason for doing that.
As for the sleep being necessary, that is (as your surmised) because browser actions occur asynchronously which means that accepting the confirm returns as soon as the confirm is accepted. It will then take a little time for the deletion request to be processed by your server and the Post.count
will be checked before the deletion has actually occurred. To fix that you should be checking for whatever visual change indicates the deletion has occurred. In your case that looks to be the text "Post was successfully destroyed.", so move that inside the Post.count expectation in order to synchronize your test with the application.
expect{
within 'table' do
accept_confirm do
find_link(class: 'tester').click
end
end
expect(page).to have_content("Post was successfully destroyed.")
}.to change {Post.count}.by(-1)
Why Capypara + Rspect tests still pass even though I delete application.js file?
Try with
rake assets:clobber
This will remove compiled assets and clean them.
Why would binding.pry cause Rspec Selenium test to fail?
When testing apps with JS capable drivers the app is run in a different thread than the tests. This means when you add binding.pry to the controller code, it gets paused but the test thread may continue on, finishes/fails the test and then database cleaner is run to clean up your objects. If you're relatively quick in your pry session you'll find your objects ( within the sleep(5) timeframe ) - otherwise they may be cleaned up and gone. Also it's telling you the error is occurring in an after hook, but you don't show any after hooks, only before, in your code???
Note: using sleep()
in a test with Capybara is generally frowned upon since it means your tests will take longer than necessary. Instead you should be checking a visual change on the page that indicates the action has completed - something like
expect(page).to have_text('Order updated')
or
expect(page).to have_current_path('/success')
etc. depending on exactly what your app does or how it shows that the update was successful
Capybara test doesn't pass with database cleaner, must be run twice without database_cleaner to pass
There is no visit
shown in the test, which means you've visited the page before the questions are created and therefore the info expected is not shown on the page. The data would exist from the first run on the second run if you don't clear the DB which explains why it passes second time around. You should always visit the page after creating the test data.
Additionally as I mentioned in the comments you probably want to fix (remove if using Rails 5.1+) your DatabaseCleaner config and the use of trigger
is a really bad idea in tests since it can do things a user never could.
Related Topics
Convert To/From Datetime and Time in Ruby
How to Display Ruby on Rails Form Validation Error Messages One At a Time
Why Does Ruby'S 'Gets' Includes the Closing Newline
How to Hide Password Input from Terminal in Ruby Script
Match a String Against Multiple Patterns
Ruby: How to Copy a Variable Without Pointing to the Same Object
Rails Assets:Precompile Yarn Executable Was Not Detected in the System
Rails Catch-All/Globbing Routes
What Does a ||= Mean in Ruby Language
How to Switch to Ruby 1.9.3 Installed Using Homebrew
Ruby - Net/Http - Following Redirects
Why Are Symbols in Ruby Not Thought of as a Type of Variable
Why Are Methods in Ruby Documentation Preceded by a Hash Sign
Ruby Run Shell Command in a Specific Directory
Flutter Pod Install Problem - Undefined Method 'Each_Child' For #≪Dir:0X00007Fa6F7E2Ec80≫