capybara 2.0.3 → 2.1.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.
- data/History.md +82 -0
- data/README.md +57 -52
- data/lib/capybara/cucumber.rb +4 -1
- data/lib/capybara/driver/base.rb +13 -9
- data/lib/capybara/driver/node.rb +18 -6
- data/lib/capybara/helpers.rb +111 -22
- data/lib/capybara/node/actions.rb +30 -25
- data/lib/capybara/node/base.rb +25 -32
- data/lib/capybara/node/document.rb +6 -2
- data/lib/capybara/node/element.rb +44 -7
- data/lib/capybara/node/finders.rb +49 -22
- data/lib/capybara/node/matchers.rb +38 -21
- data/lib/capybara/node/simple.rb +31 -9
- data/lib/capybara/query.rb +72 -26
- data/lib/capybara/rack_test/browser.rb +11 -3
- data/lib/capybara/rack_test/css_handlers.rb +8 -0
- data/lib/capybara/rack_test/driver.rb +11 -3
- data/lib/capybara/rack_test/form.rb +8 -1
- data/lib/capybara/rack_test/node.rb +91 -35
- data/lib/capybara/rails.rb +0 -1
- data/lib/capybara/result.rb +21 -37
- data/lib/capybara/rspec/matchers.rb +60 -31
- data/lib/capybara/selector.rb +46 -13
- data/lib/capybara/selenium/driver.rb +42 -7
- data/lib/capybara/selenium/node.rb +23 -5
- data/lib/capybara/server.rb +1 -1
- data/lib/capybara/session.rb +47 -12
- data/lib/capybara/spec/public/test.js +12 -0
- data/lib/capybara/spec/session/all_spec.rb +9 -8
- data/lib/capybara/spec/session/attach_file_spec.rb +14 -0
- data/lib/capybara/spec/session/check_spec.rb +14 -0
- data/lib/capybara/spec/session/choose_spec.rb +14 -0
- data/lib/capybara/spec/session/click_button_spec.rb +77 -1
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +65 -0
- data/lib/capybara/spec/session/click_link_spec.rb +24 -0
- data/lib/capybara/spec/session/current_scope_spec.rb +29 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +26 -0
- data/lib/capybara/spec/session/find_button_spec.rb +12 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +12 -1
- data/lib/capybara/spec/session/find_field_spec.rb +30 -0
- data/lib/capybara/spec/session/find_link_spec.rb +12 -0
- data/lib/capybara/spec/session/find_spec.rb +264 -16
- data/lib/capybara/spec/session/first_spec.rb +25 -8
- data/lib/capybara/spec/session/has_css_spec.rb +2 -2
- data/lib/capybara/spec/session/has_field_spec.rb +10 -2
- data/lib/capybara/spec/session/has_selector_spec.rb +9 -0
- data/lib/capybara/spec/session/has_text_spec.rb +96 -0
- data/lib/capybara/spec/session/has_title_spec.rb +47 -0
- data/lib/capybara/spec/session/node_spec.rb +48 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +10 -2
- data/lib/capybara/spec/session/save_page_spec.rb +30 -0
- data/lib/capybara/spec/session/select_spec.rb +65 -0
- data/lib/capybara/spec/session/text_spec.rb +31 -0
- data/lib/capybara/spec/session/title_spec.rb +16 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +14 -0
- data/lib/capybara/spec/session/unselect_spec.rb +42 -0
- data/lib/capybara/spec/session/visit_spec.rb +3 -3
- data/lib/capybara/spec/session/within_frame_spec.rb +14 -0
- data/lib/capybara/spec/session/within_spec.rb +3 -3
- data/lib/capybara/spec/spec_helper.rb +7 -2
- data/lib/capybara/spec/views/form.erb +39 -2
- data/lib/capybara/spec/views/frame_child.erb +9 -0
- data/lib/capybara/spec/views/frame_parent.erb +8 -0
- data/lib/capybara/spec/views/with_base_tag.erb +10 -0
- data/lib/capybara/spec/views/with_count.erb +7 -0
- data/lib/capybara/spec/views/with_hover.erb +17 -0
- data/lib/capybara/spec/views/with_html.erb +23 -2
- data/lib/capybara/spec/views/with_js.erb +5 -0
- data/lib/capybara/spec/views/with_scope.erb +6 -1
- data/lib/capybara/spec/views/with_title.erb +1 -0
- data/lib/capybara/spec/views/within_frames.erb +1 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara.rb +43 -62
- data/spec/basic_node_spec.rb +75 -24
- data/spec/dsl_spec.rb +2 -1
- data/spec/rack_test_spec.rb +4 -3
- data/spec/rspec/matchers_spec.rb +105 -17
- data/spec/server_spec.rb +15 -8
- data/spec/spec_helper.rb +2 -1
- data.tar.gz.sig +0 -0
- metadata +82 -22
- metadata.gz.sig +0 -0
data/lib/capybara/selector.rb
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
module Capybara
|
|
2
2
|
class Selector
|
|
3
|
-
|
|
3
|
+
class Filter
|
|
4
|
+
def initialize(name, block, options={})
|
|
5
|
+
@name = name
|
|
6
|
+
@block = block
|
|
7
|
+
@options = options
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def default?
|
|
11
|
+
@options.has_key?(:default)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def default
|
|
15
|
+
@options[:default]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def matches?(node, value)
|
|
19
|
+
@block.call(node, value)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
4
22
|
|
|
23
|
+
attr_reader :name, :custom_filters, :format
|
|
5
24
|
|
|
6
25
|
class << self
|
|
7
26
|
def all
|
|
@@ -27,16 +46,16 @@ module Capybara
|
|
|
27
46
|
end
|
|
28
47
|
|
|
29
48
|
def xpath(&block)
|
|
49
|
+
@format = :xpath
|
|
30
50
|
@xpath = block if block
|
|
31
51
|
@xpath
|
|
32
52
|
end
|
|
33
53
|
|
|
34
54
|
# Same as xpath, but wrap in XPath.css().
|
|
35
55
|
def css(&block)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@xpath
|
|
56
|
+
@format = :css
|
|
57
|
+
@css = block if block
|
|
58
|
+
@css
|
|
40
59
|
end
|
|
41
60
|
|
|
42
61
|
def match(&block)
|
|
@@ -50,15 +69,19 @@ module Capybara
|
|
|
50
69
|
end
|
|
51
70
|
|
|
52
71
|
def call(locator)
|
|
53
|
-
@
|
|
72
|
+
if @format==:css
|
|
73
|
+
@css.call(locator)
|
|
74
|
+
else
|
|
75
|
+
@xpath.call(locator)
|
|
76
|
+
end
|
|
54
77
|
end
|
|
55
78
|
|
|
56
79
|
def match?(locator)
|
|
57
80
|
@match and @match.call(locator)
|
|
58
81
|
end
|
|
59
82
|
|
|
60
|
-
def filter(name, &block)
|
|
61
|
-
@custom_filters[name] = block
|
|
83
|
+
def filter(name, options={}, &block)
|
|
84
|
+
@custom_filters[name] = Filter.new(name, block, options)
|
|
62
85
|
end
|
|
63
86
|
end
|
|
64
87
|
end
|
|
@@ -79,8 +102,15 @@ Capybara.add_selector(:field) do
|
|
|
79
102
|
xpath { |locator| XPath::HTML.field(locator) }
|
|
80
103
|
filter(:checked) { |node, value| not(value ^ node.checked?) }
|
|
81
104
|
filter(:unchecked) { |node, value| (value ^ node.checked?) }
|
|
105
|
+
filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
|
|
82
106
|
filter(:with) { |node, with| node.value == with }
|
|
83
|
-
filter(:type)
|
|
107
|
+
filter(:type) do |node, type|
|
|
108
|
+
if ['textarea', 'select'].include?(type)
|
|
109
|
+
node.tag_name == type
|
|
110
|
+
else
|
|
111
|
+
node[:type] == type
|
|
112
|
+
end
|
|
113
|
+
end
|
|
84
114
|
end
|
|
85
115
|
|
|
86
116
|
Capybara.add_selector(:fieldset) do
|
|
@@ -90,6 +120,7 @@ end
|
|
|
90
120
|
Capybara.add_selector(:link_or_button) do
|
|
91
121
|
label "link or button"
|
|
92
122
|
xpath { |locator| XPath::HTML.link_or_button(locator) }
|
|
123
|
+
filter(:disabled, :default => false) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) }
|
|
93
124
|
end
|
|
94
125
|
|
|
95
126
|
Capybara.add_selector(:link) do
|
|
@@ -101,11 +132,13 @@ end
|
|
|
101
132
|
|
|
102
133
|
Capybara.add_selector(:button) do
|
|
103
134
|
xpath { |locator| XPath::HTML.button(locator) }
|
|
135
|
+
filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
|
|
104
136
|
end
|
|
105
137
|
|
|
106
138
|
Capybara.add_selector(:fillable_field) do
|
|
107
139
|
label "field"
|
|
108
140
|
xpath { |locator| XPath::HTML.fillable_field(locator) }
|
|
141
|
+
filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
|
|
109
142
|
end
|
|
110
143
|
|
|
111
144
|
Capybara.add_selector(:radio_button) do
|
|
@@ -113,12 +146,14 @@ Capybara.add_selector(:radio_button) do
|
|
|
113
146
|
xpath { |locator| XPath::HTML.radio_button(locator) }
|
|
114
147
|
filter(:checked) { |node, value| not(value ^ node.checked?) }
|
|
115
148
|
filter(:unchecked) { |node, value| (value ^ node.checked?) }
|
|
149
|
+
filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
|
|
116
150
|
end
|
|
117
151
|
|
|
118
152
|
Capybara.add_selector(:checkbox) do
|
|
119
153
|
xpath { |locator| XPath::HTML.checkbox(locator) }
|
|
120
154
|
filter(:checked) { |node, value| not(value ^ node.checked?) }
|
|
121
155
|
filter(:unchecked) { |node, value| (value ^ node.checked?) }
|
|
156
|
+
filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
|
|
122
157
|
end
|
|
123
158
|
|
|
124
159
|
Capybara.add_selector(:select) do
|
|
@@ -133,6 +168,7 @@ Capybara.add_selector(:select) do
|
|
|
133
168
|
actual = node.all(:xpath, './/option').select { |option| option.selected? }.map { |option| option.text }
|
|
134
169
|
[selected].flatten.sort == actual.sort
|
|
135
170
|
end
|
|
171
|
+
filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
|
|
136
172
|
end
|
|
137
173
|
|
|
138
174
|
Capybara.add_selector(:option) do
|
|
@@ -142,10 +178,7 @@ end
|
|
|
142
178
|
Capybara.add_selector(:file_field) do
|
|
143
179
|
label "file field"
|
|
144
180
|
xpath { |locator| XPath::HTML.file_field(locator) }
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Capybara.add_selector(:content) do
|
|
148
|
-
xpath { |content| XPath::HTML.content(content) }
|
|
181
|
+
filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) }
|
|
149
182
|
end
|
|
150
183
|
|
|
151
184
|
Capybara.add_selector(:table) do
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'selenium-webdriver'
|
|
2
|
-
|
|
3
1
|
class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
4
2
|
DEFAULT_OPTIONS = {
|
|
5
3
|
:browser => :firefox
|
|
@@ -24,9 +22,20 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
24
22
|
end
|
|
25
23
|
|
|
26
24
|
def initialize(app, options={})
|
|
25
|
+
begin
|
|
26
|
+
require 'selenium-webdriver'
|
|
27
|
+
rescue LoadError => e
|
|
28
|
+
if e.message =~ /selenium-webdriver/
|
|
29
|
+
raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler."
|
|
30
|
+
else
|
|
31
|
+
raise e
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
@app = app
|
|
28
36
|
@browser = nil
|
|
29
37
|
@exit_status = nil
|
|
38
|
+
@frame_handles = {}
|
|
30
39
|
@options = DEFAULT_OPTIONS.merge(options)
|
|
31
40
|
end
|
|
32
41
|
|
|
@@ -38,14 +47,22 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
38
47
|
browser.page_source
|
|
39
48
|
end
|
|
40
49
|
|
|
50
|
+
def title
|
|
51
|
+
browser.title
|
|
52
|
+
end
|
|
53
|
+
|
|
41
54
|
def current_url
|
|
42
55
|
browser.current_url
|
|
43
56
|
end
|
|
44
57
|
|
|
45
|
-
def
|
|
58
|
+
def find_xpath(selector)
|
|
46
59
|
browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
|
|
47
60
|
end
|
|
48
61
|
|
|
62
|
+
def find_css(selector)
|
|
63
|
+
browser.find_elements(:css, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
|
|
64
|
+
end
|
|
65
|
+
|
|
49
66
|
def wait?; true; end
|
|
50
67
|
def needs_server?; true; end
|
|
51
68
|
|
|
@@ -74,12 +91,29 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
74
91
|
end
|
|
75
92
|
end
|
|
76
93
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
94
|
+
##
|
|
95
|
+
#
|
|
96
|
+
# Webdriver supports frame name, id, index(zero-based) or {Capybara::Element} to find iframe
|
|
97
|
+
#
|
|
98
|
+
# @overload within_frame(index)
|
|
99
|
+
# @param [Integer] index index of a frame
|
|
100
|
+
# @overload within_frame(name_or_id)
|
|
101
|
+
# @param [String] name_or_id name or id of a frame
|
|
102
|
+
# @overload within_frame(element)
|
|
103
|
+
# @param [Capybara::Node::Base] a_node frame element
|
|
104
|
+
#
|
|
105
|
+
def within_frame(frame_handle)
|
|
106
|
+
@frame_handles[browser.window_handle] ||= []
|
|
107
|
+
frame_handle = frame_handle.native if frame_handle.is_a?(Capybara::Node::Base)
|
|
108
|
+
@frame_handles[browser.window_handle] << frame_handle
|
|
109
|
+
a=browser.switch_to.frame(frame_handle)
|
|
80
110
|
yield
|
|
81
111
|
ensure
|
|
82
|
-
|
|
112
|
+
# There doesnt appear to be any way in Webdriver to move back to a parent frame
|
|
113
|
+
# other than going back to the root and then reiterating down
|
|
114
|
+
@frame_handles[browser.window_handle].pop
|
|
115
|
+
browser.switch_to.default_content
|
|
116
|
+
@frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) }
|
|
83
117
|
end
|
|
84
118
|
|
|
85
119
|
def find_window( selector )
|
|
@@ -111,4 +145,5 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
|
111
145
|
def invalid_element_errors
|
|
112
146
|
[Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError]
|
|
113
147
|
end
|
|
148
|
+
|
|
114
149
|
end
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
2
|
-
def
|
|
2
|
+
def visible_text
|
|
3
3
|
# Selenium doesn't normalize Unicode whitespace.
|
|
4
4
|
Capybara::Helpers.normalize_whitespace(native.text)
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
+
def all_text
|
|
8
|
+
text = driver.browser.execute_script("return arguments[0].textContent", native)
|
|
9
|
+
Capybara::Helpers.normalize_whitespace(text)
|
|
10
|
+
end
|
|
11
|
+
|
|
7
12
|
def [](name)
|
|
8
13
|
native.attribute(name.to_s)
|
|
9
14
|
rescue Selenium::WebDriver::Error::WebDriverError
|
|
@@ -32,7 +37,8 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
|
32
37
|
path_names = value.to_s.empty? ? [] : value
|
|
33
38
|
native.send_keys(*path_names)
|
|
34
39
|
elsif tag_name == 'textarea' or tag_name == 'input'
|
|
35
|
-
|
|
40
|
+
#script can change a readonly element which user input cannot, so dont execute if readonly
|
|
41
|
+
driver.browser.execute_script "arguments[0].value = ''", native unless self[:readonly]
|
|
36
42
|
native.send_keys(value.to_s)
|
|
37
43
|
end
|
|
38
44
|
end
|
|
@@ -52,6 +58,10 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
|
52
58
|
native.click
|
|
53
59
|
end
|
|
54
60
|
|
|
61
|
+
def hover
|
|
62
|
+
driver.browser.action.move_to(native).perform
|
|
63
|
+
end
|
|
64
|
+
|
|
55
65
|
def drag_to(element)
|
|
56
66
|
driver.browser.action.drag_and_drop(native, element.native).perform
|
|
57
67
|
end
|
|
@@ -70,12 +80,20 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
|
70
80
|
selected and selected != "false"
|
|
71
81
|
end
|
|
72
82
|
|
|
83
|
+
def disabled?
|
|
84
|
+
!native.enabled?
|
|
85
|
+
end
|
|
86
|
+
|
|
73
87
|
alias :checked? :selected?
|
|
74
88
|
|
|
75
|
-
def
|
|
89
|
+
def find_xpath(locator)
|
|
76
90
|
native.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) }
|
|
77
91
|
end
|
|
78
|
-
|
|
92
|
+
|
|
93
|
+
def find_css(locator)
|
|
94
|
+
native.find_elements(:css, locator).map { |n| self.class.new(driver, n) }
|
|
95
|
+
end
|
|
96
|
+
|
|
79
97
|
def ==(other)
|
|
80
98
|
native == other.native
|
|
81
99
|
end
|
|
@@ -84,6 +102,6 @@ private
|
|
|
84
102
|
|
|
85
103
|
# a reference to the select node if this is an option node
|
|
86
104
|
def select_node
|
|
87
|
-
|
|
105
|
+
find_xpath('./ancestor::select').first
|
|
88
106
|
end
|
|
89
107
|
end
|
data/lib/capybara/server.rb
CHANGED
data/lib/capybara/session.rb
CHANGED
|
@@ -40,11 +40,13 @@ module Capybara
|
|
|
40
40
|
:body, :html, :current_url, :current_host, :evaluate_script, :source,
|
|
41
41
|
:visit, :within, :within_fieldset, :within_table, :within_frame,
|
|
42
42
|
:within_window, :current_path, :save_page, :save_and_open_page,
|
|
43
|
-
:save_screenshot, :reset_session!, :response_headers, :status_code
|
|
43
|
+
:save_screenshot, :reset_session!, :response_headers, :status_code,
|
|
44
|
+
:title, :has_title?, :has_no_title?, :current_scope
|
|
44
45
|
]
|
|
45
46
|
DSL_METHODS = NODE_METHODS + SESSION_METHODS
|
|
46
47
|
|
|
47
48
|
attr_reader :mode, :app, :server
|
|
49
|
+
attr_accessor :synchronized
|
|
48
50
|
|
|
49
51
|
def initialize(mode, app=nil)
|
|
50
52
|
@mode = mode
|
|
@@ -74,7 +76,7 @@ module Capybara
|
|
|
74
76
|
def reset!
|
|
75
77
|
driver.reset! if @touched
|
|
76
78
|
@touched = false
|
|
77
|
-
raise @server.error if @server and @server.error
|
|
79
|
+
raise @server.error if Capybara.raise_server_errors and @server and @server.error
|
|
78
80
|
ensure
|
|
79
81
|
@server.reset_error! if @server
|
|
80
82
|
end
|
|
@@ -137,6 +139,14 @@ module Capybara
|
|
|
137
139
|
driver.current_url
|
|
138
140
|
end
|
|
139
141
|
|
|
142
|
+
##
|
|
143
|
+
#
|
|
144
|
+
# @return [String] Title of the current page
|
|
145
|
+
#
|
|
146
|
+
def title
|
|
147
|
+
driver.title
|
|
148
|
+
end
|
|
149
|
+
|
|
140
150
|
##
|
|
141
151
|
#
|
|
142
152
|
# Navigate to the given URL. The URL can either be a relative URL or an absolute URL
|
|
@@ -243,13 +253,16 @@ module Capybara
|
|
|
243
253
|
|
|
244
254
|
##
|
|
245
255
|
#
|
|
246
|
-
# Execute the given block within the given iframe given
|
|
247
|
-
#
|
|
256
|
+
# Execute the given block within the given iframe using given frame name or index.
|
|
257
|
+
# May be supported by not all drivers. Drivers that support it, may provide additional options.
|
|
248
258
|
#
|
|
249
|
-
# @
|
|
259
|
+
# @overload within_frame(index)
|
|
260
|
+
# @param [Integer] index index of a frame
|
|
261
|
+
# @overload within_frame(name)
|
|
262
|
+
# @param [String] name name of a frame
|
|
250
263
|
#
|
|
251
|
-
def within_frame(
|
|
252
|
-
driver.within_frame(
|
|
264
|
+
def within_frame(frame_handle)
|
|
265
|
+
driver.within_frame(frame_handle) do
|
|
253
266
|
yield
|
|
254
267
|
end
|
|
255
268
|
end
|
|
@@ -304,7 +317,7 @@ module Capybara
|
|
|
304
317
|
|
|
305
318
|
FileUtils.mkdir_p(File.dirname(path))
|
|
306
319
|
|
|
307
|
-
File.open(path,'w') { |f| f.write(body) }
|
|
320
|
+
File.open(path,'w') { |f| f.write(Capybara::Helpers.inject_asset_host(body)) }
|
|
308
321
|
path
|
|
309
322
|
end
|
|
310
323
|
|
|
@@ -312,7 +325,7 @@ module Capybara
|
|
|
312
325
|
#
|
|
313
326
|
# Save a snapshot of the page and open it in a browser for inspection
|
|
314
327
|
#
|
|
315
|
-
# @param [String]
|
|
328
|
+
# @param [String] file_name The path to where it should be saved [optional]
|
|
316
329
|
#
|
|
317
330
|
def save_and_open_page(file_name=nil)
|
|
318
331
|
require "launchy"
|
|
@@ -338,7 +351,7 @@ module Capybara
|
|
|
338
351
|
NODE_METHODS.each do |method|
|
|
339
352
|
define_method method do |*args, &block|
|
|
340
353
|
@touched = true
|
|
341
|
-
|
|
354
|
+
current_scope.send(method, *args, &block)
|
|
342
355
|
end
|
|
343
356
|
end
|
|
344
357
|
|
|
@@ -346,12 +359,34 @@ module Capybara
|
|
|
346
359
|
%(#<Capybara::Session>)
|
|
347
360
|
end
|
|
348
361
|
|
|
349
|
-
|
|
362
|
+
def has_title?(content)
|
|
363
|
+
document.synchronize do
|
|
364
|
+
unless title.match(Capybara::Helpers.to_regexp(content))
|
|
365
|
+
raise ExpectationNotMet
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
return true
|
|
369
|
+
rescue Capybara::ExpectationNotMet
|
|
370
|
+
return false
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def has_no_title?(content)
|
|
374
|
+
document.synchronize do
|
|
375
|
+
if title.match(Capybara::Helpers.to_regexp(content))
|
|
376
|
+
raise ExpectationNotMet
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
return true
|
|
380
|
+
rescue Capybara::ExpectationNotMet
|
|
381
|
+
return false
|
|
382
|
+
end
|
|
350
383
|
|
|
351
|
-
def
|
|
384
|
+
def current_scope
|
|
352
385
|
scopes.last
|
|
353
386
|
end
|
|
354
387
|
|
|
388
|
+
private
|
|
389
|
+
|
|
355
390
|
def scopes
|
|
356
391
|
@scopes ||= [document]
|
|
357
392
|
end
|
|
@@ -18,6 +18,13 @@ $(function() {
|
|
|
18
18
|
}, 500);
|
|
19
19
|
return false;
|
|
20
20
|
});
|
|
21
|
+
$('#slow-click').click(function() {
|
|
22
|
+
var link = $(this);
|
|
23
|
+
setTimeout(function() {
|
|
24
|
+
$(link).after('<a id="slow-clicked" href="#">Slow link clicked</a>');
|
|
25
|
+
}, 4000);
|
|
26
|
+
return false;
|
|
27
|
+
});
|
|
21
28
|
$('#waiter').change(function() {
|
|
22
29
|
activeRequests = 1;
|
|
23
30
|
setTimeout(function() {
|
|
@@ -48,4 +55,9 @@ $(function() {
|
|
|
48
55
|
$('#the-list').html('<li>Foo</li><li>Bar</li>');
|
|
49
56
|
}, 250)
|
|
50
57
|
});
|
|
58
|
+
$('#change-title').click(function() {
|
|
59
|
+
setTimeout(function() {
|
|
60
|
+
$('title').text('changed title')
|
|
61
|
+
}, 250)
|
|
62
|
+
});
|
|
51
63
|
});
|
|
@@ -48,22 +48,23 @@ Capybara::SpecHelper.spec "#all" do
|
|
|
48
48
|
@session.all('h1').first.text.should == 'This is a test'
|
|
49
49
|
@session.all("input[id='test_field']").first[:value].should == 'monkey'
|
|
50
50
|
end
|
|
51
|
-
after { Capybara.default_selector = :xpath }
|
|
52
51
|
end
|
|
53
52
|
|
|
54
53
|
context "with visible filter" do
|
|
55
|
-
|
|
56
|
-
it "should only find visible nodes" do
|
|
57
|
-
@session.all(:css, "a.simple").should have(2).elements
|
|
54
|
+
it "should only find visible nodes when true" do
|
|
58
55
|
@session.all(:css, "a.simple", :visible => true).should have(1).elements
|
|
59
|
-
Capybara.ignore_hidden_elements = true
|
|
60
|
-
@session.all(:css, "a.simple").should have(1).elements
|
|
61
56
|
end
|
|
62
57
|
|
|
63
|
-
it "should
|
|
64
|
-
Capybara.ignore_hidden_elements = true
|
|
58
|
+
it "should find nodes regardless of whether they are invisible when false" do
|
|
65
59
|
@session.all(:css, "a.simple", :visible => false).should have(2).elements
|
|
66
60
|
end
|
|
61
|
+
|
|
62
|
+
it "should default to Capybara.ignore_hidden_elements" do
|
|
63
|
+
Capybara.ignore_hidden_elements = true
|
|
64
|
+
@session.all(:css, "a.simple").should have(1).elements
|
|
65
|
+
Capybara.ignore_hidden_elements = false
|
|
66
|
+
@session.all(:css, "a.simple").should have(2).elements
|
|
67
|
+
end
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
context "within a scope" do
|
|
@@ -87,4 +87,18 @@ Capybara::SpecHelper.spec "#attach_file" do
|
|
|
87
87
|
expect { @session.attach_file('Image', '/no_such_file.png') }.to raise_error(Capybara::FileNotFound)
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
+
|
|
91
|
+
context "with :exact option" do
|
|
92
|
+
it "should set a file path by partial label when false" do
|
|
93
|
+
@session.attach_file "Imag", __FILE__, :exact => false
|
|
94
|
+
@session.click_button('awesome')
|
|
95
|
+
extract_results(@session)['image'].should == File.basename(__FILE__)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "not allow partial matches when true" do
|
|
99
|
+
expect do
|
|
100
|
+
@session.attach_file "Imag", __FILE__, :exact => true
|
|
101
|
+
end.to raise_error(Capybara::ElementNotFound)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
90
104
|
end
|
|
@@ -82,4 +82,18 @@ Capybara::SpecHelper.spec "#check" do
|
|
|
82
82
|
end.to raise_error(Capybara::ElementNotFound)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
|
+
|
|
86
|
+
context "with :exact option" do
|
|
87
|
+
it "should accept partial matches when false" do
|
|
88
|
+
@session.check('Ham', :exact => false)
|
|
89
|
+
@session.click_button('awesome')
|
|
90
|
+
extract_results(@session)['pets'].should include('hamster')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "should not accept partial matches when true" do
|
|
94
|
+
expect do
|
|
95
|
+
@session.check('Ham', :exact => true)
|
|
96
|
+
end.to raise_error(Capybara::ElementNotFound)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
85
99
|
end
|
|
@@ -37,4 +37,18 @@ Capybara::SpecHelper.spec "#choose" do
|
|
|
37
37
|
end.to raise_error(Capybara::ElementNotFound)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
|
+
|
|
41
|
+
context "with :exact option" do
|
|
42
|
+
it "should accept partial matches when false" do
|
|
43
|
+
@session.choose("Mal", :exact => false)
|
|
44
|
+
@session.click_button('awesome')
|
|
45
|
+
extract_results(@session)['gender'].should == 'male'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should not accept partial matches when true" do
|
|
49
|
+
expect do
|
|
50
|
+
@session.choose("Mal", :exact => true)
|
|
51
|
+
end.to raise_error(Capybara::ElementNotFound)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
40
54
|
end
|
|
@@ -63,7 +63,7 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
it "should serialise and submit color fields" do
|
|
66
|
-
@results['html5_color'].should == '#FFFFFF'
|
|
66
|
+
@results['html5_color'].upcase.should == '#FFFFFF'
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
69
|
|
|
@@ -162,6 +162,69 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
|
162
162
|
end
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
+
context "with fields associated with the form using the form attribute" do
|
|
166
|
+
before do
|
|
167
|
+
@session.click_button('submit_form1')
|
|
168
|
+
@results = extract_results(@session)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "should serialize and submit text fields" do
|
|
172
|
+
@results['outside_input'].should == 'outside_input'
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "should serialize text areas" do
|
|
176
|
+
@results['outside_textarea'].should == 'Some text here'
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "should serialize select tags" do
|
|
180
|
+
@results['outside_select'].should == 'Ruby'
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it "should not serliaze fields associated with a different form" do
|
|
184
|
+
@results['for_form2'].should be_nil
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
context "with submit button outside the form defined by <button> tag" do
|
|
190
|
+
before do
|
|
191
|
+
@session.click_button('outside_button')
|
|
192
|
+
@results = extract_results(@session)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "should submit the associated form" do
|
|
196
|
+
@results['which_form'].should == 'form2'
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "should submit the button that was clicked, but not other buttons" do
|
|
200
|
+
@results['outside_button'].should == 'outside_button'
|
|
201
|
+
@results['unused'].should be_nil
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
context "with submit button outside the form defined by <input type='submit'> tag" do
|
|
206
|
+
before do
|
|
207
|
+
@session.click_button('outside_submit')
|
|
208
|
+
@results = extract_results(@session)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "should submit the associated form" do
|
|
212
|
+
@results['which_form'].should == 'form1'
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "should submit the button that was clicked, but not other buttons" do
|
|
216
|
+
@results['outside_submit'].should == 'outside_submit'
|
|
217
|
+
@results['submit_form1'].should be_nil
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
context "with submit button for form1 located within form2" do
|
|
222
|
+
it "should submit the form associated with the button" do
|
|
223
|
+
@session.click_button('other_form_button')
|
|
224
|
+
extract_results(@session)['which_form'].should == "form1"
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
165
228
|
context "with alt given on an image button" do
|
|
166
229
|
it "should submit the associated form" do
|
|
167
230
|
@session.click_button('oh hai thar')
|
|
@@ -332,4 +395,17 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
|
332
395
|
addresses[1]["city"].should == 'Mikolaiv'
|
|
333
396
|
addresses[1]["country"].should == 'Ukraine'
|
|
334
397
|
end
|
|
398
|
+
|
|
399
|
+
context "with :exact option" do
|
|
400
|
+
it "should accept partial matches when false" do
|
|
401
|
+
@session.click_button('What an Awesome', :exact => false)
|
|
402
|
+
extract_results(@session)['first_name'].should == 'John'
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
it "should not accept partial matches when true" do
|
|
406
|
+
expect do
|
|
407
|
+
@session.click_button('What an Awesome', :exact => true)
|
|
408
|
+
end.to raise_error(Capybara::ElementNotFound)
|
|
409
|
+
end
|
|
410
|
+
end
|
|
335
411
|
end
|