capybara 1.1.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. data/{History.txt → History.md} +138 -0
  2. data/License.txt +22 -0
  3. data/README.md +850 -0
  4. data/lib/capybara/cucumber.rb +2 -5
  5. data/lib/capybara/driver/base.rb +6 -6
  6. data/lib/capybara/driver/node.rb +3 -2
  7. data/lib/capybara/dsl.rb +13 -124
  8. data/lib/capybara/helpers.rb +33 -0
  9. data/lib/capybara/node/actions.rb +16 -30
  10. data/lib/capybara/node/base.rb +56 -13
  11. data/lib/capybara/node/element.rb +18 -30
  12. data/lib/capybara/node/finders.rb +28 -90
  13. data/lib/capybara/node/matchers.rb +121 -73
  14. data/lib/capybara/node/simple.rb +13 -11
  15. data/lib/capybara/query.rb +78 -0
  16. data/lib/capybara/rack_test/browser.rb +27 -39
  17. data/lib/capybara/rack_test/driver.rb +13 -3
  18. data/lib/capybara/rack_test/node.rb +31 -2
  19. data/lib/capybara/result.rb +72 -0
  20. data/lib/capybara/rspec/features.rb +4 -1
  21. data/lib/capybara/rspec/matchers.rb +33 -63
  22. data/lib/capybara/rspec.rb +7 -4
  23. data/lib/capybara/selector.rb +97 -34
  24. data/lib/capybara/selenium/driver.rb +15 -62
  25. data/lib/capybara/selenium/node.rb +14 -21
  26. data/lib/capybara/server.rb +32 -27
  27. data/lib/capybara/session.rb +90 -50
  28. data/lib/capybara/spec/fixtures/another_test_file.txt +1 -0
  29. data/lib/capybara/spec/public/jquery-ui.js +791 -0
  30. data/lib/capybara/spec/public/jquery.js +9046 -0
  31. data/lib/capybara/spec/public/test.js +3 -0
  32. data/lib/capybara/spec/session/all_spec.rb +61 -59
  33. data/lib/capybara/spec/session/assert_selector.rb +123 -0
  34. data/lib/capybara/spec/session/attach_file_spec.rb +72 -55
  35. data/lib/capybara/spec/session/body_spec.rb +21 -0
  36. data/lib/capybara/spec/session/check_spec.rb +68 -48
  37. data/lib/capybara/spec/session/choose_spec.rb +32 -18
  38. data/lib/capybara/spec/session/click_button_spec.rb +263 -232
  39. data/lib/capybara/spec/session/click_link_or_button_spec.rb +40 -29
  40. data/lib/capybara/spec/session/click_link_spec.rb +96 -96
  41. data/lib/capybara/spec/session/current_url_spec.rb +88 -10
  42. data/lib/capybara/spec/session/evaluate_script_spec.rb +6 -0
  43. data/lib/capybara/spec/session/execute_script_spec.rb +7 -0
  44. data/lib/capybara/spec/session/fill_in_spec.rb +119 -103
  45. data/lib/capybara/spec/session/find_button_spec.rb +16 -14
  46. data/lib/capybara/spec/session/find_by_id_spec.rb +16 -14
  47. data/lib/capybara/spec/session/find_field_spec.rb +23 -21
  48. data/lib/capybara/spec/session/find_link_spec.rb +15 -14
  49. data/lib/capybara/spec/session/find_spec.rb +93 -115
  50. data/lib/capybara/spec/session/first_spec.rb +51 -85
  51. data/lib/capybara/spec/session/has_button_spec.rb +22 -24
  52. data/lib/capybara/spec/session/has_css_spec.rb +190 -205
  53. data/lib/capybara/spec/session/has_field_spec.rb +170 -144
  54. data/lib/capybara/spec/session/has_link_spec.rb +26 -29
  55. data/lib/capybara/spec/session/has_select_spec.rb +161 -109
  56. data/lib/capybara/spec/session/has_selector_spec.rb +94 -100
  57. data/lib/capybara/spec/session/has_table_spec.rb +22 -88
  58. data/lib/capybara/spec/session/has_text_spec.rb +195 -0
  59. data/lib/capybara/spec/session/has_xpath_spec.rb +100 -96
  60. data/lib/capybara/spec/session/headers.rb +4 -17
  61. data/lib/capybara/spec/session/html_spec.rb +15 -0
  62. data/lib/capybara/spec/session/node_spec.rb +205 -0
  63. data/lib/capybara/spec/session/reset_session_spec.rb +42 -0
  64. data/lib/capybara/spec/session/response_code.rb +4 -17
  65. data/lib/capybara/spec/session/save_page_spec.rb +46 -0
  66. data/lib/capybara/spec/session/screenshot.rb +13 -0
  67. data/lib/capybara/spec/session/select_spec.rb +99 -88
  68. data/lib/capybara/spec/session/source_spec.rb +12 -0
  69. data/lib/capybara/spec/session/text_spec.rb +15 -12
  70. data/lib/capybara/spec/session/uncheck_spec.rb +22 -17
  71. data/lib/capybara/spec/session/unselect_spec.rb +69 -58
  72. data/lib/capybara/spec/session/visit_spec.rb +74 -0
  73. data/lib/capybara/spec/session/within_frame_spec.rb +31 -0
  74. data/lib/capybara/spec/session/within_spec.rb +118 -131
  75. data/lib/capybara/spec/session/within_window_spec.rb +38 -0
  76. data/lib/capybara/spec/spec_helper.rb +84 -0
  77. data/lib/capybara/spec/test_app.rb +32 -6
  78. data/lib/capybara/spec/views/form.erb +12 -10
  79. data/lib/capybara/spec/views/host_links.erb +2 -2
  80. data/lib/capybara/spec/views/tables.erb +6 -66
  81. data/lib/capybara/spec/views/with_html.erb +9 -4
  82. data/lib/capybara/spec/views/with_js.erb +11 -7
  83. data/lib/capybara/version.rb +1 -1
  84. data/lib/capybara.rb +125 -6
  85. data/spec/basic_node_spec.rb +17 -5
  86. data/spec/capybara_spec.rb +9 -0
  87. data/spec/dsl_spec.rb +31 -17
  88. data/spec/rack_test_spec.rb +157 -0
  89. data/spec/result_spec.rb +51 -0
  90. data/spec/rspec/features_spec.rb +19 -2
  91. data/spec/rspec/matchers_spec.rb +170 -89
  92. data/spec/rspec_spec.rb +1 -3
  93. data/spec/selenium_spec.rb +53 -0
  94. data/spec/server_spec.rb +37 -25
  95. data/spec/spec_helper.rb +1 -30
  96. metadata +39 -31
  97. data/README.rdoc +0 -722
  98. data/lib/capybara/spec/driver.rb +0 -301
  99. data/lib/capybara/spec/session/current_host_spec.rb +0 -68
  100. data/lib/capybara/spec/session/has_content_spec.rb +0 -106
  101. data/lib/capybara/spec/session/javascript.rb +0 -306
  102. data/lib/capybara/spec/session.rb +0 -154
  103. data/lib/capybara/util/save_and_open_page.rb +0 -44
  104. data/lib/capybara/util/timeout.rb +0 -27
  105. data/spec/driver/rack_test_driver_spec.rb +0 -89
  106. data/spec/driver/selenium_driver_spec.rb +0 -37
  107. data/spec/save_and_open_page_spec.rb +0 -155
  108. data/spec/session/rack_test_session_spec.rb +0 -55
  109. data/spec/session/selenium_session_spec.rb +0 -26
  110. data/spec/string_spec.rb +0 -77
  111. data/spec/timeout_spec.rb +0 -28
