From 7c5954644a14f2b519f29a5dd53122226f35afa5 Mon Sep 17 00:00:00 2001 From: Thomas Walpole Date: Thu, 16 Aug 2018 13:49:12 -0700 Subject: [PATCH] Metaprogram RSpec matchers --- lib/capybara/minitest/spec.rb | 2 +- lib/capybara/node/actions.rb | 6 +- lib/capybara/node/element.rb | 6 +- lib/capybara/rspec/matchers.rb | 116 +++++++++++++++--------------- lib/capybara/selector.rb | 4 +- lib/capybara/selector/selector.rb | 2 +- 6 files changed, 69 insertions(+), 67 deletions(-) diff --git a/lib/capybara/minitest/spec.rb b/lib/capybara/minitest/spec.rb index e6b623ac..a24eaee4 100644 --- a/lib/capybara/minitest/spec.rb +++ b/lib/capybara/minitest/spec.rb @@ -169,7 +169,7 @@ module Capybara # Expectation that element has style # # @!method must_have_style - # see {Capybara::SessionMatchers#assert_style} + # see {Capybara::Node::Matchers#assert_style} end end end diff --git a/lib/capybara/node/actions.rb b/lib/capybara/node/actions.rb index 640aad9e..f8387814 100644 --- a/lib/capybara/node/actions.rb +++ b/lib/capybara/node/actions.rb @@ -170,7 +170,7 @@ module Capybara # @macro waiting_behavior # # @param value [String] Which option to select - # @param from: [String] The id, Capybara.test_id atrtribute, name or label of the select box + # @param from [String] The id, Capybara.test_id atrtribute, name or label of the select box # # @return [Capybara::Node::Element] The option element selected def select(value = nil, from: nil, **options) @@ -193,8 +193,8 @@ module Capybara # # @macro waiting_behavior # - # @param value [String] Which option to unselect - # @param from: [String] The id, Capybara.test_id attribute, name or label of the select box + # @param value [String] Which option to unselect + # @param from [String] The id, Capybara.test_id attribute, name or label of the select box # # @return [Capybara::Node::Element] The option element unselected def unselect(value = nil, from: nil, **options) diff --git a/lib/capybara/node/element.rb b/lib/capybara/node/element.rb index 05208471..9b523ac4 100644 --- a/lib/capybara/node/element.rb +++ b/lib/capybara/node/element.rb @@ -78,8 +78,8 @@ module Capybara # # element.style('color', 'font-size') # => Computed values of CSS 'color' and 'font-size' styles # - # @param [String] Names of the desired CSS properties - # @return [Hash] Hash of the CSS property names to computed values + # @param [Array] styles Names of the desired CSS properties + # @return [Hash] Hash of the CSS property names to computed values # def style(*styles) styles = styles.flatten.map(&:to_s) @@ -108,7 +108,7 @@ module Capybara # Set the value of the form element to the given value. # # @param [String] value The new value - # @param [Hash{}] options Driver specific options for how to set the value. Take default values from {Capybara#default_set_options} + # @param [Hash{}] options Driver specific options for how to set the value. Take default values from `Capybara#default_set_options` - See {Capybara::configure} # # @return [Capybara::Node::Element] The element def set(value, **options) diff --git a/lib/capybara/rspec/matchers.rb b/lib/capybara/rspec/matchers.rb index 5ebbe2f9..e3523005 100644 --- a/lib/capybara/rspec/matchers.rb +++ b/lib/capybara/rspec/matchers.rb @@ -280,27 +280,71 @@ module Capybara MatchSelector.new(*args, &optional_filter_block) end - # RSpec matcher for whether elements(s) matching a given xpath selector exist - # See {Capybara::Node::Matchers#has_xpath?} - def have_xpath(xpath, **options, &optional_filter_block) - HaveSelector.new(:xpath, xpath, options, &optional_filter_block) + %i[css xpath].each do |selector| + define_method "have_#{selector}" do |expr, **options, &optional_filter_block| + HaveSelector.new(selector, expr, options, &optional_filter_block) + end + + define_method "match_#{selector}" do |expr, **options, &optional_filter_block| + MatchSelector.new(selector, expr, options, &optional_filter_block) + end end - # RSpec matcher for whether the current element matches a given xpath selector - def match_xpath(xpath, **options, &optional_filter_block) - MatchSelector.new(:xpath, xpath, options, &optional_filter_block) + # @!method have_xpath(xpath, **options, &optional_filter_block) + # RSpec matcher for whether elements(s) matching a given xpath selector exist + # See {Capybara::Node::Matchers#has_xpath?} + + # @!method have_css(css, **options, &optional_filter_block) + # RSpec matcher for whether elements(s) matching a given css selector exist + # See {Capybara::Node::Matchers#has_css?} + + # @!method match_xpath(xpath, **options, &optional_filter_block) + # RSpec matcher for whether the current element matches a given xpath selector + # See {Capybara::Node::Matchers#matches_xpath?} + + # @!method match_css(css, **options, &optional_filter_block) + # RSpec matcher for whether the current element matches a given css selector + # See {Capybara::Node::Matchers#matches_css?} + + %i[link button field select table].each do |selector| + define_method "have_#{selector}" do |locator = nil, **options, &optional_filter_block| + HaveSelector.new(selector, locator, options, &optional_filter_block) + end end - # RSpec matcher for whether elements(s) matching a given css selector exist - # See {Capybara::Node::Matchers#has_css?} - def have_css(css, **options, &optional_filter_block) - HaveSelector.new(:css, css, options, &optional_filter_block) + # @!method have_link(locator = nil, **options, &optional_filter_block) + # RSpec matcher for links + # See {Capybara::Node::Matchers#has_link?} + + # @!method have_button(locator = nil, **options, &optional_filter_block) + # RSpec matcher for buttons + # See {Capybara::Node::Matchers#has_button?} + + # @!method have_field(locator = nil, **options, &optional_filter_block) + # RSpec matcher for links + # See {Capybara::Node::Matchers#has_field?} + + # @!method have_select(locator = nil, **options, &optional_filter_block) + # RSpec matcher for select elements + # See {Capybara::Node::Matchers#has_select?} + + # @!method have_table(locator = nil, **options, &optional_filter_block) + # RSpec matcher for table elements + # See {Capybara::Node::Matchers#has_table?} + + %i[checked unchecked].each do |state| + define_method "have_#{state}_field" do |locator = nil, **options, &optional_filter_block| + HaveSelector.new(:field, locator, options.merge(state => true), &optional_filter_block) + end end - # RSpec matcher for whether the current element matches a given css selector - def match_css(css, **options, &optional_filter_block) - MatchSelector.new(:css, css, options, &optional_filter_block) - end + # @!method have_checked_field(locator = nil, **options, &optional_filter_block) + # RSpec matcher for checked fields + # See {Capybara::Node::Matchers#has_checked_field?} + + # @!method have_unchecked_field(locator = nil, **options, &optional_filter_block) + # RSpec matcher for unchecked fields + # See {Capybara::Node::Matchers#has_unchecked_field?} # RSpec matcher for text content # See {Capybara::SessionMatchers#assert_text} @@ -319,48 +363,6 @@ module Capybara HaveCurrentPath.new(path, options) end - # RSpec matcher for links - # See {Capybara::Node::Matchers#has_link?} - def have_link(locator = nil, **options, &optional_filter_block) - HaveSelector.new(:link, locator, options, &optional_filter_block) - end - - # RSpec matcher for buttons - # See {Capybara::Node::Matchers#has_button?} - def have_button(locator = nil, **options, &optional_filter_block) - HaveSelector.new(:button, locator, options, &optional_filter_block) - end - - # RSpec matcher for links - # See {Capybara::Node::Matchers#has_field?} - def have_field(locator = nil, **options, &optional_filter_block) - HaveSelector.new(:field, locator, options, &optional_filter_block) - end - - # RSpec matcher for checked fields - # See {Capybara::Node::Matchers#has_checked_field?} - def have_checked_field(locator = nil, **options, &optional_filter_block) - HaveSelector.new(:field, locator, options.merge(checked: true), &optional_filter_block) - end - - # RSpec matcher for unchecked fields - # See {Capybara::Node::Matchers#has_unchecked_field?} - def have_unchecked_field(locator = nil, **options, &optional_filter_block) - HaveSelector.new(:field, locator, options.merge(unchecked: true), &optional_filter_block) - end - - # RSpec matcher for select elements - # See {Capybara::Node::Matchers#has_select?} - def have_select(locator = nil, **options, &optional_filter_block) - HaveSelector.new(:select, locator, options, &optional_filter_block) - end - - # RSpec matcher for table elements - # See {Capybara::Node::Matchers#has_table?} - def have_table(locator = nil, **options, &optional_filter_block) - HaveSelector.new(:table, locator, options, &optional_filter_block) - end - # RSpec matcher for element style # See {Capybara::Node::Matchers#has_style?} def have_style(styles, **options) diff --git a/lib/capybara/selector.rb b/lib/capybara/selector.rb index 78c9054b..c2d17865 100644 --- a/lib/capybara/selector.rb +++ b/lib/capybara/selector.rb @@ -483,9 +483,9 @@ Capybara.add_selector(:element) do end describe_expression_filters do |**options| - booleans, values = options.partition {|k,v| [true, false].include? v }.map &:to_h + booleans, values = options.partition { |_k, v| [true, false].include? v }.map(&:to_h) desc = describe_all_expression_filters(values) - desc += booleans.map do |k, v| + desc + booleans.map do |k, v| v ? " with #{k} attribute" : "without #{k} attribute" end.join end diff --git a/lib/capybara/selector/selector.rb b/lib/capybara/selector/selector.rb index fff3fd1a..9398aea8 100644 --- a/lib/capybara/selector/selector.rb +++ b/lib/capybara/selector/selector.rb @@ -337,7 +337,7 @@ module Capybara # # Define an expression filter for use with this selector # - # @!method expression_filter(name, *types, options={}, &block) + # @!method expression_filter(name, *types, matcher: nil, **options, &block) # @param [Symbol, Regexp] name The filter name # @param [Regexp] matcher (nil) A Regexp used to check whether a specific option is handled by this filter # @param [Array] types The types of the filter - currently valid types are [:boolean]