capybara 2.5.0 → 2.18.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.
- checksums.yaml +5 -5
- data/.yard/templates_custom/default/class/html/selectors.erb +38 -0
- data/.yard/templates_custom/default/class/html/setup.rb +17 -0
- data/.yard/yard_extensions.rb +78 -0
- data/.yardopts +1 -0
- data/History.md +413 -10
- data/License.txt +1 -1
- data/README.md +237 -130
- data/lib/capybara/config.rb +132 -0
- data/lib/capybara/cucumber.rb +3 -1
- data/lib/capybara/driver/base.rb +27 -6
- data/lib/capybara/driver/node.rb +14 -5
- data/lib/capybara/dsl.rb +2 -3
- data/lib/capybara/helpers.rb +13 -65
- data/lib/capybara/minitest/spec.rb +177 -0
- data/lib/capybara/minitest.rb +278 -0
- data/lib/capybara/node/actions.rb +180 -24
- data/lib/capybara/node/base.rb +17 -5
- data/lib/capybara/node/document.rb +5 -0
- data/lib/capybara/node/document_matchers.rb +15 -14
- data/lib/capybara/node/element.rb +55 -7
- data/lib/capybara/node/finders.rb +179 -67
- data/lib/capybara/node/matchers.rb +301 -105
- data/lib/capybara/node/simple.rb +15 -4
- data/lib/capybara/queries/ancestor_query.rb +25 -0
- data/lib/capybara/queries/base_query.rb +69 -3
- data/lib/capybara/queries/current_path_query.rb +17 -8
- data/lib/capybara/queries/match_query.rb +19 -0
- data/lib/capybara/queries/selector_query.rb +251 -0
- data/lib/capybara/queries/sibling_query.rb +25 -0
- data/lib/capybara/queries/text_query.rb +67 -16
- data/lib/capybara/queries/title_query.rb +4 -2
- data/lib/capybara/query.rb +3 -131
- data/lib/capybara/rack_test/browser.rb +14 -5
- data/lib/capybara/rack_test/css_handlers.rb +1 -0
- data/lib/capybara/rack_test/driver.rb +15 -8
- data/lib/capybara/rack_test/form.rb +34 -12
- data/lib/capybara/rack_test/node.rb +29 -12
- data/lib/capybara/rails.rb +3 -3
- data/lib/capybara/result.rb +104 -9
- data/lib/capybara/rspec/compound.rb +95 -0
- data/lib/capybara/rspec/features.rb +17 -6
- data/lib/capybara/rspec/matcher_proxies.rb +45 -0
- data/lib/capybara/rspec/matchers.rb +199 -80
- data/lib/capybara/rspec.rb +4 -2
- data/lib/capybara/selector/css.rb +30 -0
- data/lib/capybara/selector/filter.rb +20 -0
- data/lib/capybara/selector/filter_set.rb +74 -0
- data/lib/capybara/selector/filters/base.rb +33 -0
- data/lib/capybara/selector/filters/expression_filter.rb +40 -0
- data/lib/capybara/selector/filters/node_filter.rb +27 -0
- data/lib/capybara/selector/selector.rb +276 -0
- data/lib/capybara/selector.rb +452 -157
- data/lib/capybara/selenium/driver.rb +282 -81
- data/lib/capybara/selenium/node.rb +144 -46
- data/lib/capybara/server.rb +59 -16
- data/lib/capybara/session/config.rb +114 -0
- data/lib/capybara/session/matchers.rb +29 -19
- data/lib/capybara/session.rb +378 -143
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/jquery-ui.js +13 -791
- data/lib/capybara/spec/public/jquery.js +4 -9045
- data/lib/capybara/spec/public/test.js +45 -11
- data/lib/capybara/spec/session/accept_alert_spec.rb +30 -7
- data/lib/capybara/spec/session/accept_confirm_spec.rb +14 -2
- data/lib/capybara/spec/session/accept_prompt_spec.rb +35 -6
- data/lib/capybara/spec/session/all_spec.rb +45 -32
- data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +110 -0
- data/lib/capybara/spec/session/assert_current_path.rb +15 -2
- data/lib/capybara/spec/session/assert_selector.rb +29 -28
- data/lib/capybara/spec/session/assert_text.rb +59 -20
- data/lib/capybara/spec/session/assert_title.rb +25 -11
- data/lib/capybara/spec/session/attach_file_spec.rb +42 -4
- data/lib/capybara/spec/session/body_spec.rb +1 -0
- data/lib/capybara/spec/session/check_spec.rb +90 -14
- data/lib/capybara/spec/session/choose_spec.rb +31 -5
- data/lib/capybara/spec/session/click_button_spec.rb +20 -9
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +15 -9
- data/lib/capybara/spec/session/click_link_spec.rb +39 -15
- data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
- data/lib/capybara/spec/session/current_url_spec.rb +12 -3
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +6 -5
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +4 -3
- data/lib/capybara/spec/session/element/assert_match_selector.rb +36 -0
- data/lib/capybara/spec/session/element/match_css_spec.rb +23 -0
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +106 -0
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +23 -1
- data/lib/capybara/spec/session/execute_script_spec.rb +22 -3
- data/lib/capybara/spec/session/fill_in_spec.rb +50 -32
- data/lib/capybara/spec/session/find_button_spec.rb +43 -2
- data/lib/capybara/spec/session/find_by_id_spec.rb +3 -2
- data/lib/capybara/spec/session/find_field_spec.rb +42 -6
- data/lib/capybara/spec/session/find_link_spec.rb +22 -3
- data/lib/capybara/spec/session/find_spec.rb +103 -57
- data/lib/capybara/spec/session/first_spec.rb +34 -18
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
- data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +44 -2
- data/lib/capybara/spec/session/go_back_spec.rb +2 -1
- data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_button_spec.rb +17 -8
- data/lib/capybara/spec/session/has_css_spec.rb +85 -73
- data/lib/capybara/spec/session/has_current_path_spec.rb +91 -7
- data/lib/capybara/spec/session/has_field_spec.rb +93 -58
- data/lib/capybara/spec/session/has_link_spec.rb +9 -8
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
- data/lib/capybara/spec/session/has_select_spec.rb +159 -59
- data/lib/capybara/spec/session/has_selector_spec.rb +64 -28
- data/lib/capybara/spec/session/has_table_spec.rb +1 -0
- data/lib/capybara/spec/session/has_text_spec.rb +27 -12
- data/lib/capybara/spec/session/has_title_spec.rb +22 -4
- data/lib/capybara/spec/session/has_xpath_spec.rb +32 -29
- data/lib/capybara/spec/session/headers.rb +2 -1
- data/lib/capybara/spec/session/html_spec.rb +4 -3
- data/lib/capybara/spec/session/node_spec.rb +198 -38
- data/lib/capybara/spec/session/refresh_spec.rb +28 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +46 -5
- data/lib/capybara/spec/session/response_code.rb +2 -1
- data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -5
- data/lib/capybara/spec/session/save_page_spec.rb +34 -2
- data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
- data/lib/capybara/spec/session/screenshot_spec.rb +4 -2
- data/lib/capybara/spec/session/select_spec.rb +34 -32
- data/lib/capybara/spec/session/selectors_spec.rb +65 -0
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/text_spec.rb +4 -4
- data/lib/capybara/spec/session/title_spec.rb +2 -1
- data/lib/capybara/spec/session/uncheck_spec.rb +42 -2
- data/lib/capybara/spec/session/unselect_spec.rb +17 -16
- data/lib/capybara/spec/session/visit_spec.rb +77 -2
- data/lib/capybara/spec/session/window/become_closed_spec.rb +12 -11
- data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -11
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +7 -4
- data/lib/capybara/spec/session/window/window_spec.rb +36 -29
- data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
- data/lib/capybara/spec/session/window/within_window_spec.rb +31 -7
- data/lib/capybara/spec/session/within_spec.rb +14 -6
- data/lib/capybara/spec/spec_helper.rb +37 -4
- data/lib/capybara/spec/test_app.rb +15 -3
- data/lib/capybara/spec/views/buttons.erb +1 -0
- data/lib/capybara/spec/views/fieldsets.erb +2 -1
- data/lib/capybara/spec/views/form.erb +169 -9
- data/lib/capybara/spec/views/frame_child.erb +10 -2
- data/lib/capybara/spec/views/frame_one.erb +2 -1
- data/lib/capybara/spec/views/frame_parent.erb +3 -2
- data/lib/capybara/spec/views/frame_two.erb +2 -1
- data/lib/capybara/spec/views/header_links.erb +1 -0
- data/lib/capybara/spec/views/host_links.erb +1 -0
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/path.erb +1 -0
- data/lib/capybara/spec/views/popup_one.erb +1 -0
- data/lib/capybara/spec/views/popup_two.erb +1 -0
- data/lib/capybara/spec/views/postback.erb +2 -1
- data/lib/capybara/spec/views/tables.erb +1 -0
- data/lib/capybara/spec/views/with_base_tag.erb +1 -0
- data/lib/capybara/spec/views/with_count.erb +2 -1
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +7 -1
- data/lib/capybara/spec/views/with_html.erb +40 -2
- data/lib/capybara/spec/views/with_html_entities.erb +1 -0
- data/lib/capybara/spec/views/with_js.erb +32 -1
- data/lib/capybara/spec/views/with_scope.erb +1 -0
- data/lib/capybara/spec/views/with_simple_html.erb +2 -1
- data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
- data/lib/capybara/spec/views/with_title.erb +2 -1
- data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
- data/lib/capybara/spec/views/with_windows.erb +7 -0
- data/lib/capybara/spec/views/within_frames.erb +3 -2
- data/lib/capybara/version.rb +2 -1
- data/lib/capybara/window.rb +20 -3
- data/lib/capybara.rb +189 -93
- data/spec/basic_node_spec.rb +7 -6
- data/spec/capybara_spec.rb +90 -4
- data/spec/dsl_spec.rb +3 -1
- data/spec/filter_set_spec.rb +28 -0
- data/spec/fixtures/capybara.csv +1 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -1
- data/spec/fixtures/selenium_driver_rspec_success.rb +5 -1
- data/spec/minitest_spec.rb +130 -0
- data/spec/minitest_spec_spec.rb +135 -0
- data/spec/per_session_config_spec.rb +67 -0
- data/spec/rack_test_spec.rb +50 -7
- data/spec/result_spec.rb +76 -0
- data/spec/rspec/features_spec.rb +21 -8
- data/spec/rspec/scenarios_spec.rb +21 -0
- data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +160 -54
- data/spec/rspec/views_spec.rb +5 -0
- data/spec/rspec_matchers_spec.rb +46 -0
- data/spec/rspec_spec.rb +79 -1
- data/spec/selector_spec.rb +199 -0
- data/spec/selenium_spec_chrome.rb +54 -9
- data/spec/selenium_spec_firefox.rb +68 -0
- data/spec/selenium_spec_marionette.rb +127 -0
- data/spec/server_spec.rb +102 -14
- data/spec/session_spec.rb +54 -0
- data/spec/shared_selenium_session.rb +215 -0
- data/spec/spec_helper.rb +7 -0
- metadata +140 -15
- data/spec/selenium_spec.rb +0 -128
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'capybara/selector/filter'
|
|
3
|
+
|
|
4
|
+
module Capybara
|
|
5
|
+
class Selector
|
|
6
|
+
class FilterSet
|
|
7
|
+
attr_reader :descriptions
|
|
8
|
+
|
|
9
|
+
def initialize(name, &block)
|
|
10
|
+
@name = name
|
|
11
|
+
@descriptions = []
|
|
12
|
+
instance_eval(&block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def filter(name, *types_and_options, &block)
|
|
16
|
+
add_filter(name, Filters::NodeFilter, *types_and_options, &block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def expression_filter(name, *types_and_options, &block)
|
|
20
|
+
add_filter(name, Filters::ExpressionFilter, *types_and_options, &block)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def describe(&block)
|
|
24
|
+
descriptions.push block
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def description(options={})
|
|
28
|
+
options_with_defaults = options.dup
|
|
29
|
+
filters.each do |name, filter|
|
|
30
|
+
options_with_defaults[name] = filter.default if filter.default? && !options_with_defaults.has_key?(name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
@descriptions.map do |desc|
|
|
34
|
+
desc.call(options_with_defaults).to_s
|
|
35
|
+
end.join
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def filters
|
|
39
|
+
@filters ||= {}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def node_filters
|
|
43
|
+
filters.reject { |_n, f| f.nil? || f.is_a?(Filters::ExpressionFilter) }.freeze
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def expression_filters
|
|
47
|
+
filters.select { |_n, f| f.nil? || f.is_a?(Filters::ExpressionFilter) }.freeze
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class << self
|
|
51
|
+
|
|
52
|
+
def all
|
|
53
|
+
@filter_sets ||= {}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def add(name, &block)
|
|
57
|
+
all[name.to_sym] = FilterSet.new(name.to_sym, &block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def remove(name)
|
|
61
|
+
all.delete(name.to_sym)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def add_filter(name, filter_class, *types_and_options, &block)
|
|
68
|
+
options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
|
|
69
|
+
types_and_options.each { |k| options[k] = true}
|
|
70
|
+
filters[name] = filter_class.new(name, block, options)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Capybara
|
|
3
|
+
class Selector
|
|
4
|
+
module Filters
|
|
5
|
+
class Base
|
|
6
|
+
def initialize(name, block, options={})
|
|
7
|
+
@name = name
|
|
8
|
+
@block = block
|
|
9
|
+
@options = options
|
|
10
|
+
@options[:valid_values] = [true,false] if options[:boolean]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def default?
|
|
14
|
+
@options.has_key?(:default)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def default
|
|
18
|
+
@options[:default]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def skip?(value)
|
|
22
|
+
@options.has_key?(:skip_if) && value == @options[:skip_if]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def valid_value?(value)
|
|
28
|
+
!@options.has_key?(:valid_values) || Array(@options[:valid_values]).include?(value)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'capybara/selector/filters/base'
|
|
3
|
+
|
|
4
|
+
module Capybara
|
|
5
|
+
class Selector
|
|
6
|
+
module Filters
|
|
7
|
+
class ExpressionFilter < Base
|
|
8
|
+
def apply_filter(expr, value)
|
|
9
|
+
return expr if skip?(value)
|
|
10
|
+
|
|
11
|
+
if !valid_value?(value)
|
|
12
|
+
msg = "Invalid value #{value.inspect} passed to expression filter #{@name} - "
|
|
13
|
+
if default?
|
|
14
|
+
warn msg + "defaulting to #{default}"
|
|
15
|
+
value = default
|
|
16
|
+
else
|
|
17
|
+
warn msg + "skipping"
|
|
18
|
+
return expr
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
@block.call(expr, value)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class IdentityExpressionFilter < ExpressionFilter
|
|
27
|
+
def initialize
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def default?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def apply_filter(expr, _value)
|
|
35
|
+
return expr
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'capybara/selector/filters/base'
|
|
3
|
+
|
|
4
|
+
module Capybara
|
|
5
|
+
class Selector
|
|
6
|
+
module Filters
|
|
7
|
+
class NodeFilter < Base
|
|
8
|
+
def matches?(node, value)
|
|
9
|
+
return true if skip?(value)
|
|
10
|
+
|
|
11
|
+
if !valid_value?(value)
|
|
12
|
+
msg = "Invalid value #{value.inspect} passed to filter #{@name} - "
|
|
13
|
+
if default?
|
|
14
|
+
warn msg + "defaulting to #{default}"
|
|
15
|
+
value = default
|
|
16
|
+
else
|
|
17
|
+
warn msg + "skipping"
|
|
18
|
+
return true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
@block.call(node, value)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'capybara/selector/filter_set'
|
|
3
|
+
require 'capybara/selector/css'
|
|
4
|
+
require 'xpath'
|
|
5
|
+
|
|
6
|
+
#Patch XPath to allow a nil condition in where
|
|
7
|
+
module XPath
|
|
8
|
+
class Renderer
|
|
9
|
+
undef :where if method_defined?(:where)
|
|
10
|
+
def where(on, condition)
|
|
11
|
+
condition = condition.to_s
|
|
12
|
+
if !condition.empty?
|
|
13
|
+
"#{on}[#{condition}]"
|
|
14
|
+
else
|
|
15
|
+
"#{on}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module Capybara
|
|
22
|
+
class Selector
|
|
23
|
+
|
|
24
|
+
attr_reader :name, :format
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
def all
|
|
28
|
+
@selectors ||= {}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def add(name, &block)
|
|
32
|
+
all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def update(name, &block)
|
|
36
|
+
all[name.to_sym].instance_eval(&block)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def remove(name)
|
|
40
|
+
all.delete(name.to_sym)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize(name, &block)
|
|
45
|
+
@name = name
|
|
46
|
+
@filter_set = FilterSet.add(name){}
|
|
47
|
+
@match = nil
|
|
48
|
+
@label = nil
|
|
49
|
+
@failure_message = nil
|
|
50
|
+
@description = nil
|
|
51
|
+
@format = nil
|
|
52
|
+
@expression = nil
|
|
53
|
+
@expression_filters = {}
|
|
54
|
+
@default_visibility = nil
|
|
55
|
+
instance_eval(&block)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def custom_filters
|
|
59
|
+
@filter_set.filters
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def node_filters
|
|
63
|
+
@filter_set.node_filters
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def expression_filters
|
|
67
|
+
@filter_set.expression_filters
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
##
|
|
71
|
+
#
|
|
72
|
+
# Define a selector by an xpath expression
|
|
73
|
+
#
|
|
74
|
+
# @overload xpath(*expression_filters, &block)
|
|
75
|
+
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this expression
|
|
76
|
+
# @yield [locator, options] The block to use to generate the XPath expression
|
|
77
|
+
# @yieldparam [String] locator The locator string passed to the query
|
|
78
|
+
# @yieldparam [Hash] options The options hash passed to the query
|
|
79
|
+
# @yieldreturn [#to_xpath, #to_s] An object that can produce an xpath expression
|
|
80
|
+
#
|
|
81
|
+
# @overload xpath()
|
|
82
|
+
# @return [#call] The block that will be called to generate the XPath expression
|
|
83
|
+
#
|
|
84
|
+
def xpath(*expression_filters, &block)
|
|
85
|
+
if block
|
|
86
|
+
@format, @expression = :xpath, block
|
|
87
|
+
expression_filters.flatten.each { |ef| custom_filters[ef] = Filters::IdentityExpressionFilter.new }
|
|
88
|
+
end
|
|
89
|
+
format == :xpath ? @expression : nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
#
|
|
94
|
+
# Define a selector by a CSS selector
|
|
95
|
+
#
|
|
96
|
+
# @overload css(*expression_filters, &block)
|
|
97
|
+
# @param [Array<Symbol>] expression_filters ([]) Names of filters that can be implemented via this CSS selector
|
|
98
|
+
# @yield [locator, options] The block to use to generate the CSS selector
|
|
99
|
+
# @yieldparam [String] locator The locator string passed to the query
|
|
100
|
+
# @yieldparam [Hash] options The options hash passed to the query
|
|
101
|
+
# @yieldreturn [#to_s] An object that can produce a CSS selector
|
|
102
|
+
#
|
|
103
|
+
# @overload css()
|
|
104
|
+
# @return [#call] The block that will be called to generate the CSS selector
|
|
105
|
+
#
|
|
106
|
+
def css(*expression_filters, &block)
|
|
107
|
+
if block
|
|
108
|
+
@format, @expression = :css, block
|
|
109
|
+
expression_filters.flatten.each { |ef| custom_filters[ef] = nil }
|
|
110
|
+
end
|
|
111
|
+
format == :css ? @expression : nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
##
|
|
115
|
+
#
|
|
116
|
+
# Automatic selector detection
|
|
117
|
+
#
|
|
118
|
+
# @yield [locator] This block takes the passed in locator string and returns whether or not it matches the selector
|
|
119
|
+
# @yieldparam [String], locator The locator string used to determin if it matches the selector
|
|
120
|
+
# @yieldreturn [Boolean] Whether this selector matches the locator string
|
|
121
|
+
# @return [#call] The block that will be used to detect selector match
|
|
122
|
+
#
|
|
123
|
+
def match(&block)
|
|
124
|
+
@match = block if block
|
|
125
|
+
@match
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
##
|
|
129
|
+
#
|
|
130
|
+
# Set/get a descriptive label for the selector
|
|
131
|
+
#
|
|
132
|
+
# @overload label(label)
|
|
133
|
+
# @param [String] label A descriptive label for this selector - used in error messages
|
|
134
|
+
# @overload label()
|
|
135
|
+
# @return [String] The currently set label
|
|
136
|
+
#
|
|
137
|
+
def label(label=nil)
|
|
138
|
+
@label = label if label
|
|
139
|
+
@label
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
##
|
|
143
|
+
#
|
|
144
|
+
# Description of the selector
|
|
145
|
+
#
|
|
146
|
+
# @param [Hash] options The options of the query used to generate the description
|
|
147
|
+
# @return [String] Description of the selector when used with the options passed
|
|
148
|
+
#
|
|
149
|
+
def description(options={})
|
|
150
|
+
@filter_set.description(options)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def call(locator, options={})
|
|
154
|
+
if format
|
|
155
|
+
# @expression.call(locator, options.select {|k,v| @expression_filters.include?(k)})
|
|
156
|
+
@expression.call(locator, options)
|
|
157
|
+
else
|
|
158
|
+
warn "Selector has no format"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
##
|
|
163
|
+
#
|
|
164
|
+
# Should this selector be used for the passed in locator
|
|
165
|
+
#
|
|
166
|
+
# This is used by the automatic selector selection mechanism when no selector type is passed to a selector query
|
|
167
|
+
#
|
|
168
|
+
# @param [String] locator The locator passed to the query
|
|
169
|
+
# @return [Boolean] Whether or not to use this selector
|
|
170
|
+
#
|
|
171
|
+
def match?(locator)
|
|
172
|
+
@match and @match.call(locator)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
##
|
|
176
|
+
#
|
|
177
|
+
# Define a non-expression filter for use with this selector
|
|
178
|
+
#
|
|
179
|
+
# @overload filter(name, *types, options={}, &block)
|
|
180
|
+
# @param [Symbol] name The filter name
|
|
181
|
+
# @param [Array<Symbol>] types The types of the filter - currently valid types are [:boolean]
|
|
182
|
+
# @param [Hash] options ({}) Options of the filter
|
|
183
|
+
# @option options [Array<>] :valid_values Valid values for this filter
|
|
184
|
+
# @option options :default The default value of the filter (if any)
|
|
185
|
+
# @option options :skip_if Value of the filter that will cause it to be skipped
|
|
186
|
+
#
|
|
187
|
+
def filter(name, *types_and_options, &block)
|
|
188
|
+
options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
|
|
189
|
+
types_and_options.each { |k| options[k] = true }
|
|
190
|
+
custom_filters[name] = Filters::NodeFilter.new(name, block, options)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def expression_filter(name, *types_and_options, &block)
|
|
194
|
+
options = types_and_options.last.is_a?(Hash) ? types_and_options.pop.dup : {}
|
|
195
|
+
types_and_options.each { |k| options[k] = true }
|
|
196
|
+
custom_filters[name] = Filters::ExpressionFilter.new(name, block, options)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def filter_set(name, filters_to_use = nil)
|
|
200
|
+
f_set = FilterSet.all[name]
|
|
201
|
+
f_set.filters.each do |n, filter|
|
|
202
|
+
custom_filters[n] = filter if filters_to_use.nil? || filters_to_use.include?(n)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
f_set.descriptions.each { |desc| @filter_set.describe(&desc) }
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def describe &block
|
|
209
|
+
@filter_set.describe(&block)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
##
|
|
213
|
+
#
|
|
214
|
+
# Set the default visibility mode that shouble be used if no visibile option is passed when using the selector.
|
|
215
|
+
# If not specified will default to the behavior indicated by Capybara.ignore_hidden_elements
|
|
216
|
+
#
|
|
217
|
+
# @param [Symbol] default_visibility Only find elements with the specified visibility:
|
|
218
|
+
# * :all - finds visible and invisible elements.
|
|
219
|
+
# * :hidden - only finds invisible elements.
|
|
220
|
+
# * :visible - only finds visible elements.
|
|
221
|
+
def visible(default_visibility)
|
|
222
|
+
@default_visibility = default_visibility
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def default_visibility(fallback = Capybara.ignore_hidden_elements)
|
|
226
|
+
if @default_visibility.nil?
|
|
227
|
+
fallback
|
|
228
|
+
else
|
|
229
|
+
@default_visibility
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
private
|
|
234
|
+
|
|
235
|
+
def locate_field(xpath, locator, options={})
|
|
236
|
+
locate_xpath = xpath #need to save original xpath for the label wrap
|
|
237
|
+
if locator
|
|
238
|
+
locator = locator.to_s
|
|
239
|
+
attr_matchers = XPath.attr(:id).equals(locator).or(
|
|
240
|
+
XPath.attr(:name).equals(locator)).or(
|
|
241
|
+
XPath.attr(:placeholder).equals(locator)).or(
|
|
242
|
+
XPath.attr(:id).equals(XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)))
|
|
243
|
+
attr_matchers = attr_matchers.or XPath.attr(:'aria-label').is(locator) if options[:enable_aria_label]
|
|
244
|
+
|
|
245
|
+
locate_xpath = locate_xpath[attr_matchers]
|
|
246
|
+
locate_xpath = locate_xpath.union(XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath))
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# locate_xpath = [:name, :placeholder].inject(locate_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
|
250
|
+
locate_xpath
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def describe_all_expression_filters(opts={})
|
|
254
|
+
expression_filters.map { |ef| " with #{ef} #{opts[ef]}" if opts.has_key?(ef) }.join
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def find_by_attr(attribute, value)
|
|
258
|
+
finder_name = "find_by_#{attribute}_attr"
|
|
259
|
+
if respond_to?(finder_name, true)
|
|
260
|
+
send(finder_name, value)
|
|
261
|
+
else
|
|
262
|
+
value ? XPath.attr(attribute).equals(value) : nil
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def find_by_class_attr(classes)
|
|
267
|
+
if classes
|
|
268
|
+
Array(classes).map do |klass|
|
|
269
|
+
"contains(concat(' ',normalize-space(@class),' '),' #{klass} ')"
|
|
270
|
+
end.join(" and ").to_sym
|
|
271
|
+
else
|
|
272
|
+
nil
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|