bbc-capybara 1.1.2
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.txt +325 -0
- data/License.txt +22 -0
- data/README.md +815 -0
- data/lib/capybara.rb +368 -0
- data/lib/capybara/cucumber.rb +25 -0
- data/lib/capybara/driver/base.rb +64 -0
- data/lib/capybara/driver/node.rb +74 -0
- data/lib/capybara/dsl.rb +50 -0
- data/lib/capybara/node/actions.rb +146 -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 +154 -0
- data/lib/capybara/node/matchers.rb +442 -0
- data/lib/capybara/node/simple.rb +132 -0
- data/lib/capybara/query.rb +63 -0
- data/lib/capybara/rack_test/browser.rb +126 -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 +121 -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 +152 -0
- data/lib/capybara/selector.rb +156 -0
- data/lib/capybara/selenium/driver.rb +169 -0
- data/lib/capybara/selenium/node.rb +91 -0
- data/lib/capybara/server.rb +87 -0
- data/lib/capybara/session.rb +322 -0
- data/lib/capybara/spec/driver.rb +329 -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/jquery-ui.js +791 -0
- data/lib/capybara/spec/public/jquery.js +9046 -0
- data/lib/capybara/spec/public/test.js +43 -0
- data/lib/capybara/spec/session.rb +148 -0
- data/lib/capybara/spec/session/all_spec.rb +78 -0
- data/lib/capybara/spec/session/attach_file_spec.rb +76 -0
- data/lib/capybara/spec/session/check_spec.rb +68 -0
- data/lib/capybara/spec/session/choose_spec.rb +29 -0
- data/lib/capybara/spec/session/click_button_spec.rb +305 -0
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +37 -0
- data/lib/capybara/spec/session/click_link_spec.rb +120 -0
- data/lib/capybara/spec/session/current_url_spec.rb +83 -0
- data/lib/capybara/spec/session/fill_in_spec.rb +127 -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 +168 -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_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 +34 -0
- data/lib/capybara/spec/session/has_text_spec.rb +138 -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 +312 -0
- data/lib/capybara/spec/session/response_code.rb +19 -0
- data/lib/capybara/spec/session/select_spec.rb +119 -0
- data/lib/capybara/spec/session/text_spec.rb +24 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
- data/lib/capybara/spec/session/unselect_spec.rb +67 -0
- data/lib/capybara/spec/session/within_spec.rb +178 -0
- data/lib/capybara/spec/test_app.rb +156 -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 +366 -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 +62 -0
- data/lib/capybara/spec/views/with_html.erb +75 -0
- data/lib/capybara/spec/views/with_html_entities.erb +1 -0
- data/lib/capybara/spec/views/with_js.erb +53 -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 +45 -0
- data/lib/capybara/util/timeout.rb +27 -0
- data/lib/capybara/version.rb +3 -0
- data/spec/basic_node_spec.rb +89 -0
- data/spec/capybara_spec.rb +46 -0
- data/spec/driver/rack_test_driver_spec.rb +90 -0
- data/spec/driver/selenium_driver_spec.rb +55 -0
- data/spec/dsl_spec.rb +255 -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 +43 -0
- data/spec/rspec/matchers_spec.rb +564 -0
- data/spec/rspec_spec.rb +51 -0
- data/spec/save_and_open_page_spec.rb +155 -0
- data/spec/server_spec.rb +74 -0
- data/spec/session/rack_test_session_spec.rb +61 -0
- data/spec/session/selenium_session_spec.rb +26 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/timeout_spec.rb +28 -0
- metadata +297 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
class Capybara::RackTest::Node < Capybara::Driver::Node
|
|
2
|
+
def text
|
|
3
|
+
unnormalized_text.strip.gsub(/\s+/, ' ')
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def [](name)
|
|
7
|
+
string_node[name]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def value
|
|
11
|
+
string_node.value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def set(value)
|
|
15
|
+
if tag_name == 'input' and type == 'radio'
|
|
16
|
+
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
|
|
17
|
+
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
|
|
18
|
+
native['checked'] = 'checked'
|
|
19
|
+
elsif tag_name == 'input' and type == 'checkbox'
|
|
20
|
+
if value && !native['checked']
|
|
21
|
+
native['checked'] = 'checked'
|
|
22
|
+
elsif !value && native['checked']
|
|
23
|
+
native.remove_attribute('checked')
|
|
24
|
+
end
|
|
25
|
+
elsif tag_name == 'input'
|
|
26
|
+
if (type == 'text' || type == 'password') && self[:maxlength] &&
|
|
27
|
+
!self[:maxlength].empty?
|
|
28
|
+
# Browser behavior for maxlength="0" is inconsistent, so we stick with
|
|
29
|
+
# Firefox, allowing no input
|
|
30
|
+
value = value[0...self[:maxlength].to_i]
|
|
31
|
+
end
|
|
32
|
+
native['value'] = value.to_s
|
|
33
|
+
elsif tag_name == "textarea"
|
|
34
|
+
native.content = value.to_s
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def select_option
|
|
39
|
+
if select_node['multiple'] != 'multiple'
|
|
40
|
+
select_node.find(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
|
|
41
|
+
end
|
|
42
|
+
native["selected"] = 'selected'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def unselect_option
|
|
46
|
+
if select_node['multiple'] != 'multiple'
|
|
47
|
+
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
|
|
48
|
+
end
|
|
49
|
+
native.remove_attribute('selected')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def click
|
|
53
|
+
if tag_name == 'a'
|
|
54
|
+
method = self["data-method"] if driver.options[:respect_data_method]
|
|
55
|
+
method ||= :get
|
|
56
|
+
driver.follow(method, self[:href].to_s)
|
|
57
|
+
elsif (tag_name == 'input' and %w(submit image).include?(type)) or
|
|
58
|
+
((tag_name == 'button') and type.nil? or type == "submit")
|
|
59
|
+
Capybara::RackTest::Form.new(driver, form).submit(self)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def tag_name
|
|
64
|
+
native.node_name
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def visible?
|
|
68
|
+
string_node.visible?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def checked?
|
|
72
|
+
string_node.checked?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def selected?
|
|
76
|
+
string_node.selected?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def path
|
|
80
|
+
native.path
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def find(locator)
|
|
84
|
+
native.xpath(locator).map { |n| self.class.new(driver, n) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
protected
|
|
88
|
+
|
|
89
|
+
def unnormalized_text
|
|
90
|
+
if !visible?
|
|
91
|
+
''
|
|
92
|
+
elsif native.text?
|
|
93
|
+
native.text
|
|
94
|
+
elsif native.element?
|
|
95
|
+
native.children.map do |child|
|
|
96
|
+
Capybara::RackTest::Node.new(driver, child).unnormalized_text
|
|
97
|
+
end.join
|
|
98
|
+
else
|
|
99
|
+
''
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
def string_node
|
|
106
|
+
@string_node ||= Capybara::Node::Simple.new(native)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# a reference to the select node if this is an option node
|
|
110
|
+
def select_node
|
|
111
|
+
find('./ancestor::select').first
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def type
|
|
115
|
+
native[:type]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def form
|
|
119
|
+
native.ancestors('form').first
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -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,152 @@
|
|
|
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
|
+
query.failure_message(:assert, @actual)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def failure_message_for_should_not
|
|
23
|
+
query.negative_failure_message(:assert, @actual)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def description
|
|
27
|
+
"has #{query.description}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def wrap(actual)
|
|
31
|
+
if actual.respond_to?("has_selector?")
|
|
32
|
+
actual
|
|
33
|
+
else
|
|
34
|
+
Capybara.string(actual.to_s)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def query
|
|
39
|
+
@query ||= Capybara::Query.new(*@args)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class HaveMatcher
|
|
44
|
+
attr_reader :name, :locator, :options, :failure_message, :actual
|
|
45
|
+
|
|
46
|
+
def initialize(name, locator, options={}, &block)
|
|
47
|
+
@name = name
|
|
48
|
+
@locator = locator
|
|
49
|
+
@options = options
|
|
50
|
+
@failure_message = block
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def arguments
|
|
54
|
+
if options.empty? then [locator] else [locator, options] end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def matches?(actual)
|
|
58
|
+
@actual = wrap(actual)
|
|
59
|
+
@actual.send(:"has_#{name}?", *arguments)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def does_not_match?(actual)
|
|
63
|
+
@actual = wrap(actual)
|
|
64
|
+
@actual.send(:"has_no_#{name}?", *arguments)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def failure_message_for_should
|
|
68
|
+
if failure_message
|
|
69
|
+
failure_message.call(actual, self)
|
|
70
|
+
elsif(@options[:count])
|
|
71
|
+
"expected #{selector_name} to be returned #{@options[:count]} times"
|
|
72
|
+
else
|
|
73
|
+
"expected #{selector_name} to return something"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def failure_message_for_should_not
|
|
78
|
+
"expected #{selector_name} not to return anything"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def description
|
|
82
|
+
"has #{selector_name}"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def selector_name
|
|
86
|
+
selector_name = "#{name} #{locator.inspect}"
|
|
87
|
+
selector_name << " with text #{options[:text].inspect}" if options[:text]
|
|
88
|
+
selector_name
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def wrap(actual)
|
|
92
|
+
if actual.respond_to?("has_selector?")
|
|
93
|
+
actual
|
|
94
|
+
else
|
|
95
|
+
Capybara.string(actual.to_s)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def have_selector(*args)
|
|
101
|
+
HaveSelector.new(*args)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def have_xpath(xpath, options={})
|
|
105
|
+
HaveMatcher.new(:xpath, xpath, options)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def have_css(css, options={})
|
|
109
|
+
HaveMatcher.new(:css, css, options)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def have_content(text)
|
|
113
|
+
HaveMatcher.new(:content, text.to_s) do |page, matcher|
|
|
114
|
+
%(expected there to be content #{matcher.locator.inspect} in #{page.text.inspect})
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def have_text(text)
|
|
119
|
+
HaveMatcher.new(:text, text.to_s) do |page, matcher|
|
|
120
|
+
%(expected there to be text #{matcher.locator.inspect} in #{page.text.inspect})
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def have_link(locator, options={})
|
|
125
|
+
HaveMatcher.new(:link, locator, options)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def have_button(locator)
|
|
129
|
+
HaveMatcher.new(:button, locator)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def have_field(locator, options={})
|
|
133
|
+
HaveMatcher.new(:field, locator, options)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def have_checked_field(locator)
|
|
137
|
+
HaveMatcher.new(:checked_field, locator)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def have_unchecked_field(locator)
|
|
141
|
+
HaveMatcher.new(:unchecked_field, locator)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def have_select(locator, options={})
|
|
145
|
+
HaveMatcher.new(:select, locator, options)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def have_table(locator, options={})
|
|
149
|
+
HaveMatcher.new(:table, locator, options)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
module Capybara
|
|
2
|
+
class Selector
|
|
3
|
+
attr_reader :name, :custom_filters
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
def all
|
|
8
|
+
@selectors ||= {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def add(name, &block)
|
|
12
|
+
all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def remove(name)
|
|
16
|
+
all.delete(name.to_sym)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def initialize(name, &block)
|
|
21
|
+
@name = name
|
|
22
|
+
@custom_filters = {}
|
|
23
|
+
@match = nil
|
|
24
|
+
@failure_message = nil
|
|
25
|
+
instance_eval(&block)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def xpath(&block)
|
|
29
|
+
@xpath = block if block
|
|
30
|
+
@xpath
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Same as xpath, but wrap in XPath.css().
|
|
34
|
+
def css(&block)
|
|
35
|
+
if block
|
|
36
|
+
@xpath = xpath { |*args| XPath.css(block.call(*args)) }
|
|
37
|
+
end
|
|
38
|
+
@xpath
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def match(&block)
|
|
42
|
+
@match = block if block
|
|
43
|
+
@match
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def failure_message(&block)
|
|
47
|
+
@failure_message = block if block
|
|
48
|
+
@failure_message
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def call(locator)
|
|
52
|
+
@xpath.call(locator)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def match?(locator)
|
|
56
|
+
@match and @match.call(locator)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def filter(name, &block)
|
|
60
|
+
@custom_filters[name] = block
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
Capybara.add_selector(:xpath) do
|
|
66
|
+
xpath { |xpath| xpath }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
Capybara.add_selector(:css) do
|
|
70
|
+
css { |css| css }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
Capybara.add_selector(:id) do
|
|
74
|
+
xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
|
|
75
|
+
match { |value| value.is_a?(Symbol) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
Capybara.add_selector(:field) do
|
|
79
|
+
xpath { |locator| XPath::HTML.field(locator) }
|
|
80
|
+
filter(:checked) { |node, value| not(value ^ node.checked?) }
|
|
81
|
+
filter(:unchecked) { |node, value| (value ^ node.checked?) }
|
|
82
|
+
filter(:with) { |node, with| node.value == with }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
Capybara.add_selector(:fieldset) do
|
|
86
|
+
xpath { |locator| XPath::HTML.fieldset(locator) }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
Capybara.add_selector(:link_or_button) do
|
|
90
|
+
xpath { |locator| XPath::HTML.link_or_button(locator) }
|
|
91
|
+
failure_message { |node, selector| "no link or button '#{selector.locator}' found" }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
Capybara.add_selector(:link) do
|
|
95
|
+
xpath { |locator| XPath::HTML.link(locator) }
|
|
96
|
+
failure_message { |node, selector| "no link with title, id or text '#{selector.locator}' found" }
|
|
97
|
+
filter(:href) do |node, href|
|
|
98
|
+
node.first(:xpath, XPath.axis(:self)[XPath.attr(:href).equals(href)])
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
Capybara.add_selector(:button) do
|
|
103
|
+
xpath { |locator| XPath::HTML.button(locator) }
|
|
104
|
+
failure_message { |node, selector| "no button with value or id or text '#{selector.locator}' found" }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
Capybara.add_selector(:fillable_field) do
|
|
108
|
+
xpath { |locator| XPath::HTML.fillable_field(locator) }
|
|
109
|
+
failure_message { |node, selector| "no text field, text area or password field with id, name, or label '#{selector.locator}' found" }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
Capybara.add_selector(:radio_button) do
|
|
113
|
+
xpath { |locator| XPath::HTML.radio_button(locator) }
|
|
114
|
+
failure_message { |node, selector| "no radio button with id, name, or label '#{selector.locator}' found" }
|
|
115
|
+
filter(:checked) { |node, value| not(value ^ node.checked?) }
|
|
116
|
+
filter(:unchecked) { |node, value| (value ^ node.checked?) }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
Capybara.add_selector(:checkbox) do
|
|
120
|
+
xpath { |locator| XPath::HTML.checkbox(locator) }
|
|
121
|
+
failure_message { |node, selector| "no checkbox with id, name, or label '#{selector.locator}' found" }
|
|
122
|
+
filter(:checked) { |node, value| not(value ^ node.checked?) }
|
|
123
|
+
filter(:unchecked) { |node, value| (value ^ node.checked?) }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
Capybara.add_selector(:select) do
|
|
127
|
+
xpath { |locator| XPath::HTML.select(locator) }
|
|
128
|
+
failure_message { |node, selector| "no select box with id, name, or label '#{selector.locator}' found" }
|
|
129
|
+
filter(:options) { |node, options| options.all? { |option| node.first(:option, option) } }
|
|
130
|
+
filter(:selected) do |node, selected|
|
|
131
|
+
actual = node.all(:xpath, './/option').select { |option| option.selected? }.map { |option| option.text }
|
|
132
|
+
([selected].flatten - actual).empty?
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
Capybara.add_selector(:option) do
|
|
137
|
+
xpath { |locator| XPath::HTML.option(locator) }
|
|
138
|
+
failure_message do |node, selector|
|
|
139
|
+
"no option with text '#{selector.locator}'".tap do |message|
|
|
140
|
+
message << " in the select box" if node.tag_name == 'select'
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
Capybara.add_selector(:file_field) do
|
|
146
|
+
xpath { |locator| XPath::HTML.file_field(locator) }
|
|
147
|
+
failure_message { |node, selector| "no file field with id, name, or label '#{selector.locator}' found" }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
Capybara.add_selector(:content) do
|
|
151
|
+
xpath { |content| XPath::HTML.content(content) }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
Capybara.add_selector(:table) do
|
|
155
|
+
xpath { |locator| XPath::HTML.table(locator) }
|
|
156
|
+
end
|