capybara 2.0.3 → 2.1.0.beta1
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.tar.gz.sig +0 -0
- data/History.md +73 -0
- data/README.md +52 -5
- data/lib/capybara.rb +44 -62
- 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 +24 -19
- data/lib/capybara/node/base.rb +25 -32
- data/lib/capybara/node/document.rb +6 -2
- data/lib/capybara/node/element.rb +45 -7
- data/lib/capybara/node/finders.rb +48 -21
- data/lib/capybara/node/matchers.rb +38 -21
- data/lib/capybara/node/simple.rb +29 -7
- 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 +92 -36
- data/lib/capybara/rails.rb +1 -2
- 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 -6
- data/lib/capybara/selenium/node.rb +23 -5
- data/lib/capybara/session.rb +46 -11
- 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 +14 -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 +258 -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 +43 -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 +6 -1
- 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 +21 -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/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 +8 -8
- data/spec/spec_helper.rb +2 -1
- metadata +83 -23
- metadata.gz.sig +0 -0
data/lib/capybara/rails.rb
CHANGED
@@ -3,7 +3,7 @@ require 'capybara/dsl'
|
|
3
3
|
|
4
4
|
Capybara.app = Rack::Builder.new do
|
5
5
|
map "/" do
|
6
|
-
if
|
6
|
+
if Rails.version.to_f >= 3.0
|
7
7
|
run Rails.application
|
8
8
|
else # Rails 2
|
9
9
|
use Rails::Rack::Static
|
@@ -12,7 +12,6 @@ Capybara.app = Rack::Builder.new do
|
|
12
12
|
end
|
13
13
|
end.to_app
|
14
14
|
|
15
|
-
Capybara.asset_root = Rails.root.join('public')
|
16
15
|
Capybara.save_and_open_page_path = Rails.root.join('tmp/capybara')
|
17
16
|
|
18
17
|
# Override default rack_test driver to respect data-method attributes.
|
data/lib/capybara/result.rb
CHANGED
@@ -1,6 +1,23 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
module Capybara
|
4
|
+
|
5
|
+
##
|
6
|
+
# A {Capybara::Result} represents a collection of {Capybara::Element} on the page. It is possible to interact with this
|
7
|
+
# collection similar to an Array because it implements Enumerable and offers the following Array methods through delegation:
|
8
|
+
#
|
9
|
+
# * []
|
10
|
+
# * each()
|
11
|
+
# * at()
|
12
|
+
# * size()
|
13
|
+
# * count()
|
14
|
+
# * length()
|
15
|
+
# * first()
|
16
|
+
# * last()
|
17
|
+
# * empty?()
|
18
|
+
#
|
19
|
+
# @see Capybara::Element
|
20
|
+
#
|
4
21
|
class Result
|
5
22
|
include Enumerable
|
6
23
|
extend Forwardable
|
@@ -15,36 +32,13 @@ module Capybara
|
|
15
32
|
def_delegators :@result, :each, :[], :at, :size, :count, :length, :first, :last, :empty?
|
16
33
|
|
17
34
|
def matches_count?
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
def find!
|
22
|
-
raise find_error if @result.size != 1
|
23
|
-
@result.first
|
24
|
-
end
|
25
|
-
|
26
|
-
def find_error
|
27
|
-
if @result.size == 0
|
28
|
-
Capybara::ElementNotFound.new("Unable to find #{@query.description}")
|
29
|
-
elsif @result.size > 1
|
30
|
-
Capybara::Ambiguous.new("Ambiguous match, found #{size} elements matching #{@query.description}")
|
31
|
-
end
|
35
|
+
Capybara::Helpers.matches_count?(@result.size, @query.options)
|
32
36
|
end
|
33
37
|
|
34
38
|
def failure_message
|
35
|
-
message =
|
36
|
-
"expected #{@query.description} to be found #{@query.options[:count]} #{declension("time", "times", @query.options[:count])}"
|
37
|
-
elsif @query.options[:between]
|
38
|
-
"expected #{@query.description} to be found between #{@query.options[:between].first} and #{@query.options[:between].last} times"
|
39
|
-
elsif @query.options[:maximum]
|
40
|
-
"expected #{@query.description} to be found at most #{@query.options[:maximum]} #{declension("time", "times", @query.options[:maximum])}"
|
41
|
-
elsif @query.options[:minimum]
|
42
|
-
"expected #{@query.description} to be found at least #{@query.options[:minimum]} #{declension("time", "times", @query.options[:minimum])}"
|
43
|
-
else
|
44
|
-
"expected to find #{@query.description}"
|
45
|
-
end
|
39
|
+
message = Capybara::Helpers.failure_message(@query.description, @query.options)
|
46
40
|
if count > 0
|
47
|
-
message << ", found #{count} #{declension("match", "matches")}: " << @result.map(&:text).map(&:inspect).join(", ")
|
41
|
+
message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << @result.map(&:text).map(&:inspect).join(", ")
|
48
42
|
else
|
49
43
|
message << " but there were no matches"
|
50
44
|
end
|
@@ -56,17 +50,7 @@ module Capybara
|
|
56
50
|
end
|
57
51
|
|
58
52
|
def negative_failure_message
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def declension(singular, plural, count=count)
|
65
|
-
if count == 1
|
66
|
-
singular
|
67
|
-
else
|
68
|
-
plural
|
69
|
-
end
|
53
|
+
failure_message.sub(/(to be found|to find)/, 'not \1')
|
70
54
|
end
|
71
55
|
end
|
72
56
|
end
|
@@ -1,6 +1,16 @@
|
|
1
1
|
module Capybara
|
2
2
|
module RSpecMatchers
|
3
|
-
class
|
3
|
+
class Matcher
|
4
|
+
def wrap(actual)
|
5
|
+
if actual.respond_to?("has_selector?")
|
6
|
+
actual
|
7
|
+
else
|
8
|
+
Capybara.string(actual.to_s)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class HaveSelector < Matcher
|
4
14
|
def initialize(*args)
|
5
15
|
@args = args
|
6
16
|
end
|
@@ -17,59 +27,77 @@ module Capybara
|
|
17
27
|
"have #{query.description}"
|
18
28
|
end
|
19
29
|
|
20
|
-
def wrap(actual)
|
21
|
-
if actual.respond_to?("has_selector?")
|
22
|
-
actual
|
23
|
-
else
|
24
|
-
Capybara.string(actual.to_s)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
30
|
def query
|
29
31
|
@query ||= Capybara::Query.new(*@args)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
class HaveText
|
34
|
-
attr_reader :
|
35
|
+
class HaveText < Matcher
|
36
|
+
attr_reader :type, :content, :options
|
35
37
|
|
36
|
-
def initialize(
|
37
|
-
@
|
38
|
+
def initialize(*args)
|
39
|
+
@type = args.shift if args.first.is_a?(Symbol)
|
40
|
+
@content = args.shift
|
41
|
+
@options = (args.first.is_a?(Hash))? args.first : {}
|
38
42
|
end
|
39
43
|
|
40
44
|
def matches?(actual)
|
41
45
|
@actual = wrap(actual)
|
42
|
-
@actual.has_text?(
|
46
|
+
@actual.has_text?(type, content, options)
|
43
47
|
end
|
44
48
|
|
45
49
|
def does_not_match?(actual)
|
46
50
|
@actual = wrap(actual)
|
47
|
-
@actual.has_no_text?(
|
51
|
+
@actual.has_no_text?(type, content, options)
|
48
52
|
end
|
49
53
|
|
50
54
|
def failure_message_for_should
|
51
|
-
|
55
|
+
message = Capybara::Helpers.failure_message(description, options)
|
56
|
+
message << " in #{format(@actual.text(type))}"
|
57
|
+
message
|
52
58
|
end
|
53
59
|
|
54
60
|
def failure_message_for_should_not
|
55
|
-
|
61
|
+
failure_message_for_should.sub(/(to find)/, 'not \1')
|
56
62
|
end
|
57
63
|
|
58
64
|
def description
|
59
|
-
"
|
65
|
+
"text #{format(content)}"
|
60
66
|
end
|
61
67
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
+
def format(content)
|
69
|
+
content = Capybara::Helpers.normalize_whitespace(content) unless content.is_a? Regexp
|
70
|
+
content.inspect
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class HaveTitle < Matcher
|
75
|
+
attr_reader :title
|
76
|
+
|
77
|
+
def initialize(title)
|
78
|
+
@title = title
|
68
79
|
end
|
69
80
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
81
|
+
def matches?(actual)
|
82
|
+
@actual = wrap(actual)
|
83
|
+
@actual.has_title?(title)
|
84
|
+
end
|
85
|
+
|
86
|
+
def does_not_match?(actual)
|
87
|
+
@actual = wrap(actual)
|
88
|
+
@actual.has_no_title?(title)
|
89
|
+
end
|
90
|
+
|
91
|
+
def failure_message_for_should
|
92
|
+
"expected there to be title #{title.inspect} in #{@actual.title.inspect}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def failure_message_for_should_not
|
96
|
+
"expected there not to be title #{title.inspect} in #{@actual.title.inspect}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def description
|
100
|
+
"have title #{title.inspect}"
|
73
101
|
end
|
74
102
|
end
|
75
103
|
|
@@ -85,12 +113,13 @@ module Capybara
|
|
85
113
|
HaveSelector.new(:css, css, options)
|
86
114
|
end
|
87
115
|
|
88
|
-
def
|
89
|
-
HaveText.new(
|
116
|
+
def have_text(*args)
|
117
|
+
HaveText.new(*args)
|
90
118
|
end
|
119
|
+
alias_method :have_content, :have_text
|
91
120
|
|
92
|
-
def
|
93
|
-
|
121
|
+
def have_title(title)
|
122
|
+
HaveTitle.new(title)
|
94
123
|
end
|
95
124
|
|
96
125
|
def have_link(locator, options={})
|
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,4 +1,13 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'selenium-webdriver'
|
3
|
+
rescue LoadError => e
|
4
|
+
if e.message =~ /selenium-webdriver/
|
5
|
+
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."
|
6
|
+
else
|
7
|
+
raise e
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
2
11
|
|
3
12
|
class Capybara::Selenium::Driver < Capybara::Driver::Base
|
4
13
|
DEFAULT_OPTIONS = {
|
@@ -27,6 +36,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
27
36
|
@app = app
|
28
37
|
@browser = nil
|
29
38
|
@exit_status = nil
|
39
|
+
@frame_handles = {}
|
30
40
|
@options = DEFAULT_OPTIONS.merge(options)
|
31
41
|
end
|
32
42
|
|
@@ -38,14 +48,22 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
38
48
|
browser.page_source
|
39
49
|
end
|
40
50
|
|
51
|
+
def title
|
52
|
+
browser.title
|
53
|
+
end
|
54
|
+
|
41
55
|
def current_url
|
42
56
|
browser.current_url
|
43
57
|
end
|
44
58
|
|
45
|
-
def
|
59
|
+
def find_xpath(selector)
|
46
60
|
browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
|
47
61
|
end
|
48
62
|
|
63
|
+
def find_css(selector)
|
64
|
+
browser.find_elements(:css, selector).map { |node| Capybara::Selenium::Node.new(self, node) }
|
65
|
+
end
|
66
|
+
|
49
67
|
def wait?; true; end
|
50
68
|
def needs_server?; true; end
|
51
69
|
|
@@ -74,12 +92,29 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
74
92
|
end
|
75
93
|
end
|
76
94
|
|
77
|
-
|
78
|
-
|
79
|
-
|
95
|
+
##
|
96
|
+
#
|
97
|
+
# Webdriver supports frame name, id, index(zero-based) or {Capybara::Element} to find iframe
|
98
|
+
#
|
99
|
+
# @overload within_frame(index)
|
100
|
+
# @param [Integer] index index of a frame
|
101
|
+
# @overload within_frame(name_or_id)
|
102
|
+
# @param [String] name_or_id name or id of a frame
|
103
|
+
# @overload within_frame(element)
|
104
|
+
# @param [Capybara::Node::Base] a_node frame element
|
105
|
+
#
|
106
|
+
def within_frame(frame_handle)
|
107
|
+
@frame_handles[browser.window_handle] ||= []
|
108
|
+
frame_handle = frame_handle.native if frame_handle.is_a?(Capybara::Node::Base)
|
109
|
+
@frame_handles[browser.window_handle] << frame_handle
|
110
|
+
a=browser.switch_to.frame(frame_handle)
|
80
111
|
yield
|
81
112
|
ensure
|
82
|
-
|
113
|
+
# There doesnt appear to be any way in Webdriver to move back to a parent frame
|
114
|
+
# other than going back to the root and then reiterating down
|
115
|
+
@frame_handles[browser.window_handle].pop
|
116
|
+
browser.switch_to.default_content
|
117
|
+
@frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) }
|
83
118
|
end
|
84
119
|
|
85
120
|
def find_window( selector )
|
@@ -111,4 +146,5 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
111
146
|
def invalid_element_errors
|
112
147
|
[Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError]
|
113
148
|
end
|
149
|
+
|
114
150
|
end
|