Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Add "Wait for AJAX" post
- Loading branch information
Showing
5 changed files
with
183 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,44 @@ | |||
--- | |||
wordpress_id: RB-342 | |||
layout: post | |||
title: Waiting for AJAX in Capybara | |||
--- | |||
|
|||
In Spree recently, we've been using more and more of [Spree's API](http://guides.spreecommerce.com/api) for the Backend component. This means that we've introduced more AJAX-powered features into the backend, which has lead to some interesting test failures. | |||
|
|||
Some of these test failures are that the tests just aren't waiting long enough for an AJAX request to complete before checking for content on the page. Others are more ... bewildering: | |||
|
|||
``` | |||
F | |||
An error occurred in an after hook | |||
ActiveRecord::StatementInvalid: | |||
SQLite3::BusyException: | |||
database is locked: DELETE FROM "spree_activators"; | |||
occurred at ...lib/sqlite3/statement.rb:108:in `step' | |||
``` | |||
|
|||
This error happens when an AJAX request is still being processed by the server, but the test finishes and Database Cleaner attempts to wipe the database. The server has locked the database until it's done what it needs to do, and during that lock Database Cleaner attempts to wipe all the data and can't. | |||
|
|||
To fix this, we just needed to wait for all AJAX requests to complete. This means replacing `sleep` with magic numbers, like this: | |||
|
|||
``` | |||
sleep(2) | |||
``` | |||
|
|||
With this method: | |||
|
|||
``` | |||
def wait_for_ajax | |||
counter = 0 | |||
while page.execute_script("return $.active").to_i > 0 | |||
counter += 1 | |||
sleep(0.1) | |||
raise "AJAX request took longer than 5 seconds." if counter >= 50 | |||
end | |||
end | |||
``` | |||
|
|||
This code will call `$.active` which is jQuery-code for "how many `$.ajax` requests are still active?", and if that returns more than 0, then it will sleep for a moment, and check again. This code gives AJAX requests 5 seconds to wrap up before raising an exception and moving on. | |||
|
|||
Use this `wait_for_ajax` method when you need to wait for AJAX requests to finish in your tests to prevent weird, unpredictable JavaScript errors. | |||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,70 @@ | |||
<!DOCTYPE HTML> | |||
<html> | |||
<head> | |||
<title>Blog of Ryan Bigg - Waiting for AJAX in Capybara</title> | |||
<link href="http://feeds.feedburner.com/ryanbigg" rel="alternate" title="The Life of a Radar" type="application/atom+xml" /> | |||
<link rel='stylesheet' href='/css/style.css' media='screen'> | |||
<link rel='stylesheet' href='/css/mobile.css'> | |||
<body> | |||
<h1 align='center'><a href='http://ryanbigg.com'>The Life of a Radar</a></h1> | |||
<div id='page'> | |||
<article> | |||
<a href="/2013/07/waiting-for-ajax-in-capybara"><header>Waiting for AJAX in Capybara</header></a> | |||
<small>09 Jul 2013</small><br> | |||
<p>In Spree recently, we've been using more and more of <a href="http://guides.spreecommerce.com/api">Spree's API</a> for the Backend component. This means that we've introduced more AJAX-powered features into the backend, which has lead to some interesting test failures.</p> | |||
|
|||
<p>Some of these test failures are that the tests just aren't waiting long enough for an AJAX request to complete before checking for content on the page. Others are more ... bewildering:</p> | |||
<div class="highlight"><pre><code class="text language-text" data-lang="text">F | |||
An error occurred in an after hook | |||
ActiveRecord::StatementInvalid: | |||
SQLite3::BusyException: | |||
database is locked: DELETE FROM "spree_activators"; | |||
occurred at ...lib/sqlite3/statement.rb:108:in `step' | |||
</code></pre></div> | |||
<p>This error happens when an AJAX request is still being processed by the server, but the test finishes and Database Cleaner attempts to wipe the database. The server has locked the database until it's done what it needs to do, and during that lock Database Cleaner attempts to wipe all the data and can't.</p> | |||
|
|||
<p>To fix this, we just needed to wait for all AJAX requests to complete. This means replacing <code>sleep</code> with magic numbers, like this:</p> | |||
<div class="highlight"><pre><code class="text language-text" data-lang="text">sleep(2) | |||
</code></pre></div> | |||
<p>With this method:</p> | |||
<div class="highlight"><pre><code class="text language-text" data-lang="text">def wait_for_ajax | |||
counter = 0 | |||
while page.execute_script("return $.active").to_i > 0 | |||
counter += 1 | |||
sleep(0.1) | |||
raise "AJAX request took longer than 5 seconds." if counter >= 50 | |||
end | |||
end | |||
</code></pre></div> | |||
<p>This code will call <code>$.active</code> which is jQuery-code for "how many <code>$.ajax</code> requests are still active?", and if that returns more than 0, then it will sleep for a moment, and check again. This code gives AJAX requests 5 seconds to wrap up before raising an exception and moving on.</p> | |||
|
|||
<p>Use this <code>wait_for_ajax</code> method when you need to wait for AJAX requests to finish in your tests to prevent weird, unpredictable JavaScript errors.</p> | |||
|
|||
</article> | |||
</div> | |||
<div id='disqus_thread'></div> | |||
<script type="text/javascript"> | |||
var disqus_shortname = 'ryanbigg'; // required: replace example with your forum shortname | |||
|
|||
var disqus_identifier = 'RB-342 http://ryanbigg.com/?p=RB-342' | |||
var disqus_url = 'http://ryanbigg.com/2013/07/waiting-for-ajax-in-capybara'; | |||
</script> | |||
<script src='http://ryanbigg.disqus.com/embed.js'></script> | |||
|
|||
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> | |||
<a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a> | |||
<script type="text/javascript"> | |||
var _gauges = _gauges || []; | |||
(function() { | |||
var t = document.createElement('script'); | |||
t.type = 'text/javascript'; | |||
t.async = true; | |||
t.id = 'gauges-tracker'; | |||
t.setAttribute('data-site-id', '4e30f771f5a1f547c8000001'); | |||
t.src = '//secure.gaug.es/track.js'; | |||
var s = document.getElementsByTagName('script')[0]; | |||
s.parentNode.insertBefore(t, s); | |||
})(); | |||
</script> | |||
</body> | |||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.