When using capybara-webkit or poltergeist to test JavaScript behavior, I often find (or unfortunately, write) tests that look like this
it "saves the check box value when clicked", js: true do
visit '/somewhere'
page.should have_unchecked_field 'cool_check_box'
page.check 'cool_check_box'
visit '/somewhere'
page.should have_checked_field 'cool_check_box'
end
... where checking the checkbox makes some AJAX request that saves whatever state allows it to be checked after a quick reload.
That test seems guaranteed to flake, because if the AJAX request doesn't complete by the time the second visit '/somewhere'
happens, it will load with the checkbox in the wrong state.
Luckily on this page there's also a spinner that spins along while the checkbox request is completing, so I can amend the test like so
it "saves the check box value when clicked", js: true do
visit '/somewhere'
page.should have_unchecked_field 'cool_check_box'
page.check 'cool_check_box'
# Wait for checkbox ajax to complete
page.should have_css('.spinner:not(.active)')
visit '/somewhere'
page.should have_checked_field 'cool_check_box'
end
I'm still a little paranoid, though: if the page.check
line ran but didn't manage to set the spinner as active
before the page.should have_css
line, that line would succeed before the request even started.
Given that the JavaScript triggered by the checkbox sets the active
class, can I guarantee this test will never flake?
What you're talking about is the risk of the code that handles the check event running concurrently to the code which checks for .spinner:not(.active)
. This is not a risk since the Javascript on the page is single-threaded - you can guarantee that the check even will be handled first.