mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
add match_xxx methods and matchers to check whether an element matches css, xpath, selector
This commit is contained in:
parent
f44f1e45aa
commit
8715327c43
15 changed files with 435 additions and 141 deletions
|
@ -419,10 +419,12 @@ module Capybara
|
||||||
require 'capybara/version'
|
require 'capybara/version'
|
||||||
|
|
||||||
require 'capybara/queries/base_query'
|
require 'capybara/queries/base_query'
|
||||||
require 'capybara/query'
|
require 'capybara/queries/selector_query'
|
||||||
require 'capybara/queries/text_query'
|
require 'capybara/queries/text_query'
|
||||||
require 'capybara/queries/title_query'
|
require 'capybara/queries/title_query'
|
||||||
require 'capybara/queries/current_path_query'
|
require 'capybara/queries/current_path_query'
|
||||||
|
require 'capybara/queries/match_query'
|
||||||
|
require 'capybara/query'
|
||||||
|
|
||||||
require 'capybara/node/finders'
|
require 'capybara/node/finders'
|
||||||
require 'capybara/node/matchers'
|
require 'capybara/node/matchers'
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Capybara
|
||||||
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
||||||
#
|
#
|
||||||
def find(*args)
|
def find(*args)
|
||||||
query = Capybara::Query.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
if query.match == :smart or query.match == :prefer_exact
|
if query.match == :smart or query.match == :prefer_exact
|
||||||
result = query.resolve_for(self, true)
|
result = query.resolve_for(self, true)
|
||||||
|
@ -178,7 +178,7 @@ module Capybara
|
||||||
# @return [Capybara::Result] A collection of found elements
|
# @return [Capybara::Result] A collection of found elements
|
||||||
#
|
#
|
||||||
def all(*args)
|
def all(*args)
|
||||||
query = Capybara::Query.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
result = query.resolve_for(self)
|
result = query.resolve_for(self)
|
||||||
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
||||||
|
|
|
@ -56,6 +56,36 @@ module Capybara
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node matches given selector
|
||||||
|
# Usage is identical to Capybara::Node::Matchers#has_selector?
|
||||||
|
#
|
||||||
|
# @param (see Capybara::Node::Finders#has_selector?)
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def match_selector?(*args)
|
||||||
|
assert_match_selector(*args)
|
||||||
|
rescue Capybara::ExpectationNotMet
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node does not match given selector
|
||||||
|
# Usage is identical to Capybara::Node::Matchers#has_selector?
|
||||||
|
#
|
||||||
|
# @param (see Capybara::Node::Finders#has_selector?)
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def not_match_selector?(*args)
|
||||||
|
assert_not_match_selector(*args)
|
||||||
|
rescue Capybara::ExpectationNotMet
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Asserts that a given selector is on the page or current node.
|
# Asserts that a given selector is on the page or current node.
|
||||||
|
@ -90,7 +120,7 @@ module Capybara
|
||||||
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
||||||
#
|
#
|
||||||
def assert_selector(*args)
|
def assert_selector(*args)
|
||||||
query = Capybara::Query.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
result = query.resolve_for(self)
|
result = query.resolve_for(self)
|
||||||
matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
|
matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
|
||||||
|
@ -118,7 +148,7 @@ module Capybara
|
||||||
# @raise [Capybara::ExpectationNotMet] If the selector exists
|
# @raise [Capybara::ExpectationNotMet] If the selector exists
|
||||||
#
|
#
|
||||||
def assert_no_selector(*args)
|
def assert_no_selector(*args)
|
||||||
query = Capybara::Query.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
result = query.resolve_for(self)
|
result = query.resolve_for(self)
|
||||||
matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
|
matches_count = Capybara::Helpers.matches_count?(result.size, query.options)
|
||||||
|
@ -130,6 +160,45 @@ module Capybara
|
||||||
end
|
end
|
||||||
alias_method :refute_selector, :assert_no_selector
|
alias_method :refute_selector, :assert_no_selector
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Asserts that the current_node matches a given selector
|
||||||
|
#
|
||||||
|
# node.assert_match_selector('p#foo')
|
||||||
|
# node.assert_match_selector(:xpath, '//p[@id="foo"]')
|
||||||
|
# node.assert_match_selector(:foo)
|
||||||
|
#
|
||||||
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
||||||
|
# such as :text and :visible.
|
||||||
|
#
|
||||||
|
# node.assert_match_selector('li', :text => 'Horse', :visible => true)
|
||||||
|
#
|
||||||
|
# @param (see Capybara::Node::Finders#all)
|
||||||
|
# @raise [Capybara::ExpectationNotMet] If the selector does not match
|
||||||
|
#
|
||||||
|
def assert_match_selector(*args)
|
||||||
|
query = Capybara::Queries::MatchQuery.new(*args)
|
||||||
|
synchronize(query.wait) do
|
||||||
|
result = query.resolve_for(self.parent)
|
||||||
|
unless result.include? self
|
||||||
|
raise Capybara::ExpectationNotMet, "Item does not match the provided selector"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_not_match_selector(*args)
|
||||||
|
query = Capybara::Queries::MatchQuery.new(*args)
|
||||||
|
synchronize(query.wait) do
|
||||||
|
result = query.resolve_for(self.parent)
|
||||||
|
if result.include? self
|
||||||
|
raise Capybara::ExpectationNotMet, 'Item matched the provided selector'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
alias_method :refute_match_selector, :assert_not_match_selector
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Checks if a given XPath expression is on the page or current node.
|
# Checks if a given XPath expression is on the page or current node.
|
||||||
|
|
21
lib/capybara/queries/match_query.rb
Normal file
21
lib/capybara/queries/match_query.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
module Capybara
|
||||||
|
module Queries
|
||||||
|
class MatchQuery < Capybara::Queries::SelectorQuery
|
||||||
|
VALID_KEYS = [:text, :visible, :exact, :wait]
|
||||||
|
|
||||||
|
def visible
|
||||||
|
if options.has_key?(:visible)
|
||||||
|
super
|
||||||
|
else
|
||||||
|
:all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def valid_keys
|
||||||
|
[:text, :visible, :exact, :wait] + @selector.custom_filters.keys
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
136
lib/capybara/queries/selector_query.rb
Normal file
136
lib/capybara/queries/selector_query.rb
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Capybara
|
||||||
|
module Queries
|
||||||
|
class SelectorQuery < Queries::BaseQuery
|
||||||
|
attr_accessor :selector, :locator, :options, :expression, :find, :negative
|
||||||
|
|
||||||
|
VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum, :exact, :match, :wait]
|
||||||
|
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
||||||
|
|
||||||
|
def initialize(*args)
|
||||||
|
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
||||||
|
|
||||||
|
if args[0].is_a?(Symbol)
|
||||||
|
@selector = Selector.all[args[0]]
|
||||||
|
@locator = args[1]
|
||||||
|
else
|
||||||
|
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
|
||||||
|
@locator = args[0]
|
||||||
|
end
|
||||||
|
@selector ||= Selector.all[Capybara.default_selector]
|
||||||
|
|
||||||
|
# for compatibility with Capybara 2.0
|
||||||
|
if Capybara.exact_options and @selector == Selector.all[:option]
|
||||||
|
@options[:exact] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
@expression = @selector.call(@locator)
|
||||||
|
assert_valid_keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def name; selector.name; end
|
||||||
|
def label; selector.label or selector.name; end
|
||||||
|
|
||||||
|
def description
|
||||||
|
@description = String.new("#{label} #{locator.inspect}")
|
||||||
|
@description << " with text #{options[:text].inspect}" if options[:text]
|
||||||
|
@description << selector.description(options)
|
||||||
|
@description
|
||||||
|
end
|
||||||
|
|
||||||
|
def matches_filters?(node)
|
||||||
|
if options[:text]
|
||||||
|
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
|
||||||
|
return false if not node.text(visible).match(regexp)
|
||||||
|
end
|
||||||
|
case visible
|
||||||
|
when :visible then return false unless node.visible?
|
||||||
|
when :hidden then return false if node.visible?
|
||||||
|
end
|
||||||
|
selector.custom_filters.each do |name, filter|
|
||||||
|
if options.has_key?(name)
|
||||||
|
return false unless filter.matches?(node, options[name])
|
||||||
|
elsif filter.default?
|
||||||
|
return false unless filter.matches?(node, filter.default)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def visible
|
||||||
|
if options.has_key?(:visible)
|
||||||
|
case @options[:visible]
|
||||||
|
when true then :visible
|
||||||
|
when false then :all
|
||||||
|
else @options[:visible]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if Capybara.ignore_hidden_elements
|
||||||
|
:visible
|
||||||
|
else
|
||||||
|
:all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exact?
|
||||||
|
if options.has_key?(:exact)
|
||||||
|
@options[:exact]
|
||||||
|
else
|
||||||
|
Capybara.exact
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def match
|
||||||
|
if options.has_key?(:match)
|
||||||
|
@options[:match]
|
||||||
|
else
|
||||||
|
Capybara.match
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def xpath(exact=nil)
|
||||||
|
exact = self.exact? if exact == nil
|
||||||
|
if @expression.respond_to?(:to_xpath) and exact
|
||||||
|
@expression.to_xpath(:exact)
|
||||||
|
else
|
||||||
|
@expression.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def css
|
||||||
|
@expression
|
||||||
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
def resolve_for(node, exact = nil)
|
||||||
|
node.synchronize do
|
||||||
|
children = if selector.format == :css
|
||||||
|
node.find_css(self.css)
|
||||||
|
else
|
||||||
|
node.find_xpath(self.xpath(exact))
|
||||||
|
end.map do |child|
|
||||||
|
if node.is_a?(Capybara::Node::Base)
|
||||||
|
Capybara::Node::Element.new(node.session, child, node, self)
|
||||||
|
else
|
||||||
|
Capybara::Node::Simple.new(child)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Capybara::Result.new(children, self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def valid_keys
|
||||||
|
COUNT_KEYS + [:text, :visible, :exact, :match, :wait] + @selector.custom_filters.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_valid_keys
|
||||||
|
super
|
||||||
|
unless VALID_MATCH.include?(match)
|
||||||
|
raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(", ")}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,136 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
require 'capybara/queries/selector_query'
|
||||||
module Capybara
|
module Capybara
|
||||||
# @deprecated This class and its methods are not supposed to be used by users of Capybara's public API.
|
# @deprecated This class and its methods are not supposed to be used by users of Capybara's public API.
|
||||||
# It may be removed in future versions of Capybara.
|
# It may be removed in future versions of Capybara.
|
||||||
class Query < Queries::BaseQuery
|
Query = Queries::SelectorQuery
|
||||||
attr_accessor :selector, :locator, :options, :expression, :find, :negative
|
|
||||||
|
|
||||||
VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum, :exact, :match, :wait]
|
|
||||||
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
|
||||||
|
|
||||||
def initialize(*args)
|
|
||||||
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
|
||||||
|
|
||||||
if args[0].is_a?(Symbol)
|
|
||||||
@selector = Selector.all[args[0]]
|
|
||||||
@locator = args[1]
|
|
||||||
else
|
|
||||||
@selector = Selector.all.values.find { |s| s.match?(args[0]) }
|
|
||||||
@locator = args[0]
|
|
||||||
end
|
|
||||||
@selector ||= Selector.all[Capybara.default_selector]
|
|
||||||
|
|
||||||
# for compatibility with Capybara 2.0
|
|
||||||
if Capybara.exact_options and @selector == Selector.all[:option]
|
|
||||||
@options[:exact] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
@expression = @selector.call(@locator)
|
|
||||||
assert_valid_keys
|
|
||||||
end
|
|
||||||
|
|
||||||
def name; selector.name; end
|
|
||||||
def label; selector.label or selector.name; end
|
|
||||||
|
|
||||||
def description
|
|
||||||
@description = String.new("#{label} #{locator.inspect}")
|
|
||||||
@description << " with text #{options[:text].inspect}" if options[:text]
|
|
||||||
@description << selector.description(options)
|
|
||||||
@description
|
|
||||||
end
|
|
||||||
|
|
||||||
def matches_filters?(node)
|
|
||||||
if options[:text]
|
|
||||||
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
|
|
||||||
return false if not node.text(visible).match(regexp)
|
|
||||||
end
|
|
||||||
case visible
|
|
||||||
when :visible then return false unless node.visible?
|
|
||||||
when :hidden then return false if node.visible?
|
|
||||||
end
|
|
||||||
selector.custom_filters.each do |name, filter|
|
|
||||||
if options.has_key?(name)
|
|
||||||
return false unless filter.matches?(node, options[name])
|
|
||||||
elsif filter.default?
|
|
||||||
return false unless filter.matches?(node, filter.default)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def visible
|
|
||||||
if options.has_key?(:visible)
|
|
||||||
case @options[:visible]
|
|
||||||
when true then :visible
|
|
||||||
when false then :all
|
|
||||||
else @options[:visible]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if Capybara.ignore_hidden_elements
|
|
||||||
:visible
|
|
||||||
else
|
|
||||||
:all
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def exact?
|
|
||||||
if options.has_key?(:exact)
|
|
||||||
@options[:exact]
|
|
||||||
else
|
|
||||||
Capybara.exact
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def match
|
|
||||||
if options.has_key?(:match)
|
|
||||||
@options[:match]
|
|
||||||
else
|
|
||||||
Capybara.match
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def xpath(exact=nil)
|
|
||||||
exact = self.exact? if exact == nil
|
|
||||||
if @expression.respond_to?(:to_xpath) and exact
|
|
||||||
@expression.to_xpath(:exact)
|
|
||||||
else
|
|
||||||
@expression.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def css
|
|
||||||
@expression
|
|
||||||
end
|
|
||||||
|
|
||||||
# @api private
|
|
||||||
def resolve_for(node, exact = nil)
|
|
||||||
node.synchronize do
|
|
||||||
children = if selector.format == :css
|
|
||||||
node.find_css(self.css)
|
|
||||||
else
|
|
||||||
node.find_xpath(self.xpath(exact))
|
|
||||||
end.map do |child|
|
|
||||||
if node.is_a?(Capybara::Node::Base)
|
|
||||||
Capybara::Node::Element.new(node.session, child, node, self)
|
|
||||||
else
|
|
||||||
Capybara::Node::Simple.new(child)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Capybara::Result.new(children, self)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def valid_keys
|
|
||||||
COUNT_KEYS + [:text, :visible, :exact, :match, :wait] + @selector.custom_filters.keys
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_valid_keys
|
|
||||||
super
|
|
||||||
unless VALID_MATCH.include?(match)
|
|
||||||
raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(", ")}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
module Capybara
|
module Capybara
|
||||||
module RSpecMatchers
|
module RSpecMatchers
|
||||||
class Matcher
|
class Matcher
|
||||||
include ::RSpec::Matchers::Composable if defined?(::RSpec::Expectations::Version) && RSpec::Expectations::Version::STRING.to_f >= 3.0
|
include ::RSpec::Matchers::Composable if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.0'))
|
||||||
|
|
||||||
def wrap(actual)
|
def wrap(actual)
|
||||||
if actual.respond_to?("has_selector?")
|
if actual.respond_to?("has_selector?")
|
||||||
|
@ -39,7 +39,7 @@ module Capybara
|
||||||
end
|
end
|
||||||
|
|
||||||
def query
|
def query
|
||||||
@query ||= Capybara::Query.new(*@args)
|
@query ||= Capybara::Queries::SelectorQuery.new(*@args)
|
||||||
end
|
end
|
||||||
|
|
||||||
# RSpec 2 compatibility:
|
# RSpec 2 compatibility:
|
||||||
|
@ -161,7 +161,7 @@ module Capybara
|
||||||
|
|
||||||
class BecomeClosed
|
class BecomeClosed
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
@wait_time = Capybara::Query.new(options).wait
|
@wait_time = Capybara::Queries::SelectorQuery.new(options).wait
|
||||||
end
|
end
|
||||||
|
|
||||||
def matches?(window)
|
def matches?(window)
|
||||||
|
@ -187,18 +187,68 @@ module Capybara
|
||||||
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class MatchSelector < Matcher
|
||||||
|
attr_reader :failure_message, :failure_message_when_negated
|
||||||
|
|
||||||
|
def initialize(*args)
|
||||||
|
@args = args
|
||||||
|
end
|
||||||
|
|
||||||
|
def matches?(actual)
|
||||||
|
actual.assert_match_selector(*@args)
|
||||||
|
rescue Capybara::ExpectationNotMet => e
|
||||||
|
@failure_message = e.message
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
def does_not_match?(actual)
|
||||||
|
actual.assert_not_match_selector(*@args)
|
||||||
|
rescue Capybara::ExpectationNotMet => e
|
||||||
|
@failure_message_when_negated = e.message
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
def description
|
||||||
|
"match #{query.description}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def query
|
||||||
|
@query ||= Capybara::Queries::MatchQuery.new(*@args)
|
||||||
|
end
|
||||||
|
|
||||||
|
# RSpec 2 compatibility:
|
||||||
|
alias_method :failure_message_for_should, :failure_message
|
||||||
|
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
||||||
|
end
|
||||||
|
|
||||||
def have_selector(*args)
|
def have_selector(*args)
|
||||||
HaveSelector.new(*args)
|
HaveSelector.new(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def match_selector(*args)
|
||||||
|
MatchSelector.new(*args)
|
||||||
|
end
|
||||||
|
# defined_negated_matcher was added in RSpec 3.1 - it's syntactic sugar only since a user can do
|
||||||
|
# expect(page).not_to match_selector, so not sure we really need to support not_match_selector for prior to RSpec 3.1
|
||||||
|
::RSpec::Matchers.define_negated_matcher :not_match_selector, :match_selector if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.1'))
|
||||||
|
|
||||||
|
|
||||||
def have_xpath(xpath, options={})
|
def have_xpath(xpath, options={})
|
||||||
HaveSelector.new(:xpath, xpath, options)
|
HaveSelector.new(:xpath, xpath, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def match_xpath(xpath, options={})
|
||||||
|
MatchSelector.new(:xpath, xpath, options)
|
||||||
|
end
|
||||||
|
|
||||||
def have_css(css, options={})
|
def have_css(css, options={})
|
||||||
HaveSelector.new(:css, css, options)
|
HaveSelector.new(:css, css, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def match_css(css, options={})
|
||||||
|
MatchSelector.new(:css, css, options)
|
||||||
|
end
|
||||||
|
|
||||||
def have_text(*args)
|
def have_text(*args)
|
||||||
HaveText.new(*args)
|
HaveText.new(*args)
|
||||||
end
|
end
|
||||||
|
|
|
@ -404,7 +404,7 @@ module Capybara
|
||||||
driver.switch_to_window(window.handle)
|
driver.switch_to_window(window.handle)
|
||||||
window
|
window
|
||||||
else
|
else
|
||||||
wait_time = Capybara::Query.new(options).wait
|
wait_time = Capybara::Queries::SelectorQuery.new(options).wait
|
||||||
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
||||||
original_window_handle = driver.current_window_handle
|
original_window_handle = driver.current_window_handle
|
||||||
begin
|
begin
|
||||||
|
@ -501,7 +501,7 @@ module Capybara
|
||||||
old_handles = driver.window_handles
|
old_handles = driver.window_handles
|
||||||
block.call
|
block.call
|
||||||
|
|
||||||
wait_time = Capybara::Query.new(options).wait
|
wait_time = Capybara::Queries::SelectorQuery.new(options).wait
|
||||||
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
document.synchronize(wait_time, errors: [Capybara::WindowError]) do
|
||||||
opened_handles = (driver.window_handles - old_handles)
|
opened_handles = (driver.window_handles - old_handles)
|
||||||
if opened_handles.size != 1
|
if opened_handles.size != 1
|
||||||
|
|
|
@ -117,4 +117,10 @@ $(function() {
|
||||||
$('#with-key-events').keydown(function(e){
|
$('#with-key-events').keydown(function(e){
|
||||||
$('#key-events-output').append('keydown:'+e.which+' ')
|
$('#key-events-output').append('keydown:'+e.which+' ')
|
||||||
});
|
});
|
||||||
|
$('#disable-on-click').click(function(e){
|
||||||
|
var input = this
|
||||||
|
setTimeout(function() {
|
||||||
|
input.disabled = true;
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
31
lib/capybara/spec/session/element/assert_match_selector.rb
Normal file
31
lib/capybara/spec/session/element/assert_match_selector.rb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
Capybara::SpecHelper.spec '#assert_match_selector' do
|
||||||
|
before do
|
||||||
|
@session.visit('/with_html')
|
||||||
|
@element = @session.find(:css, 'span', text: '42')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be true if the given selector matches the element" do
|
||||||
|
expect(@element.assert_match_selector(:css, '.number')).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be false if the given selector does not match the element" do
|
||||||
|
expect { @element.assert_match_selector(:css, '.not_number') }.to raise_error(Capybara::ElementNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be callable on the session" do
|
||||||
|
expect { @session.assert_match_selector(:css, '.number') }.to raise_error(NoMethodError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should wait for match to occur", requires: [:js] do
|
||||||
|
@session.visit('/with_js')
|
||||||
|
input = @session.find(:css, '#disable-on-click')
|
||||||
|
|
||||||
|
expect(input.assert_match_selector(:css, 'input:enabled')).to be true
|
||||||
|
input.click
|
||||||
|
expect(input.assert_match_selector(:css, 'input:disabled')).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not accept count options" do
|
||||||
|
expect { @element.assert_match_selector(:css, '.number', count: 1) }.to raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
end
|
17
lib/capybara/spec/session/element/match_css_spec.rb
Normal file
17
lib/capybara/spec/session/element/match_css_spec.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Capybara::SpecHelper.spec '#match_css?' do
|
||||||
|
before do
|
||||||
|
@session.visit('/with_html')
|
||||||
|
@element = @session.find(:css, 'span', text: '42')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be true if the given selector matches the element" do
|
||||||
|
expect(@element).to match_css("span")
|
||||||
|
expect(@element).to match_css("span.number")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be false if the given selector does not match" do
|
||||||
|
expect(@element).not_to match_css("div")
|
||||||
|
expect(@element).not_to match_css("p a#doesnotexist")
|
||||||
|
expect(@element).not_to match_css("p.nosuchclass")
|
||||||
|
end
|
||||||
|
end
|
23
lib/capybara/spec/session/element/match_xpath_spec.rb
Normal file
23
lib/capybara/spec/session/element/match_xpath_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
Capybara::SpecHelper.spec '#match_xpath?' do
|
||||||
|
before do
|
||||||
|
@session.visit('/with_html')
|
||||||
|
@element = @session.find(:css, 'span.number')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be true if the given selector is on the page" do
|
||||||
|
expect(@element).to match_xpath("//span")
|
||||||
|
expect(@element).to match_xpath("//span[@class='number']")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be false if the given selector is not on the page" do
|
||||||
|
expect(@element).not_to match_xpath("//abbr")
|
||||||
|
expect(@element).not_to match_xpath("//div")
|
||||||
|
expect(@element).not_to match_xpath("//span[@class='not_a_number']")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should use xpath even if default selector is CSS" do
|
||||||
|
Capybara.default_selector = :css
|
||||||
|
expect(@element).not_to have_xpath("//span[@class='not_a_number']")
|
||||||
|
expect(@element).not_to have_xpath("//div[@class='number']")
|
||||||
|
end
|
||||||
|
end
|
63
lib/capybara/spec/session/element/matches_selector_spec.rb
Normal file
63
lib/capybara/spec/session/element/matches_selector_spec.rb
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
Capybara::SpecHelper.spec '#match_xpath?' do
|
||||||
|
before do
|
||||||
|
@session.visit('/with_html')
|
||||||
|
@element = @session.find('//span', text: '42')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be true if the element matches the given selector" do
|
||||||
|
expect(@element).to match_selector(:xpath, "//span")
|
||||||
|
expect(@element).to match_selector(:css, 'span.number')
|
||||||
|
expect(@element.match_selector?(:css, 'span.number')).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be false if the element does not match the given selector" do
|
||||||
|
expect(@element).not_to match_selector(:xpath, "//div")
|
||||||
|
expect(@element).not_to match_selector(:css, "span.not_a_number")
|
||||||
|
expect(@element.match_selector?(:css, "span.not_a_number")).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should use default selector" do
|
||||||
|
Capybara.default_selector = :css
|
||||||
|
expect(@element).not_to match_selector("span.not_a_number")
|
||||||
|
expect(@element).to match_selector("span.number")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with text" do
|
||||||
|
it "should discard all matches where the given string is not contained" do
|
||||||
|
expect(@element).to match_selector("//span", :text => "42")
|
||||||
|
expect(@element).not_to match_selector("//span", :text => "Doesnotexist")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Capybara::SpecHelper.spec '#not_match_selector?' do
|
||||||
|
before do
|
||||||
|
@session.visit('/with_html')
|
||||||
|
@element = @session.find(:css, "span", text: 42)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be false if the given selector matches the element" do
|
||||||
|
expect(@element).not_to not_match_selector(:xpath, "//span")
|
||||||
|
expect(@element).not_to not_match_selector(:css, "span.number")
|
||||||
|
expect(@element.not_match_selector?(:css, "span.number")).to be false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be true if the given selector does not match the element" do
|
||||||
|
expect(@element).to not_match_selector(:xpath, "//abbr")
|
||||||
|
expect(@element).to not_match_selector(:css, "p a#doesnotexist")
|
||||||
|
expect(@element.not_match_selector?(:css, "p a#doesnotexist")).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should use default selector" do
|
||||||
|
Capybara.default_selector = :css
|
||||||
|
expect(@element).to not_match_selector("p a#doesnotexist")
|
||||||
|
expect(@element).not_to not_match_selector("span.number")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with text" do
|
||||||
|
it "should discard all matches where the given string is contained" do
|
||||||
|
expect(@element).not_to not_match_selector(:css, "span.number", :text => "42")
|
||||||
|
expect(@element).to not_match_selector(:css, "span.number", :text => "Doesnotexist")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end if Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.1')
|
|
@ -11,6 +11,7 @@
|
||||||
<h2 class="head">Header Class Test Five</h2>
|
<h2 class="head">Header Class Test Five</h2>
|
||||||
|
|
||||||
<span class="number">42</span>
|
<span class="number">42</span>
|
||||||
|
<span>Other span</span>
|
||||||
|
|
||||||
<p class="para" id="first">
|
<p class="para" id="first">
|
||||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
|
|
@ -94,6 +94,10 @@
|
||||||
<a href="#" id="open-prompt">Open prompt</a>
|
<a href="#" id="open-prompt">Open prompt</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<input id="disable-on-click"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="#" id="delayed-page-change">Change page</a>
|
<a href="#" id="delayed-page-change">Change page</a>
|
||||||
<a href="/with_html?options[]=things">Non-escaped query options</a>
|
<a href="/with_html?options[]=things">Non-escaped query options</a>
|
||||||
|
|
Loading…
Add table
Reference in a new issue