@@ -2,13 +2,11 @@ require 'selenium-webdriver'
2
2
 
3
3
  class Capybara::Selenium::Driver < Capybara::Driver::Base
4
4
  DEFAULT_OPTIONS = {
5
- :resynchronize => false,
6
- :resynchronization_timeout => 10,
7
5
  :browser => :firefox
8
6
  }
9
- SPECIAL_OPTIONS = [:browser, :resynchronize, :resynchronization_timeout]
7
+ SPECIAL_OPTIONS = [:browser]
10
8
 
11
- attr_reader :app, :rack_server, :options
9
+ attr_reader :app, :options
12
10
 
13
11
  def browser
14
12
  unless @browser
@@ -27,20 +25,20 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
27
25
 
28
26
  def initialize(app, options={})
29
27
  @app = app
28
+ @browser = nil
29
+ @exit_status = nil
30
30
  @options = DEFAULT_OPTIONS.merge(options)
31
- @rack_server = Capybara::Server.new(@app)
32
- @rack_server.boot if Capybara.run_server
33
31
  end
34
32
 
35
33
  def visit(path)
36
- browser.navigate.to(url(path))
34
+ browser.navigate.to(path)
37
35
  end
38
36
 
39
37
  def source
40
38
  browser.page_source
41
39
  end
