nimboids-capybara 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +289 -0
- data/README.rdoc +722 -0
- data/lib/capybara.rb +252 -0
- data/lib/capybara/cucumber.rb +28 -0
- data/lib/capybara/driver/base.rb +64 -0
- data/lib/capybara/driver/node.rb +74 -0
- data/lib/capybara/dsl.rb +168 -0
- data/lib/capybara/node/actions.rb +162 -0
- data/lib/capybara/node/base.rb +63 -0
- data/lib/capybara/node/document.rb +25 -0
- data/lib/capybara/node/element.rb +201 -0
- data/lib/capybara/node/finders.rb +197 -0
- data/lib/capybara/node/matchers.rb +417 -0
- data/lib/capybara/node/simple.rb +132 -0
- data/lib/capybara/rack_test/browser.rb +121 -0
- data/lib/capybara/rack_test/driver.rb +80 -0
- data/lib/capybara/rack_test/form.rb +80 -0
- data/lib/capybara/rack_test/node.rb +105 -0
- data/lib/capybara/rails.rb +17 -0
- data/lib/capybara/rspec.rb +26 -0
- data/lib/capybara/rspec/features.rb +22 -0
- data/lib/capybara/rspec/matchers.rb +154 -0
- data/lib/capybara/selector.rb +89 -0
- data/lib/capybara/selenium/driver.rb +163 -0
- data/lib/capybara/selenium/node.rb +91 -0
- data/lib/capybara/server.rb +90 -0
- data/lib/capybara/session.rb +321 -0
- data/lib/capybara/spec/driver.rb +301 -0
- data/lib/capybara/spec/fixtures/capybara.jpg +3 -0
- data/lib/capybara/spec/fixtures/test_file.txt +1 -0
- data/lib/capybara/spec/public/test.js +43 -0
- data/lib/capybara/spec/session.rb +154 -0
- data/lib/capybara/spec/session/all_spec.rb +78 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +73 -0
- data/lib/capybara/spec/session/check_spec.rb +65 -0
- data/lib/capybara/spec/session/choose_spec.rb +26 -0
- data/lib/capybara/spec/session/click_button_spec.rb +304 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +36 -0
- data/lib/capybara/spec/session/click_link_spec.rb +119 -0
- data/lib/capybara/spec/session/current_host_spec.rb +68 -0
- data/lib/capybara/spec/session/current_url_spec.rb +15 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +125 -0
- data/lib/capybara/spec/session/find_button_spec.rb +18 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +18 -0
- data/lib/capybara/spec/session/find_field_spec.rb +26 -0
- data/lib/capybara/spec/session/find_link_spec.rb +19 -0
- data/lib/capybara/spec/session/find_spec.rb +149 -0
- data/lib/capybara/spec/session/first_spec.rb +105 -0
- data/lib/capybara/spec/session/has_button_spec.rb +32 -0
- data/lib/capybara/spec/session/has_content_spec.rb +106 -0
- data/lib/capybara/spec/session/has_css_spec.rb +243 -0
- data/lib/capybara/spec/session/has_field_spec.rb +192 -0
- data/lib/capybara/spec/session/has_link_spec.rb +37 -0
- data/lib/capybara/spec/session/has_select_spec.rb +129 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
- data/lib/capybara/spec/session/has_table_spec.rb +96 -0
- data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
- data/lib/capybara/spec/session/headers.rb +19 -0
- data/lib/capybara/spec/session/javascript.rb +289 -0
- data/lib/capybara/spec/session/response_code.rb +19 -0
- data/lib/capybara/spec/session/select_spec.rb +113 -0
- data/lib/capybara/spec/session/text_spec.rb +19 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
- data/lib/capybara/spec/session/unselect_spec.rb +61 -0
- data/lib/capybara/spec/session/within_spec.rb +178 -0
- data/lib/capybara/spec/test_app.rb +142 -0
- data/lib/capybara/spec/views/buttons.erb +4 -0
- data/lib/capybara/spec/views/fieldsets.erb +29 -0
- data/lib/capybara/spec/views/form.erb +365 -0
- data/lib/capybara/spec/views/frame_one.erb +8 -0
- data/lib/capybara/spec/views/frame_two.erb +8 -0
- data/lib/capybara/spec/views/header_links.erb +7 -0
- data/lib/capybara/spec/views/host_links.erb +12 -0
- data/lib/capybara/spec/views/popup_one.erb +8 -0
- data/lib/capybara/spec/views/popup_two.erb +8 -0
- data/lib/capybara/spec/views/postback.erb +13 -0
- data/lib/capybara/spec/views/tables.erb +122 -0
- data/lib/capybara/spec/views/with_html.erb +78 -0
- data/lib/capybara/spec/views/with_html_entities.erb +1 -0
- data/lib/capybara/spec/views/with_js.erb +48 -0
- data/lib/capybara/spec/views/with_scope.erb +36 -0
- data/lib/capybara/spec/views/with_simple_html.erb +1 -0
- data/lib/capybara/spec/views/within_frames.erb +10 -0
- data/lib/capybara/spec/views/within_popups.erb +25 -0
- data/lib/capybara/util/save_and_open_page.rb +44 -0
- data/lib/capybara/util/timeout.rb +27 -0
- data/lib/capybara/version.rb +3 -0
- data/spec/basic_node_spec.rb +77 -0
- data/spec/capybara_spec.rb +46 -0
- data/spec/driver/rack_test_driver_spec.rb +89 -0
- data/spec/driver/selenium_driver_spec.rb +50 -0
- data/spec/dsl_spec.rb +253 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +8 -0
- data/spec/fixtures/selenium_driver_rspec_success.rb +8 -0
- data/spec/rspec/features_spec.rb +45 -0
- data/spec/rspec/matchers_spec.rb +495 -0
- data/spec/rspec_spec.rb +53 -0
- data/spec/save_and_open_page_spec.rb +155 -0
- data/spec/server_spec.rb +89 -0
- data/spec/session/rack_test_session_spec.rb +55 -0
- data/spec/session/selenium_session_spec.rb +26 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/string_spec.rb +77 -0
- data/spec/timeout_spec.rb +28 -0
- metadata +346 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require 'capybara/dsl'
|
3
|
+
|
4
|
+
Capybara.app = Rack::Builder.new do
|
5
|
+
map "/" do
|
6
|
+
if Rails.version.to_f >= 3.0
|
7
|
+
run Rails.application
|
8
|
+
else # Rails 2
|
9
|
+
use Rails::Rack::Static
|
10
|
+
run ActionController::Dispatcher.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end.to_app
|
14
|
+
|
15
|
+
Capybara.asset_root = Rails.root.join('public')
|
16
|
+
Capybara.save_and_open_page_path = Rails.root.join('tmp/capybara')
|
17
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
require 'capybara/dsl'
|
3
|
+
require 'rspec/core'
|
4
|
+
require 'capybara/rspec/matchers'
|
5
|
+
require 'capybara/rspec/features'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.include Capybara::DSL, :type => :request
|
9
|
+
config.include Capybara::DSL, :type => :acceptance
|
10
|
+
config.include Capybara::RSpecMatchers, :type => :request
|
11
|
+
config.include Capybara::RSpecMatchers, :type => :acceptance
|
12
|
+
# The before and after blocks must run instantaneously, because Capybara
|
13
|
+
# might not actually be used in all examples where it's included.
|
14
|
+
config.after do
|
15
|
+
if self.class.include?(Capybara::DSL)
|
16
|
+
Capybara.reset_sessions!
|
17
|
+
Capybara.use_default_driver
|
18
|
+
end
|
19
|
+
end
|
20
|
+
config.before do
|
21
|
+
if self.class.include?(Capybara::DSL)
|
22
|
+
Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js]
|
23
|
+
Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Capybara
|
2
|
+
module Features
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_eval do
|
5
|
+
alias :background :before
|
6
|
+
alias :scenario :it
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.feature(*args, &block)
|
13
|
+
options = if args.last.is_a?(Hash) then args.pop else {} end
|
14
|
+
options[:capybara_feature] = true
|
15
|
+
options[:type] = :request
|
16
|
+
options[:caller] ||= caller
|
17
|
+
args.push(options)
|
18
|
+
|
19
|
+
describe(*args, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
RSpec.configuration.include Capybara::Features, :capybara_feature => true
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module Capybara
|
2
|
+
module RSpecMatchers
|
3
|
+
class HaveSelector
|
4
|
+
def initialize(*args)
|
5
|
+
@args = args
|
6
|
+
end
|
7
|
+
|
8
|
+
def matches?(actual)
|
9
|
+
@actual = wrap(actual)
|
10
|
+
@actual.has_selector?(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def does_not_match?(actual)
|
14
|
+
@actual = wrap(actual)
|
15
|
+
@actual.has_no_selector?(*@args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_message_for_should
|
19
|
+
if normalized.failure_message
|
20
|
+
normalized.failure_message.call(@actual, normalized)
|
21
|
+
else
|
22
|
+
"expected #{selector_name} to return something"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def failure_message_for_should_not
|
27
|
+
"expected #{selector_name} not to return anything"
|
28
|
+
end
|
29
|
+
|
30
|
+
def description
|
31
|
+
"has #{selector_name}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def selector_name
|
35
|
+
name = "#{normalized.name} #{normalized.locator.inspect}"
|
36
|
+
name << " with text #{normalized.options[:text].inspect}" if normalized.options[:text]
|
37
|
+
name
|
38
|
+
end
|
39
|
+
|
40
|
+
def wrap(actual)
|
41
|
+
if actual.respond_to?("has_selector?")
|
42
|
+
actual
|
43
|
+
else
|
44
|
+
Capybara.string(actual.to_s)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def normalized
|
49
|
+
@normalized ||= Capybara::Selector.normalize(*@args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class HaveMatcher
|
54
|
+
attr_reader :name, :locator, :options, :failure_message, :actual
|
55
|
+
|
56
|
+
def initialize(name, locator, options={}, &block)
|
57
|
+
@name = name
|
58
|
+
@locator = locator
|
59
|
+
@options = options
|
60
|
+
@failure_message = block
|
61
|
+
end
|
62
|
+
|
63
|
+
def arguments
|
64
|
+
if options.empty? then [locator] else [locator, options] end
|
65
|
+
end
|
66
|
+
|
67
|
+
def matches?(actual)
|
68
|
+
@actual = wrap(actual)
|
69
|
+
@actual.send(:"has_#{name}?", *arguments)
|
70
|
+
end
|
71
|
+
|
72
|
+
def does_not_match?(actual)
|
73
|
+
@actual = wrap(actual)
|
74
|
+
@actual.send(:"has_no_#{name}?", *arguments)
|
75
|
+
end
|
76
|
+
|
77
|
+
def failure_message_for_should
|
78
|
+
if failure_message
|
79
|
+
failure_message.call(actual, self)
|
80
|
+
else
|
81
|
+
"expected #{selector_name} to return something"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def failure_message_for_should_not
|
86
|
+
"expected #{selector_name} not to return anything"
|
87
|
+
end
|
88
|
+
|
89
|
+
def description
|
90
|
+
"has #{selector_name}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def selector_name
|
94
|
+
selector_name = "#{name} #{locator.inspect}"
|
95
|
+
selector_name << " with text #{options[:text].inspect}" if options[:text]
|
96
|
+
selector_name
|
97
|
+
end
|
98
|
+
|
99
|
+
def wrap(actual)
|
100
|
+
if actual.respond_to?("has_selector?")
|
101
|
+
actual
|
102
|
+
else
|
103
|
+
Capybara.string(actual.to_s)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def have_selector(*args)
|
109
|
+
HaveSelector.new(*args)
|
110
|
+
end
|
111
|
+
|
112
|
+
def have_xpath(xpath, options={})
|
113
|
+
HaveMatcher.new(:xpath, xpath, options)
|
114
|
+
end
|
115
|
+
|
116
|
+
def have_css(css, options={})
|
117
|
+
HaveMatcher.new(:css, css, options)
|
118
|
+
end
|
119
|
+
|
120
|
+
def have_content(text)
|
121
|
+
HaveMatcher.new(:content, text.to_s) do |page, matcher|
|
122
|
+
%(expected there to be content #{matcher.locator.inspect} in #{page.text.inspect})
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def have_link(locator, options={})
|
127
|
+
HaveMatcher.new(:link, locator, options)
|
128
|
+
end
|
129
|
+
|
130
|
+
def have_button(locator)
|
131
|
+
HaveMatcher.new(:button, locator)
|
132
|
+
end
|
133
|
+
|
134
|
+
def have_field(locator, options={})
|
135
|
+
HaveMatcher.new(:field, locator, options)
|
136
|
+
end
|
137
|
+
|
138
|
+
def have_checked_field(locator)
|
139
|
+
HaveMatcher.new(:checked_field, locator)
|
140
|
+
end
|
141
|
+
|
142
|
+
def have_unchecked_field(locator)
|
143
|
+
HaveMatcher.new(:unchecked_field, locator)
|
144
|
+
end
|
145
|
+
|
146
|
+
def have_select(locator, options={})
|
147
|
+
HaveMatcher.new(:select, locator, options)
|
148
|
+
end
|
149
|
+
|
150
|
+
def have_table(locator, options={})
|
151
|
+
HaveMatcher.new(:table, locator, options)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Capybara
|
2
|
+
class Selector
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
class Normalized
|
6
|
+
attr_accessor :selector, :locator, :options, :xpaths
|
7
|
+
|
8
|
+
def failure_message; selector.failure_message; end
|
9
|
+
def name; selector.name; end
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def all
|
14
|
+
@selectors ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(name, &block)
|
18
|
+
all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove(name)
|
22
|
+
all.delete(name.to_sym)
|
23
|
+
end
|
24
|
+
|
25
|
+
def normalize(*args)
|
26
|
+
normalized = Normalized.new
|
27
|
+
normalized.options = if args.last.is_a?(Hash) then args.pop else {} end
|
28
|
+
|
29
|
+
if args[1]
|
30
|
+
normalized.selector = all[args[0]]
|
31
|
+
normalized.locator = args[1]
|
32
|
+
else
|
33
|
+
normalized.selector = all.values.find { |s| s.match?(args[0]) }
|
34
|
+
normalized.locator = args[0]
|
35
|
+
end
|
36
|
+
normalized.selector ||= all[Capybara.default_selector]
|
37
|
+
|
38
|
+
xpath = normalized.selector.call(normalized.locator)
|
39
|
+
if xpath.respond_to?(:to_xpaths)
|
40
|
+
normalized.xpaths = xpath.to_xpaths
|
41
|
+
else
|
42
|
+
normalized.xpaths = [xpath.to_s].flatten
|
43
|
+
end
|
44
|
+
normalized
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(name, &block)
|
49
|
+
@name = name
|
50
|
+
instance_eval(&block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def xpath(&block)
|
54
|
+
@xpath = block if block
|
55
|
+
@xpath
|
56
|
+
end
|
57
|
+
|
58
|
+
def match(&block)
|
59
|
+
@match = block if block
|
60
|
+
@match
|
61
|
+
end
|
62
|
+
|
63
|
+
def failure_message(&block)
|
64
|
+
@failure_message = block if block
|
65
|
+
@failure_message
|
66
|
+
end
|
67
|
+
|
68
|
+
def call(locator)
|
69
|
+
@xpath.call(locator)
|
70
|
+
end
|
71
|
+
|
72
|
+
def match?(locator)
|
73
|
+
@match and @match.call(locator)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Capybara.add_selector(:xpath) do
|
79
|
+
xpath { |xpath| xpath }
|
80
|
+
end
|
81
|
+
|
82
|
+
Capybara.add_selector(:css) do
|
83
|
+
xpath { |css| XPath.css(css) }
|
84
|
+
end
|
85
|
+
|
86
|
+
Capybara.add_selector(:id) do
|
87
|
+
xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
|
88
|
+
match { |value| value.is_a?(Symbol) }
|
89
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'selenium-webdriver'
|
2
|
+
|
3
|
+
class Capybara::Selenium::Driver < Capybara::Driver::Base
|
4
|
+
DEFAULT_OPTIONS = {
|
5
|
+
:resynchronize => false,
|
6
|
+
:resynchronization_timeout => 10,
|
7
|
+
:browser => :firefox
|
8
|
+
}
|
9
|
+
SPECIAL_OPTIONS = [:browser, :resynchronize, :resynchronization_timeout]
|
10
|
+
|
11
|
+
attr_reader :app, :rack_server, :options
|
12
|
+
|
13
|
+
def browser
|
14
|
+
unless @browser
|
15
|
+
@browser = Selenium::WebDriver.for(options[:browser], options.reject { |key,val| SPECIAL_OPTIONS.include?(key) })
|
16
|
+
|
17
|
+
main = Process.pid
|
18
|
+
at_exit do
|
19
|
+
# Store the exit status of the test run since it goes away after calling the at_exit proc...
|
20
|
+
@exit_status = $!.status if $!.is_a?(SystemExit)
|
21
|
+
quit if Process.pid == main
|
22
|
+
exit @exit_status if @exit_status # Force exit with stored status
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@browser
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(app, options={})
|
29
|
+
@app = app
|
30
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
31
|
+
@rack_server = Capybara::Server.new(@app)
|
32
|
+
@rack_server.boot if Capybara.run_server
|
33
|
+
end
|
34
|
+
|
35
|
+
def visit(path)
|
36
|
+
browser.navigate.to(url(path))
|
37
|
+
end
|
38
|
+
|
39
|
+
def source
|
40
|
+
browser.page_source
|
41
|
+
end
|
42
|
+
|
43
|
+
def body
|
44
|
+
browser.page_source
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_url
|
48
|
+
browser.current_url
|
49
|
+
end
|
50
|
+
|
51
|
+
def find(selector)
|
52
|
+
browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def wait?; true; end
|
56
|
+
|
57
|
+
def resynchronize
|
58
|
+
if options[:resynchronize]
|
59
|
+
load_wait_for_ajax_support
|
60
|
+
yield
|
61
|
+
Capybara.timeout(options[:resynchronization_timeout], self, "failed to resynchronize, ajax request timed out") do
|
62
|
+
evaluate_script("!window.capybaraRequestsOutstanding")
|
63
|
+
end
|
64
|
+
else
|
65
|
+
yield
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def execute_script(script)
|
70
|
+
browser.execute_script script
|
71
|
+
end
|
72
|
+
|
73
|
+
def evaluate_script(script)
|
74
|
+
browser.execute_script "return #{script}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def reset!
|
78
|
+
# Use instance variable directly so we avoid starting the browser just to reset the session
|
79
|
+
if @browser
|
80
|
+
begin
|
81
|
+
@browser.manage.delete_all_cookies
|
82
|
+
rescue Selenium::WebDriver::Error::UnhandledError => e
|
83
|
+
# delete_all_cookies fails when we've previously gone
|
84
|
+
# to about:blank, so we rescue this error and do nothing
|
85
|
+
# instead.
|
86
|
+
end
|
87
|
+
@browser.navigate.to('about:blank')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def within_frame(frame_id)
|
92
|
+
old_window = browser.window_handle
|
93
|
+
browser.switch_to.frame(frame_id)
|
94
|
+
yield
|
95
|
+
browser.switch_to.window old_window
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_window( selector )
|
99
|
+
original_handle = browser.window_handle
|
100
|
+
browser.window_handles.each do |handle|
|
101
|
+
browser.switch_to.window handle
|
102
|
+
if( selector == browser.execute_script("return window.name") ||
|
103
|
+
browser.title.include?(selector) ||
|
104
|
+
browser.current_url.include?(selector) ||
|
105
|
+
(selector == handle) )
|
106
|
+
browser.switch_to.window original_handle
|
107
|
+
return handle
|
108
|
+
end
|
109
|
+
end
|
110
|
+
raise Capybara::ElementNotFound, "Could not find a window identified by #{selector}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def within_window(selector, &blk)
|
114
|
+
handle = find_window( selector )
|
115
|
+
browser.switch_to.window(handle, &blk)
|
116
|
+
end
|
117
|
+
|
118
|
+
def quit
|
119
|
+
@browser.quit
|
120
|
+
rescue Errno::ECONNREFUSED
|
121
|
+
# Browser must have already gone
|
122
|
+
end
|
123
|
+
|
124
|
+
def invalid_element_errors
|
125
|
+
[Selenium::WebDriver::Error::ObsoleteElementError]
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def load_wait_for_ajax_support
|
131
|
+
browser.execute_script <<-JS
|
132
|
+
window.capybaraRequestsOutstanding = 0;
|
133
|
+
(function() { // Overriding XMLHttpRequest
|
134
|
+
var oldXHR = window.XMLHttpRequest;
|
135
|
+
|
136
|
+
function newXHR() {
|
137
|
+
var realXHR = new oldXHR();
|
138
|
+
|
139
|
+
window.capybaraRequestsOutstanding++;
|
140
|
+
realXHR.addEventListener("readystatechange", function() {
|
141
|
+
if( realXHR.readyState == 4 ) {
|
142
|
+
setTimeout( function() {
|
143
|
+
window.capybaraRequestsOutstanding--;
|
144
|
+
if(window.capybaraRequestsOutstanding < 0) {
|
145
|
+
window.capybaraRequestsOutstanding = 0;
|
146
|
+
}
|
147
|
+
}, 500 );
|
148
|
+
}
|
149
|
+
}, false);
|
150
|
+
|
151
|
+
return realXHR;
|
152
|
+
}
|
153
|
+
|
154
|
+
window.XMLHttpRequest = newXHR;
|
155
|
+
})();
|
156
|
+
JS
|
157
|
+
end
|
158
|
+
|
159
|
+
def url(path)
|
160
|
+
rack_server.url(path)
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|