first swipe at filter sets

This commit is contained in:
Thomas Walpole 2015-01-26 14:50:59 -08:00
parent d624cbd552
commit 3331f8b3c4
4 changed files with 108 additions and 9 deletions

View File

@ -4,7 +4,7 @@ module Capybara
class SelectorQuery < Queries::BaseQuery
attr_accessor :selector, :locator, :options, :expression, :find, :negative
VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum, :exact, :match, :wait]
VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum, :exact, :match, :wait, :filter_set]
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
def initialize(*args)
@ -49,7 +49,7 @@ module Capybara
when :visible then return false unless node.visible?
when :hidden then return false if node.visible?
end
selector.custom_filters.each do |name, filter|
query_filters.each do |name, filter|
if options.has_key?(name)
return false unless filter.matches?(node, options[name])
elsif filter.default?
@ -124,7 +124,20 @@ module Capybara
private
def valid_keys
COUNT_KEYS + [:text, :visible, :exact, :match, :wait] + @selector.custom_filters.keys
vk = COUNT_KEYS + [:text, :visible, :exact, :match, :wait, :filter_set]
vk + custom_keys
end
def query_filters
if options.has_key?(:filter_set)
Capybara::Selector::FilterSet.all[options[:filter_set]].filters
else
@selector.custom_filters
end
end
def custom_keys
query_filters.keys
end
def assert_valid_keys

View File

@ -1,10 +1,10 @@
# frozen_string_literal: true
require 'capybara/selector/filter'
require 'capybara/selector/filter_set'
module Capybara
class Selector
attr_reader :name, :custom_filters, :format
attr_reader :name, :format
class << self
def all
@ -26,7 +26,7 @@ module Capybara
def initialize(name, &block)
@name = name
@custom_filters = {}
@filter_set = FilterSet.add(name){}
@match = nil
@label = nil
@failure_message = nil
@ -36,6 +36,10 @@ module Capybara
instance_eval(&block)
end
def custom_filters
@filter_set.filters
end
def xpath(&block)
@format, @expression = :xpath, block if block
format == :xpath ? @expression : nil
@ -57,7 +61,7 @@ module Capybara
end
def description(options={})
(@description && @description.call(options)).to_s
@filter_set.description(options)
end
def call(locator)
@ -73,11 +77,19 @@ module Capybara
end
def filter(name, options={}, &block)
@custom_filters[name] = Filter.new(name, block, options)
custom_filters[name] = Filter.new(name, block, options)
end
def filter_set(name)
f_set = FilterSet.all[name]
f_set.filters.each do | name, filter |
custom_filters[name] = filter
end
f_set.descriptions.each { |desc| @filter_set.describe &desc }
end
def describe &block
@description = block
@filter_set.describe &block
end
private

View File

@ -0,0 +1,46 @@
# frozen_string_literal: true
require 'capybara/selector/filter'
module Capybara
class Selector
class FilterSet
attr_reader :descriptions
def initialize(name, &block)
@name = name
@descriptions = []
instance_eval(&block)
end
def filter(name, options={}, &block)
filters[name] = Filter.new(name, block, options)
end
def describe(&block)
descriptions.push block
end
def description(options={})
@descriptions.map {|desc| desc.call(options).to_s }.join
end
def filters
@filters ||= {}
end
class << self
def all
@filter_sets ||= {}
end
def add(name, &block)
all[name.to_sym] = FilterSet.new(name.to_sym, &block)
end
def remove(name)
all.delete(name.to_sym)
end
end
end
end
end

View File

@ -165,6 +165,34 @@ Capybara::SpecHelper.spec '#find' do
end
end
context "with alternate filter set" do
before do
Capybara::Selector::FilterSet.add(:value) do
filter(:with) { |node, with| node.value == with.to_s }
end
Capybara.add_selector(:id_with_field_filters) do
xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] }
filter_set(:field)
end
end
it "should allow use of filters from custom filter set" do
expect(@session.find(:id, 'test_field', filter_set: :value, with: 'monkey').value).to eq('monkey')
expect{ @session.find(:id, 'test_field', filter_set: :value, with: 'not_monkey') }.to raise_error(Capybara::ElementNotFound)
end
it "should allow use of filter set from a different selector" do
expect(@session.find(:id, 'test_field', filter_set: :field, with: 'monkey').value).to eq('monkey')
expect{ @session.find(:id, 'test_field', filter_set: :field, with: 'not_monkey') }.to raise_error(Capybara::ElementNotFound)
end
it "should allow importing of filter set into selector" do
expect(@session.find(:id_with_field_filters, 'test_field', with: 'monkey').value).to eq('monkey')
expect{ @session.find(:id_with_field_filters, 'test_field', with: 'not_monkey') }.to raise_error(Capybara::ElementNotFound)
end
end
context "with css as default selector" do
before { Capybara.default_selector = :css }
it "should find the first element using the given locator" do