42
40
 
43
- def body
41
+ def html
44
42
  browser.page_source
45
43
  end
46
44
 
@@ -53,18 +51,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
53
51
  end
54
52
 
55
53
  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
54
+ def needs_server?; true; end
68
55
 
69
56
  def execute_script(script)
70
57
  browser.execute_script script
@@ -74,12 +61,15 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
74
61
  browser.execute_script "return #{script}"
75
62
  end
76
63
 
64
+ def save_screenshot(path, options={})
65
+ browser.save_screenshot(path)
66
+ end
67
+
77
68
  def reset!
78
69
  # Use instance variable directly so we avoid starting the browser just to reset the session
79
70
  if @browser
80
- begin
81
- @browser.manage.delete_all_cookies
82
- rescue Selenium::WebDriver::Error::UnhandledError => e
71
+ begin @browser.manage.delete_all_cookies
72
+ rescue Selenium::WebDriver::Error::UnhandledError
83
73
  # delete_all_cookies fails when we've previously gone
84
74
  # to about:blank, so we rescue this error and do nothing
85
75
  # instead.
@@ -92,6 +82,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
92
82
  old_window = browser.window_handle
93
83
  browser.switch_to.frame(frame_id)
94
84
  yield
85
+ ensure
95
86
  browser.switch_to.window old_window
96
87
  end
97
88
 
@@ -122,44 +113,6 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
122
113
  end
123
114
 
124
115
  def invalid_element_errors
125
- [ Selenium::WebDriver::Error::StaleElementReferenceError,
126
- Selenium::WebDriver::Error::InvalidSelectorError,
127
- Selenium::WebDriver::Error::UnknownError ]
128
- end
129
-
130
- private
131
-
132
- def load_wait_for_ajax_support
133
- browser.execute_script <<-JS
134
- window.capybaraRequestsOutstanding = 0;
135
- (function() { // Overriding XMLHttpRequest
136
- var oldXHR = window.XMLHttpRequest;
137
-
138
- function newXHR() {
139
- var realXHR = new oldXHR();
140
-
141
- window.capybaraRequestsOutstanding++;
142
- realXHR.addEventListener("readystatechange", function() {
143
- if( realXHR.readyState == 4 ) {
144
- setTimeout( function() {
145
- window.capybaraRequestsOutstanding--;
146
- if(window.capybaraRequestsOutstanding < 0) {
147
- window.capybaraRequestsOutstanding = 0;
148
- }
149
- }, 500 );
150
- }
151
- }, false);
152
-
153
- return realXHR;
154
- }
155
-
156
- window.XMLHttpRequest = newXHR;
157
- })();
158
- JS
159
- end
160
-
161
- def url(path)
162
- rack_server.url(path)
116
+ [Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError]
163
117
  end
164
-
165
118
  end
@@ -1,6 +1,7 @@
1
1
  class Capybara::Selenium::Node < Capybara::Driver::Node
2
2
  def text
3
- native.text
3
+ # Selenium doesn't normalize Unicode whitespace.
4
+ Capybara::Helpers.normalize_whitespace(native.text)
4
5
  end
5
6
 
6
7
  def [](name)
@@ -18,39 +19,40 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
18
19
  end
19
20
 
20
21
  def set(value)
