Skip to content

Instantly share code, notes, and snippets.

@tonyhb
Created September 18, 2014 20:48
Show Gist options
  • Save tonyhb/dfd8da6522b93a45e377 to your computer and use it in GitHub Desktop.
Save tonyhb/dfd8da6522b93a45e377 to your computer and use it in GitHub Desktop.
RackRequestCounter
# spec/support/click.rb
module Capybara
module Node
class Element < Base
# Override the default implementation of click so that whenever we click
# on something, we also wait for any ajax requests to finish.
def click
synchronize { base.click }
wait_for_ajax
end
end
end
end
# lib/rack_request_counter.rb
#
# Source, which use jruby and atomic:
# http://blog.salsify.com/engineering/tearing-capybara-ajax-tests
# https://gist.githubusercontent.com/jturkel/9317269/raw/rack_request_blocker.rb
# Rack middleware that keeps track of the number of active requests and can block new requests.
class RackRequestCounter
@@num_active_requests = 0
@@nil_requests_at = Time.now
def self.reset
@@nil_requests_at = Time.now
@@num_active_requests = 0
end
# Returns the number of requests the server is currently processing.
def self.num_active_requests
@@num_active_requests
end
def self.nil_requests_at
@@nil_requests_at
end
# 503 status.
def initialize(app)
@app = app
end
def call(env)
puts "Hit: #{env["PATH_INFO"]}" if ENV["SHOW_URLS"]
increment_active_requests
@app.call(env)
ensure
decrement_active_requests
end
private
def increment_active_requests
@@num_active_requests += 1
end
def decrement_active_requests
@@num_active_requests -= 1
# Mark this as the last time there were zero requests
@@nil_requests_at = Time.now if @@num_active_requests == 0
end
end
# spec/support/wait_for.rb
#
# Coupled with a Ruby-side request counter: see /lib/rack_request.counter.rb
class Capybara::Session
def wait_until(timeout = Capybara.default_wait_time)
Timeout.timeout(timeout) do
sleep(0.05) until value = yield
value
end
end
end
# If this is called in a scenario from rspec page will be defined. However,
# we've also overridden Capybara's default 'click' behaviour to also call
# wait_for_ajax; this means we need to load the current session from Capybara.
def wait_for_ajax(timeout = Capybara.default_wait_time)
page ||= Capybara.current_session
# After clicking, wait 50ms for an ajax request to fire off
sleep(0.05)
page.wait_until(timeout) do
# If there are no active requests and the last request was over 150ms ago,
# continue. This means that one AJAX request wasn't depending on another to
# finish... race condition central.com
RackRequestCounter.num_active_requests <= 0 && Time.now - RackRequestCounter.nil_requests_at > 0.15
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment