Skip to content

Commit

Permalink
test_id should support session specific config and default to nil
Browse files Browse the repository at this point in the history
  • Loading branch information
twalpole committed Jul 19, 2018
1 parent 888926e commit 2679697
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 37 deletions.
2 changes: 1 addition & 1 deletion History.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Release date: unreleased
* Work around Selenium lack of support for `file_detector` with remote geckodriver
* `#within_frame` locator is optional when only one frame exists
* `Capybara.test_id` option that allows for matching the Capybara provided selector types
on an arbitrary attribute - defaults to `data-test-id`
on an arbitrary attribute - defaults to nil, set to something like 'data-test-id' if using test ids in your project

# Version 3.3.1
Release date: 2018-06-27
Expand Down
4 changes: 2 additions & 2 deletions lib/capybara.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class << self
# [threadsafe = Boolean] Whether sessions can be configured individually (Default: false)
# [server = Symbol] The name of the registered server to use when running the app under test (Default: :webrick)
# [default_set_options = Hash] The default options passed to Node::set (Default: {})
# [test_id = Symbol/String/nil] Optional attribute to match locator aginst with builtin selectors along with id (Default: 'data-test-id')
# [test_id = Symbol/String/nil] Optional attribute to match locator aginst with builtin selectors along with id (Default: nil)
#
# === DSL Options
#
Expand Down Expand Up @@ -483,7 +483,7 @@ module Selenium; end
config.enable_aria_label = false
config.reuse_server = true
config.default_set_options = {}
config.test_id = 'data-test-id'
config.test_id = nil
end

Capybara.register_driver :rack_test do |app|
Expand Down
15 changes: 1 addition & 14 deletions lib/capybara/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ module Capybara
class Config
extend Forwardable

OPTIONS = %i[app reuse_server threadsafe default_wait_time server default_driver javascript_driver test_id].freeze
OPTIONS = %i[app reuse_server threadsafe default_wait_time server default_driver javascript_driver].freeze

attr_accessor :app
attr_reader :reuse_server, :threadsafe
attr_reader :session_options
attr_reader :test_id
attr_writer :default_driver, :javascript_driver

SessionConfig::OPTIONS.each do |method|
Expand Down Expand Up @@ -80,18 +79,6 @@ def javascript_driver
@javascript_driver || :selenium
end

##
#
# Set an attribue to be optionally matched against the locator for builtin selector types.
# This attribute will be checked by builtin selector types whenever id would normally be checked.
# If `nil` then it will be ignored.
#
# @params [String, Symbol, nil] id Name of the attribute to use as the test id
#
def test_id=(id)
@test_id = id&.to_sym
end

def deprecate(method, alternate_method, once = false)
@deprecation_notified ||= {}
warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead" unless once && @deprecation_notified[method]
Expand Down
2 changes: 1 addition & 1 deletion lib/capybara/queries/selector_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def initialize(*args, session_options:, **options, &filter_block)

raise ArgumentError, "Unused parameters passed to #{self.class.name} : #{args}" unless args.empty?

@expression = @selector.call(@locator, @options.merge(enable_aria_label: session_options.enable_aria_label))
@expression = @selector.call(@locator, @options.merge(enable_aria_label: session_options.enable_aria_label, test_id: session_options.test_id))

warn_exact_usage

Expand Down
24 changes: 12 additions & 12 deletions lib/capybara/selector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@
end

Capybara.add_selector(:fieldset) do
xpath(:legend) do |locator, legend: nil, **|
xpath(:legend) do |locator, legend: nil, test_id: nil, **|
locator_matchers = (XPath.attr(:id) == locator.to_s) | XPath.child(:legend)[XPath.string.n.is(locator.to_s)]
locator_matchers |= XPath.attr(Capybara.test_id) == locator if Capybara.test_id
locator_matchers |= XPath.attr(test_id) == locator if test_id
xpath = XPath.descendant(:fieldset)
xpath = xpath[locator_matchers] unless locator.nil?
xpath = xpath[XPath.child(:legend)[XPath.string.n.is(legend)]] if legend
Expand All @@ -85,7 +85,7 @@
end

Capybara.add_selector(:link) do
xpath(:title, :alt) do |locator, href: true, enable_aria_label: false, alt: nil, title: nil, **|
xpath(:title, :alt) do |locator, href: true, enable_aria_label: false, test_id: nil, alt: nil, title: nil, **|
xpath = XPath.descendant(:a)
xpath = xpath[
case href
Expand All @@ -107,7 +107,7 @@
XPath.attr(:title).is(locator),
XPath.descendant(:img)[XPath.attr(:alt).is(locator)]]
matchers << XPath.attr(:'aria-label').is(locator) if enable_aria_label
matchers << XPath.attr(Capybara.test_id) == locator if Capybara.test_id
matchers << XPath.attr(test_id) == locator if test_id
xpath = xpath[matchers.reduce(:|)]
end

Expand Down Expand Up @@ -143,7 +143,7 @@
end

Capybara.add_selector(:button) do
xpath(:value, :title, :type) do |locator, enable_aria_label: false, **options|
xpath(:value, :title, :type) do |locator, enable_aria_label: false, test_id: nil, **options|
input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
btn_xpath = XPath.descendant(:button)
image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type) == 'image']
Expand All @@ -152,7 +152,7 @@
locator = locator.to_s
locator_matchers = XPath.attr(:id).equals(locator) | XPath.attr(:value).is(locator) | XPath.attr(:title).is(locator)
locator_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
locator_matchers |= XPath.attr(Capybara.test_id) == locator if Capybara.test_id
locator_matchers |= XPath.attr(test_id) == locator if test_id

input_btn_xpath = input_btn_xpath[locator_matchers]

Expand Down Expand Up @@ -387,11 +387,11 @@

Capybara.add_selector(:label) do
label 'label'
xpath(:for) do |locator, options|
xpath(:for) do |locator, test_id: nil, **options|
xpath = XPath.descendant(:label)
unless locator.nil?
locator_matchers = XPath.string.n.is(locator.to_s) | (XPath.attr(:id) == locator.to_s)
locator_matchers |= XPath.attr(Capybara.test_id) == locator if Capybara.test_id
locator_matchers |= XPath.attr(test_id) == locator if test_id
xpath = xpath[locator_matchers]
end
if options.key?(:for) && !options[:for].is_a?(Capybara::Node::Element)
Expand Down Expand Up @@ -425,11 +425,11 @@
end

Capybara.add_selector(:table) do
xpath(:caption) do |locator, caption: nil, **|
xpath(:caption) do |locator, caption: nil, test_id: nil, **|
xpath = XPath.descendant(:table)
unless locator.nil?
locator_matchers = (XPath.attr(:id) == locator.to_s) | XPath.descendant(:caption).is(locator.to_s)
locator_matchers |= XPath.attr(Capybara.test_id) == locator if Capybara.test_id
locator_matchers |= XPath.attr(test_id) == locator if test_id
xpath = xpath[locator_matchers]
end
xpath = xpath[XPath.descendant(:caption) == caption] if caption
Expand All @@ -442,11 +442,11 @@
end

Capybara.add_selector(:frame) do
xpath(:name) do |locator, **options|
xpath(:name) do |locator, test_id: nil, **options|
xpath = XPath.descendant(:iframe).union(XPath.descendant(:frame))
unless locator.nil?
locator_matchers = (XPath.attr(:id) == locator.to_s) | (XPath.attr(:name) == locator.to_s)
locator_matchers |= XPath.attr(Capybara.test_id) == locator if Capybara.test_id
locator_matchers |= XPath.attr(test_id) == locator if test_id
xpath = xpath[locator_matchers]
end
xpath = expression_filters.keys.inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
Expand Down
4 changes: 2 additions & 2 deletions lib/capybara/selector/selector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def default_visibility(fallback = Capybara.ignore_hidden_elements)

private

def locate_field(xpath, locator, enable_aria_label: false, **_options)
def locate_field(xpath, locator, enable_aria_label: false, test_id: nil, **_options)
return xpath if locator.nil?
locate_xpath = xpath # Need to save original xpath for the label wrap
locator = locator.to_s
Expand All @@ -397,7 +397,7 @@ def locate_field(xpath, locator, enable_aria_label: false, **_options)
XPath.attr(:placeholder) == locator,
XPath.attr(:id) == XPath.anywhere(:label)[XPath.string.n.is(locator)].attr(:for)].reduce(:|)
attr_matchers |= XPath.attr(:'aria-label').is(locator) if enable_aria_label
attr_matchers |= XPath.attr(Capybara.test_id) == locator if Capybara.test_id
attr_matchers |= XPath.attr(test_id) == locator if test_id

locate_xpath = locate_xpath[attr_matchers]
locate_xpath + XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath)
Expand Down
18 changes: 17 additions & 1 deletion lib/capybara/session/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class SessionConfig
OPTIONS = %i[always_include_port run_server default_selector default_max_wait_time ignore_hidden_elements
automatic_reload match exact exact_text raise_server_errors visible_text_only
automatic_label_click enable_aria_label save_path asset_host default_host app_host
server_host server_port server_errors default_set_options disable_animation].freeze
server_host server_port server_errors default_set_options disable_animation test_id].freeze

attr_accessor(*OPTIONS)

Expand Down Expand Up @@ -54,6 +54,8 @@ class SessionConfig
# See {Capybara.configure}
# @!method disable_animation
# See {Capybara.configure}
# @!method test_id
# See {Capybara.configure}

remove_method :server_host

Expand Down Expand Up @@ -88,6 +90,20 @@ def disable_animation=(bool)
@disable_animation = bool
end


remove_method :test_id=
##
#
# Set an attribue to be optionally matched against the locator for builtin selector types.
# This attribute will be checked by builtin selector types whenever id would normally be checked.
# If `nil` then it will be ignored.
#
# @params [String, Symbol, nil] id Name of the attribute to use as the test id
#
def test_id=(id)
@test_id = id&.to_sym
end

def initialize_copy(other)
super
@server_errors = @server_errors.dup
Expand Down
11 changes: 8 additions & 3 deletions lib/capybara/spec/session/find_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -441,13 +441,18 @@
end.to raise_error(ArgumentError)
end

context 'with Capybara.test_id' do
it 'should not match when nil' do
context 'with Capybara.test_id', :focus_ do
it 'should default to nil' do
expect(Capybara.test_id).to be_nil
end

it 'should not match on it when nil' do
Capybara.test_id = nil
expect(@session).not_to have_field('test_id')
end

it 'should default to `data-test-id` attribute' do
it 'should work with the attribute set to `data-test-id` attribute' do
Capybara.test_id = 'data-test-id'
expect(@session.find(:field, 'test_id')[:id]).to eq 'test_field'
end

Expand Down
2 changes: 1 addition & 1 deletion lib/capybara/spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def reset!
Capybara.enable_aria_label = false
Capybara.default_set_options = {}
Capybara.disable_animation = false
Capybara.test_id = 'data-test-id'
Capybara.test_id = nil
reset_threadsafe
end

Expand Down

0 comments on commit 2679697

Please sign in to comment.