22
+ tag_name = self.tag_name
23
+ type = self[:type]
24
+ if (Array === value) && !self[:multiple]
25
+ raise ArgumentError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}"
26
+ end
21
27
  if tag_name == 'input' and type == 'radio'
22
28
  click
23
29
  elsif tag_name == 'input' and type == 'checkbox'
24
30
  click if value ^ native.attribute('checked').to_s.eql?("true")
25
31
  elsif tag_name == 'input' and type == 'file'
26
- resynchronize do
27
- native.send_keys(value.to_s)
28
- end
32
+ path_names = value.to_s.empty? ? [] : value
33
+ native.send_keys(*path_names)
29
34
  elsif tag_name == 'textarea' or tag_name == 'input'
30
- resynchronize do
31
- native.clear
32
- native.send_keys(value.to_s)
33
- end
35
+ native.send_keys(("\b" * native[:value].size) + value.to_s)
34
36
  end
35
37
  end
36
38
 
37
39
  def select_option
38
- resynchronize { native.click } unless selected?
40
+ native.click unless selected?
39
41
  end
40
42
 
41
43
  def unselect_option
42
44
  if select_node['multiple'] != 'multiple' and select_node['multiple'] != 'true'
43
45
  raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
44
46
  end
45
- resynchronize { native.click } if selected?
47
+ native.click if selected?
46
48
  end
47
49
 
48
50
  def click
49
- resynchronize { native.click }
51
+ native.click
50
52
  end
51
53
 
52
54
  def drag_to(element)
53
- resynchronize { driver.browser.action.drag_and_drop(native, element.native).perform }
55
+ driver.browser.action.drag_and_drop(native, element.native).perform
54
56
  end
55
57
 
56
58
  def tag_name
@@ -75,17 +77,8 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
75
77
 
76
78
  private
77
79
 
78
- def resynchronize
79
- driver.resynchronize { yield }
80
- end
81
-
82
80
  # a reference to the select node if this is an option node
83
81
  def select_node
84
82
  find('./ancestor::select').first
85
83
  end
86
-
87
- def type
88
- self[:type]
89
- end
90
-
91
84
  end
@@ -1,11 +1,12 @@
1
1
  require 'uri'
2
2
  require 'net/http'
3
3
  require 'rack'
4
- require 'capybara/util/timeout'
5
4
 
6
5
  module Capybara
7
6
  class Server
8
- class Identify
7
+ class Middleware
8
+ attr_accessor :error
9
+
9
10
  def initialize(app)
10
11
  @app = app
11
12
  end
@@ -14,7 +15,12 @@ module Capybara
14
15
  if env["PATH_INFO"] == "/__identify__"
15
16
  [200, {}, [@app.object_id.to_s]]
16
17
  else
17
- @app.call(env)
18
+ begin
19
+ @app.call(env)
20
+ rescue StandardError => e
21
+ @error = e unless @error
22
+ raise e
23
+ end
18
24
  end
19
25
  end
20
26
  end
@@ -27,23 +33,30 @@ module Capybara
27
33
 
28
34
  attr_reader :app, :port
29
35
 
30
- def initialize(app)
36
+ def initialize(app, port=Capybara.server_port)
31
37
  @app = app
38
+ @middleware = Middleware.new(@app)
39
+ @server_thread = nil # supress warnings
40
+ @port = port
41
+ @port ||= Capybara::Server.ports[@app.object_id]
42
+ @port ||= find_available_port
32
43
  end
33
44
 
34
- def host
35
- "127.0.0.1"
45
+ def reset_error!
46
+ @middleware.error = nil
36
47
  end
37
48
 
38
- def url(path)
39
- if path =~ /^http/
40
- path
41
- else
42
- (Capybara.app_host || "http://#{host}:#{port}") + path.to_s
43
- end
49
+ def error
50
+ @middleware.error
51
+ end
52
+
53
+ def host
54
+ Capybara.server_host || "127.0.0.1"
44
55
  end
45
56
 
46
57
  def responsive?
58
+ return false if @server_thread && @server_thread.join(0)
59
+
47
60
  res = Net::HTTP.start(host, @port) { |http| http.get('/__identify__') }
48
61
 
49
62
  if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection)
@@ -54,25 +67,17 @@ module Capybara
54
67
  end
55
68
 
56
69
  def boot
57
- if @app
58
- @port = Capybara::Server.ports[@app.object_id]
59
-
60
- if not @port or not responsive?
61
- @port = Capybara.server_port || find_available_port
62
- Capybara::Server.ports[@app.object_id] = @port
63
-
64
- Thread.new do
65
- Capybara.server.call(Identify.new(@app), @port)
66
- end
70
+ unless responsive?
71
+ Capybara::Server.ports[@app.object_id] = @port
67
72
 
68
- Capybara.timeout(Capybara.server_boot_timeout) do
69
- if responsive? then true else sleep(0.5) and false end
70
- end
73
+ @server_thread = Thread.new do
74
+ Capybara.server.call(@middleware, @port)
71
75
  end
76
+
77
+ Timeout.timeout(60) { @server_thread.join(0.1) until responsive? }
72
78
  end
73
79
  rescue TimeoutError
74
- puts "Rack application timed out during boot"
75
- exit
80
+ raise "Rack application timed out during boot"
76
81
  else
77
82
  self
78
83
  end
@@ -1,5 +1,3 @@
1
- require 'capybara/util/timeout'
2
-
3
1
  module Capybara
4
2
 
5
3
  ##
@@ -30,26 +28,30 @@ module Capybara
30
28
  :all, :first, :attach_file, :text, :check, :choose,
31
29
  :click_link_or_button, :click_button, :click_link, :field_labeled,
32
30
  :fill_in, :find, :find_button, :find_by_id, :find_field, :find_link,
33
- :has_content?, :has_css?, :has_no_content?, :has_no_css?, :has_no_xpath?,
34
- :has_xpath?, :select, :uncheck, :has_link?, :has_no_link?, :has_button?,
35
- :has_no_button?, :has_field?, :has_no_field?, :has_checked_field?,
36
- :has_unchecked_field?, :has_no_table?, :has_table?, :unselect,
37
- :has_select?, :has_no_select?, :has_selector?, :has_no_selector?,
38
- :click_on, :has_no_checked_field?, :has_no_unchecked_field?
31
+ :has_content?, :has_text?, :has_css?, :has_no_content?, :has_no_text?,
32
+ :has_no_css?, :has_no_xpath?, :resolve, :has_xpath?, :select, :uncheck,
33
+ :has_link?, :has_no_link?, :has_button?, :has_no_button?, :has_field?,
34
+ :has_no_field?, :has_checked_field?, :has_unchecked_field?,
35
+ :has_no_table?, :has_table?, :unselect, :has_select?, :has_no_select?,
36
+ :has_selector?, :has_no_selector?, :click_on, :has_no_checked_field?,
37
+ :has_no_unchecked_field?, :query, :assert_selector, :assert_no_selector
39
38
  ]
40
39
  SESSION_METHODS = [
41
40
  :body, :html, :current_url, :current_host, :evaluate_script, :source,
42
- :visit, :wait_until, :within, :within_fieldset, :within_table,
43
- :within_frame, :within_window, :current_path, :save_page,
44
- :save_and_open_page, :reset_session!
41
+ :visit, :within, :within_fieldset, :within_table, :within_frame,
42
+ :within_window, :current_path, :save_page, :save_and_open_page,
43
+ :save_screenshot, :reset_session!, :response_headers, :status_code
45
44
  ]
46
45
  DSL_METHODS = NODE_METHODS + SESSION_METHODS
47
46
 
48
- attr_reader :mode, :app
47
+ attr_reader :mode, :app, :server
49
48
 
50
49
  def initialize(mode, app=nil)
51
50
  @mode = mode
52
51
  @app = app
52
+ if Capybara.run_server and @app and driver.needs_server?
53
+ @server = Capybara::Server.new(@app).boot
54
+ end
53
55
  end
54
56
 
55
57
  def driver
@@ -67,7 +69,11 @@ module Capybara
67
69
  # Reset the session, removing all cookies.
68
70
  #
