Ember meet Capybara


It was a cordial hello. Capybara agreed to work nicely and Ember basically ignoring small talk and getting right down to business.

Shortly thereafter, when the real testing began, Capybara decided that it had enough and walked away. I was left standing there awkwardly with Ember trying to think of something to say. I managed “just get give us a moment” to which Ember did nothing. I can only assume it deferred processing until the next run loop tick.

I joined Capybara at the bar.

I was only one beer in when I solved the real problem. I didn’t need Capybara and Ember to be friends; I needed to have Capybara check the DOM / page after Ember did everything it needed to…


<!-- application.html.erb -->
<%= javascript_include_tag 'test' if Rails.env.test? %>
<!-- ... -->


// test.js
test = {
  ajaxRequests: {}
};

$(document).on('ajaxSend', function(e, xhr, options) {
  test.ajaxRequests[options.url] = true;
}).on('ajaxComplete', function(e, xhr, options) {
  delete test.ajaxRequests[options.url];
});


# helpers/spec_helper.rb
RSpec.configure do |config|
  config.include RequestHelper, :type => :feature
end
# ...


# helpers/request_helper.rb
module RequestHelper
  def self.included(base)
    base.send(:include, InstanceMethods)
  end

  module InstanceMethods
    ##
    # Wait up to 3 seconds for asynchronous action processing to complete
    def wait_for_async
      start_time = Time.now
      loop do
        break if page.evaluate_script('Object.keys(test.ajaxRequests).length == 0 && !Ember.run.hasScheduledTimers() && !Ember.run.currentRunLoop')
        raise "Waited too long for ajax requests to finish #{page.evaluate_script('JSON.stringify(test.ajaxRequests)')} - #{page.evaluate_script('!Ember.run.hasScheduledTimers()')} - #{page.evaluate_script('!Ember.run.currentRunLoop')}" if (Time.now - start_time) > 3
        sleep 0.1
      end
    end
  end
end