diff --git a/lib/capybara/queries/ancestor_query.rb b/lib/capybara/queries/ancestor_query.rb index 531bd23f..785c2437 100644 --- a/lib/capybara/queries/ancestor_query.rb +++ b/lib/capybara/queries/ancestor_query.rb @@ -12,7 +12,7 @@ module Capybara ancestors = node.find_xpath(XPath.ancestor.to_s) .map(&method(:to_element)) .select { |el| match_results.include?(el) } - Capybara::Result.new(ancestors, self) + Capybara::Result.new(ordered_results(ancestors), self) end end diff --git a/lib/capybara/queries/selector_query.rb b/lib/capybara/queries/selector_query.rb index 59ce0818..483e86c5 100644 --- a/lib/capybara/queries/selector_query.rb +++ b/lib/capybara/queries/selector_query.rb @@ -16,11 +16,13 @@ module Capybara enable_aria_label: session_options.enable_aria_label, test_id: session_options.test_id, selector_format: nil, + order: nil, **options, &filter_block) @resolved_node = nil @resolved_count = 0 @options = options.dup + @order = order @filter_cache = Hash.new { |hsh, key| hsh[key] = {} } super(@options) @@ -150,7 +152,7 @@ module Capybara node.synchronize do children = find_nodes_by_selector_format(node, exact).map(&method(:to_element)) - Capybara::Result.new(children, self) + Capybara::Result.new(ordered_results(children), self) end end @@ -313,6 +315,15 @@ module Capybara filters end + def ordered_results(results) + case @order + when :reverse + results.reverse + else + results + end + end + def custom_keys @custom_keys ||= node_filters.keys + expression_filters.keys end diff --git a/lib/capybara/queries/sibling_query.rb b/lib/capybara/queries/sibling_query.rb index c550573d..8fe6388a 100644 --- a/lib/capybara/queries/sibling_query.rb +++ b/lib/capybara/queries/sibling_query.rb @@ -11,7 +11,7 @@ module Capybara siblings = node.find_xpath((XPath.preceding_sibling + XPath.following_sibling).to_s) .map(&method(:to_element)) .select { |el| match_results.include?(el) } - Capybara::Result.new(siblings, self) + Capybara::Result.new(ordered_results(siblings), self) end end diff --git a/lib/capybara/spec/session/all_spec.rb b/lib/capybara/spec/session/all_spec.rb index c919dd5e..0b4909de 100644 --- a/lib/capybara/spec/session/all_spec.rb +++ b/lib/capybara/spec/session/all_spec.rb @@ -36,6 +36,13 @@ Capybara::SpecHelper.spec '#all' do expect(@result).to include('Smith', 'John', 'John Smith') end + it 'should allow reversing the order' do + @session.visit('/form') + fields = @session.all(:fillable_field, 'Name', exact: false).to_a + reverse_fields = @session.all(:fillable_field, 'Name', order: :reverse, exact: false).to_a + expect(fields).to eq(reverse_fields.reverse) + end + it 'should raise an error when given invalid options' do expect { @session.all('//p', schmoo: 'foo') }.to raise_error(ArgumentError) end diff --git a/lib/capybara/spec/session/ancestor_spec.rb b/lib/capybara/spec/session/ancestor_spec.rb index a4a3e72e..ef893bbc 100644 --- a/lib/capybara/spec/session/ancestor_spec.rb +++ b/lib/capybara/spec/session/ancestor_spec.rb @@ -20,6 +20,11 @@ Capybara::SpecHelper.spec '#ancestor' do expect(el.ancestor('//div', text: "Ancestor\nAncestor\nAncestor")[:id]).to eq('ancestor3') end + it 'should find the closest ancestor' do + el = @session.find(:css, '#child') + expect(el.ancestor('.//div', order: :reverse, match: :first)[:id]).to eq('ancestor1') + end + it 'should raise an error if there are multiple matches' do el = @session.find(:css, '#child') expect { el.ancestor('//div') }.to raise_error(Capybara::Ambiguous)