69
71
  def reset!
70
- driver.reset!
72
+ driver.reset! if @touched
73
+ @touched = false
74
+ raise @server.error if @server and @server.error
75
+ ensure
76
+ @server.reset_error! if @server
71
77
  end
72
78
  alias_method :cleanup!, :reset!
73
79
  alias_method :reset_session!, :reset!
@@ -94,12 +100,11 @@ module Capybara
94
100
 
95
101
  ##
96
102
  #
97
- # @return [String] A snapshot of the HTML of the current document, as it looks right now (potentially modified by JavaScript).
103
+ # @return [String] A snapshot of the DOM of the current document, as it looks right now (potentially modified by JavaScript).
98
104
  #
99
- def body
100
- driver.body
105
+ def html
106
+ driver.html
101
107
  end
102
- alias_method :html, :body
103
108
 
104
109
  ##
105
110
  #
@@ -108,6 +113,7 @@ module Capybara
108
113
  def source
109
114
  driver.source
110
115
  end
116
+ alias_method :body, :source
111
117
 
112
118
  ##
113
119
  #
@@ -143,17 +149,39 @@ module Capybara
143
149
  # session.visit('/foo')
144
150
  # session.visit('http://google.com')
145
151
  #
146
- # For drivers which can run against an external application, such as culerity and selenium
152
+ # For drivers which can run against an external application, such as the selenium driver
147
153
  # giving an absolute URL will navigate to that page. This allows testing applications
148
- # running on remote servers. For these drivers, setting Capybara.app_host will make the
154
+ # running on remote servers. For these drivers, setting {Capybara.app_host} will make the
149
155
  # remote server the default. For example:
150
156
  #
151
157
  # Capybara.app_host = 'http://google.com'
152
158
  # session.visit('/') # visits the google homepage
153
159
  #
160
+ # If {Capybara.always_include_port} is set to true and this session is running against
161
+ # a rack application, then the port that the rack application is running on will automatically
162
+ # be inserted into the URL. Supposing the app is running on port `4567`, doing something like:
163
+ #
164
+ # visit("http://google.com/test")
165
+ #
166
+ # Will actually navigate to `http://google.com:4567/test`.
167
+ #
154
168
  # @param [String] url The URL to navigate to
155
169
  #
156
170
  def visit(url)
171
+ @touched = true
172
+
173
+ if @server
174
+ unless url =~ /^http/
175
+ url = (Capybara.app_host || "http://#{@server.host}:#{@server.port}") + url.to_s
176
+ end
177
+
178
+ if Capybara.always_include_port
179
+ uri = URI.parse(url)
180
+ uri.port = @server.port if uri.port == uri.default_port
181
+ url = uri.to_s
182
+ end
183
+ end
184
+
157
185
  driver.visit(url)
158
186
  end
159
187
 
@@ -182,11 +210,7 @@ module Capybara
182
210
  # @raise [Capybara::ElementNotFound] If the scope can't be found before time expires
183
211
  #
184
212
  def within(*args)
185
- new_scope = if args.size == 1 && Capybara::Node::Base === args.first
186
- args.first
187
- else
188
- find(*args)
189
- end
213
+ new_scope = if args.first.is_a?(Capybara::Node::Base) then args.first else find(*args) end
190
214
  begin
191
215
  scopes.push(new_scope)
192
216
  yield
@@ -202,7 +226,7 @@ module Capybara
202
226
  # @param [String] locator Id or legend of the fieldset
203
227
  #
204
228
  def within_fieldset(locator)
205
- within :xpath, XPath::HTML.fieldset(locator) do
229
+ within :fieldset, locator do
206
230
  yield
207
231
  end
208
232
  end
@@ -214,7 +238,7 @@ module Capybara
214
238
  # @param [String] locator Id or caption of the table
215
239
  #
216
240
  def within_table(locator)
217
- within :xpath, XPath::HTML.table(locator) do
241
+ within :table, locator do
218
242
  yield
219
243
  end
220
244
  end
@@ -224,7 +248,7 @@ module Capybara
224
248
  # Execute the given block within the given iframe given the id of that iframe. Only works on
225
249
  # some drivers (e.g. Selenium)
226
250
  #
227
- # @param [String] locator Id of the frame
251
+ # @param [String] frame_id Id of the frame
228
252
  #
229
253
  def within_frame(frame_id)
230
254
  driver.within_frame(frame_id) do
@@ -237,31 +261,22 @@ module Capybara
237
261
  # Execute the given block within the given window. Only works on
238
262
  # some drivers (e.g. Selenium)
239
263
  #
240
- # @param [String] locator of the window
264
+ # @param [String] handle of the window
241
265
  #
242
266
  def within_window(handle, &blk)
243
267
  driver.within_window(handle, &blk)
244
268
  end
245
269
 
246
- ##
247
- #
248
- # Retry executing the block until a truthy result is returned or the timeout time is exceeded
249
- #
250
- # @param [Integer] timeout The amount of seconds to retry executing the given block
251
- #
252
- def wait_until(timeout = Capybara.default_wait_time)
253
- Capybara.timeout(timeout,driver) { yield }
254
- end
255
-
256
270
  ##
257
271
  #
258
272
  # Execute the given script, not returning a result. This is useful for scripts that return
259
- # complex objects, such as jQuery statements. +execute_script+ should always be used over
273
+ # complex objects, such as jQuery statements. +execute_script+ should be used over
260
274
  # +evaluate_script+ whenever possible.
261
275
  #
262
276
  # @param [String] script A string of JavaScript to execute
263
277
  #
264
278
  def execute_script(script)
279
+ @touched = true
265
280
  driver.execute_script(script)
266
281
  end
267
282
 
@@ -275,21 +290,47 @@ module Capybara
275
290
  # @return [Object] The result of the evaluated JavaScript (may be driver specific)
276
291
  #
277
292
  def evaluate_script(script)
293
+ @touched = true
278
294
  driver.evaluate_script(script)
279
295
  end
280
296
 
297
+ ##
298
+ #
299
+ # Save a snapshot of the page.
300
+ #
301
+ # @param [String] path The path to where it should be saved [optional]
302
+ #
303
+ def save_page(path=nil)
304
+ path ||= "capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}#{rand(10**10)}.html"
305
+ path = File.expand_path(path, Capybara.save_and_open_page_path) if Capybara.save_and_open_page_path
306
+
307
+ FileUtils.mkdir_p(File.dirname(path))
308
+
309
+ File.open(path,'w') { |f| f.write(body) }
310
+ path
311
+ end
312
+
281
313
  ##
282
314
  #
283
315
  # Save a snapshot of the page and open it in a browser for inspection
284
316
  #
285
- def save_page
286
- require 'capybara/util/save_and_open_page'
287
- Capybara.save_page(body)
317
+ # @param [String] path The path to where it should be saved [optional]
318
+ #
319
+ def save_and_open_page(file_name=nil)
320
+ require "launchy"
321
+ Launchy.open(save_page(file_name))
322
+ rescue LoadError
323
+ warn "Please install the launchy gem to open page with save_and_open_page"
288
324
  end
289
325
 
290
- def save_and_open_page
291
- require 'capybara/util/save_and_open_page'
292
- Capybara.save_and_open_page(body)
326
+ ##
327
+ #
328
+ # Save a screenshot of page
329
+ #
330
+ # @param [String] path A string of image path
331
+ # @option [Hash] options Options for saving screenshot
332
+ def save_screenshot(path, options={})
333
+ driver.save_screenshot(path, options)
293
334
  end
294
335
 
295
336
  def document
@@ -297,11 +338,10 @@ module Capybara
297
338
  end
298
339
 
299
340
  NODE_METHODS.each do |method|
300
- class_eval <<-RUBY
301
- def #{method}(*args, &block)
302
- current_node.send(:#{method}, *args, &block)
303
- end
304
- RUBY
341
+ define_method method do |*args, &block|
342
+ @touched = true
343
+ current_node.send(method, *args, &block)
344
+ end
305
345
  end
306
346
 
307
347
  def inspect
@@ -0,0 +1 @@
1
+ ThisIsTheOtherTestFile