Class: Capybara::Selector

Inherits:
SimpleDelegator
  • Object
show all
Defined in:
lib/capybara/selector.rb,
lib/capybara/selector/css.rb,
lib/capybara/selector/selector.rb,
lib/capybara/selector/definition.rb,
lib/capybara/selector/filter_set.rb,
lib/capybara/selector/filters/base.rb,
lib/capybara/selector/filters/node_filter.rb,
lib/capybara/selector/regexp_disassembler.rb,
lib/capybara/selector/builders/css_builder.rb,
lib/capybara/selector/builders/xpath_builder.rb,
lib/capybara/selector/filters/locator_filter.rb,
lib/capybara/selector/filters/expression_filter.rb

Overview

All Selectors below support the listed selector specific filters in addition to the following system-wide filters

  • :id (String, Regexp, XPath::Expression) - Matches the id attribute
  • :class (String, Array, Regexp, XPath::Expression) - Matches the class(es) provided
  • :style (String, Regexp, Hash) - Match on elements style
  • :above (Element) - Match elements above the passed element on the page
  • :below (Element) - Match elements below the passed element on the page
  • :left_of (Element) - Match elements left of the passed element on the page
  • :right_of (Element) - Match elements right of the passed element on the page
  • :near (Element) - Match elements near (within 50px) the passed element on the page
  • :focused (Boolean) - Match elements with focus (requires driver support)

Built-in Selectors

  • :xpath - Select elements by XPath expression
    • Locator: An XPath expression
  page.html # => '<input>'

  page.find :xpath, './/input'
  • :css - Select elements by CSS selector
    • Locator: A CSS selector
  page.html # => '<input>'

  page.find :css, 'input'
  • :id - Select element by id
    • Locator: (String, Regexp, XPath::Expression) The id of the element to match
  page.html # => '<input id="field">'

  page.find :id, 'field'
  • :field - Select field elements (input [not of type submit, image, or hidden], textarea, select)
    • Locator: Matches against the id, test_id attribute, name, placeholder, or associated label text
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :placeholder (String, Regexp) - Matches the placeholder attribute
      • :type (String) - Matches the type attribute of the field or element type for 'textarea' and 'select'
      • :readonly (Boolean) - Match on the element being readonly
      • :with (String, Regexp) - Matches the current value of the field
      • :checked (Boolean) - Match checked fields?
      • :unchecked (Boolean) - Match unchecked fields?
      • :disabled (Boolean, :all) - Match disabled field? (Default: false)
      • :multiple (Boolean) - Match fields that accept multiple values
      • :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation
      • :validation_message (String, Regexp) - Matches the elements current validationMessage
  page.html # => '<label for="article_title">Title</label>
            #     <input id="article_title" name="article[title]" value="Hello world">'

  page.find :field, 'article_title'
  page.find :field, 'article[title]'
  page.find :field, 'Title'
  page.find :field, 'Title', type: 'text', with: 'Hello world'
  • :fieldset - Select fieldset elements
    • Locator: Matches id, test_id, or contents of wrapped legend
    • Filters:
      • :legend (String) - Matches contents of wrapped legend
      • :disabled (Boolean) - Match disabled fieldset?
  page.html # => '<fieldset disabled>
            #       <legend>Fields (disabled)</legend>
            #     </fieldset>'

  page.find :fieldset, 'Fields (disabled)', disabled: true
  • :link - Find links (<a> elements with an href attribute)
    • Locator: Matches the id, test_id, or title attributes, or the string content of the link, or the alt attribute of a contained img element. By default this selector requires a link to have an href attribute.
    • Filters:
      • :title (String) - Matches the title attribute
      • :alt (String) - Matches the alt attribute of a contained img element
      • :href (String, Regexp, nil, false) - Matches the normalized href of the link, if nil will find <a> elements with no href attribute, if false ignores href presence
  page.html # => '<a href="/">Home</a>'

  page.find :link, 'Home', href: '/'

  page.html # => '<a href="/"><img src="/logo.png" alt="The logo"></a>'

  page.find :link, 'The logo', href: '/'
  page.find :link, alt: 'The logo', href: '/'
  • :button - Find buttons ( input [of type submit, reset, image, button] or button elements )
    • Locator: Matches the id, test_id attribute, name, value, or title attributes, string content of a button, or the alt attribute of an image type button or of a descendant image of a button
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :title (String) - Matches the title attribute
      • :value (String) - Matches the value of an input button
      • :type (String) - Matches the type attribute
      • :disabled (Boolean, :all) - Match disabled buttons (Default: false)
  page.html # => '<button>Submit</button>'

  page.find :button, 'Submit'

  page.html # => '<button name="article[state]" value="draft">Save as draft</button>'

  page.find :button, 'Save as draft', name: 'article[state]', value: 'draft'
  • :link_or_button - Find links or buttons
    • Locator: See :link and :button selectors
    • Filters:
      • :disabled (Boolean, :all) - Match disabled buttons? (Default: false)
  page.html # => '<a href="/">Home</a>'

  page.find :link_or_button, 'Home'

  page.html # => '<button>Submit</button>'

  page.find :link_or_button, 'Submit'
  • :fillable_field - Find text fillable fields ( textarea, input [not of type submit, image, radio, checkbox, hidden, file] )
    • Locator: Matches against the id, test_id attribute, name, placeholder, or associated label text
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :placeholder (String, Regexp) - Matches the placeholder attribute
      • :with (String, Regexp) - Matches the current value of the field
      • :type (String) - Matches the type attribute of the field or element type for 'textarea'
      • :disabled (Boolean, :all) - Match disabled field? (Default: false)
      • :multiple (Boolean) - Match fields that accept multiple values
      • :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation
      • :validation_message (String, Regexp) - Matches the elements current validationMessage
  page.html # => '<label for="article_body">Body</label>
            #     <textarea id="article_body" name="article[body]"></textarea>'

  page.find :fillable_field, 'article_body'
  page.find :fillable_field, 'article[body]'
  page.find :fillable_field, 'Body'
  page.find :field, 'Body', type: 'textarea'
  • :radio_button - Find radio buttons
    • Locator: Match id, test_id attribute, name, or associated label text
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :checked (Boolean) - Match checked fields?
      • :unchecked (Boolean) - Match unchecked fields?
      • :disabled (Boolean, :all) - Match disabled field? (Default: false)
      • :option (String, Regexp) - Match the current value
      • :with - Alias of :option
  page.html # => '<input type="radio" id="article_state_published" name="article[state]" value="published" checked>
            #     <label for="article_state_published">Published</label>
            #     <input type="radio" id="article_state_draft" name="article[state]" value="draft">
            #     <label for="article_state_draft">Draft</label>'

  page.find :radio_button, 'article_state_published'
  page.find :radio_button, 'article[state]', option: 'published'
  page.find :radio_button, 'Published', checked: true
  page.find :radio_button, 'Draft', unchecked: true
  • :checkbox - Find checkboxes
    • Locator: Match id, test_id attribute, name, or associated label text
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :checked (Boolean) - Match checked fields?
      • :unchecked (Boolean) - Match unchecked fields?
      • :disabled (Boolean, :all) - Match disabled field? (Default: false)
      • :with (String, Regexp) - Match the current value
      • :option - Alias of :with
  page.html # => '<input type="checkbox" id="registration_terms" name="registration[terms]" value="true">
            #     <label for="registration_terms">I agree to terms and conditions</label>'

  page.find :checkbox, 'registration_terms'
  page.find :checkbox, 'registration[terms]'
  page.find :checkbox, 'I agree to terms and conditions', unchecked: true
  • :select - Find select elements
    • Locator: Match id, test_id attribute, name, placeholder, or associated label text
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :placeholder (String, Placeholder) - Matches the placeholder attribute
      • :disabled (Boolean, :all) - Match disabled field? (Default: false)
      • :multiple (Boolean) - Match fields that accept multiple values
      • :options (Array) - Exact match options
      • :enabled_options (Array) - Exact match enabled options
      • :disabled_options (Array) - Exact match disabled options
      • :with_options (Array) - Partial match options
      • :selected (String, Array) - Match the selection(s)
      • :with_selected (String, Array) - Partial match the selection(s)
  page.html # => '<label for="article_category">Category</label>
            #     <select id="article_category" name="article[category]">
            #       <option value="General" checked></option>
            #       <option value="Other"></option>
            #     </select>'

  page.find :select, 'article_category'
  page.find :select, 'article[category]'
  page.find :select, 'Category'
  page.find :select, 'Category', selected: 'General'
  page.find :select, with_options: ['General']
  page.find :select, with_options: ['Other']
  page.find :select, options: ['General', 'Other']
  page.find :select, options: ['General'] # => raises Capybara::ElementNotFound
  • :option - Find option elements
    • Locator: Match text of option
    • Filters:
      • :disabled (Boolean) - Match disabled option
      • :selected (Boolean) - Match selected option
  page.html # => '<option value="General" checked></option>
            #     <option value="Disabled" disabled></option>
            #     <option value="Other"></option>'

  page.find :option, 'General'
  page.find :option, 'General', selected: true
  page.find :option, 'Disabled', disabled: true
  page.find :option, 'Other', selected: false
  • :datalist_input - Find input field with datalist completion
    • Locator: Matches against the id, test_id attribute, name, placeholder, or associated label text
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :placeholder (String, Regexp) - Matches the placeholder attribute
      • :disabled (Boolean, :all) - Match disabled field? (Default: false)
      • :options (Array) - Exact match options
      • :with_options (Array) - Partial match options
  page.html # => '<label for="ice_cream_flavor">Flavor</label>
            #     <input list="ice_cream_flavors" id="ice_cream_flavor" name="ice_cream[flavor]">
            #     <datalist id="ice_cream_flavors">
            #       <option value="Chocolate"></option>
            #       <option value="Strawberry"></option>
            #       <option value="Vanilla"></option>
            #     </datalist>'

  page.find :datalist_input, 'ice_cream_flavor'
  page.find :datalist_input, 'ice_cream[flavor]'
  page.find :datalist_input, 'Flavor'
  page.find :datalist_input, with_options: ['Chocolate', 'Strawberry']
  page.find :datalist_input, options: ['Chocolate', 'Strawberry', 'Vanilla']
  page.find :datalist_input, options: ['Chocolate'] # => raises Capybara::ElementNotFound
  • :datalist_option - Find datalist option
    • Locator: Match text or value of option
    • Filters:
      • :disabled (Boolean) - Match disabled option
  page.html # => '<datalist>
            #       <option value="Chocolate"></option>
            #       <option value="Strawberry"></option>
            #       <option value="Vanilla"></option>
            #       <option value="Forbidden" disabled></option>
            #     </datalist>'

  page.find :datalist_option, 'Chocolate'
  page.find :datalist_option, 'Strawberry'
  page.find :datalist_option, 'Vanilla'
  page.find :datalist_option, 'Forbidden', disabled: true
  • :file_field - Find file input elements
    • Locator: Match id, test_id attribute, name, or associated label text
    • Filters:
      • :name (String, Regexp) - Matches the name attribute
      • :disabled (Boolean, :all) - Match disabled field? (Default: false)
      • :multiple (Boolean) - Match field that accepts multiple values
  page.html # => '<label for="article_banner_image">Banner Image</label>
            #     <input type="file" id="article_banner_image" name="article[banner_image]">'

  page.find :file_field, 'article_banner_image'
  page.find :file_field, 'article[banner_image]'
  page.find :file_field, 'Banner Image'
  page.find :file_field, 'Banner Image', name: 'article[banner_image]'
  page.find :field, 'Banner Image', type: 'file'
  • :label - Find label elements
    • Locator: Match id, test_id, or text contents
    • Filters:
      • :for (Element, String, Regexp) - The element or id of the element associated with the label
  page.html # => '<label for="article_title">Title</label>
            #     <input id="article_title" name="article[title]">'

  page.find :label, 'Title'
  page.find :label, 'Title', for: 'article_title'
  page.find :label, 'Title', for: page.find('article[title]')
  • :table - Find table elements
    • Locator: id, test_id, or caption text of table
    • Filters:
      • :caption (String) - Match text of associated caption
      • :with_rows (Array>, Array>) - Partial match <td> data - visibility of <td> elements is not considered
      • :rows (Array>) - Match all <td>s - visibility of <td> elements is not considered
      • :with_cols (Array>, Array>) - Partial match <td> data - visibility of <td> elements is not considered
      • :cols (Array>) - Match all <td>s - visibility of <td> elements is not considered
  page.html # => '<table>
            #       <caption>A table</caption>
            #       <tr>
            #         <th>A</th>
            #         <th>B</th>
            #       </tr>
            #       <tr>
            #         <td>1</td>
            #         <td>2</td>
            #       </tr>
            #       <tr>
            #         <td>3</td>
            #         <td>4</td>
            #       </tr>
            #     </table>'

  page.find :table, 'A table'
  page.find :table, with_rows: [
    { 'A' => '1', 'B' => '2' },
    { 'A' => '3', 'B' => '4' },
  ]
  page.find :table, with_rows: [
    ['1', '2'],
    ['3', '4'],
  ]
  page.find :table, rows: [
    { 'A' => '1', 'B' => '2' },
    { 'A' => '3', 'B' => '4' },
  ]
  page.find :table, rows: [
    ['1', '2'],
    ['3', '4'],
  ]
  page.find :table, rows: [ ['1', '2'] ] # => raises Capybara::ElementNotFound
  • :table_row - Find table row
    • Locator: Array, Hash table row <td> contents - visibility of <td> elements is not considered
  page.html # => '<table>
            #       <tr>
            #         <th>A</th>
            #         <th>B</th>
            #       </tr>
            #       <tr>
            #         <td>1</td>
            #         <td>2</td>
            #       </tr>
            #       <tr>
            #         <td>3</td>
            #         <td>4</td>
            #       </tr>
            #     </table>'

  page.find :table_row, 'A' => '1', 'B' => '2'
  page.find :table_row, 'A' => '3', 'B' => '4'
  • :frame - Find frame/iframe elements
    • Locator: Match id, test_id attribute, or name
    • Filters:
      • :name (String) - Match name attribute
  page.html # => '<iframe id="embed_frame" name="embed" src="https://example.com/embed"></iframe>'

  page.find :frame, 'embed_frame'
  page.find :frame, 'embed'
  page.find :frame, name: 'embed'
  • :element
    • Locator: Type of element ('div', 'a', etc) - if not specified defaults to '*'
    • Filters:
      • :<any> (String, Regexp) - Match on any specified element attribute
  page.html # => '<button type="button" role="menuitemcheckbox" aria-checked="true">Check me</button>

  page.find :element, 'button'
  page.find :element, type: 'button', text: 'Check me'
  page.find :element, role: 'menuitemcheckbox'
  page.find :element, role: /checkbox/, 'aria-checked': 'true'

Defined Under Namespace

Modules: Filters Classes: CSS, CSSBuilder, Definition, FilterSet, RegexpDisassembler, XPathBuilder

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(definition, config:, format:) ⇒ Selector

Returns a new instance of Selector.



33
34
35
36
37
38
39
40
# File 'lib/capybara/selector/selector.rb', line 33

def initialize(definition, config:, format:)
  definition = self.class[definition] unless definition.is_a? Definition
  super(definition)
  @definition = definition
  @config = config
  @format = format
  @errors = []
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



31
32
33
# File 'lib/capybara/selector/selector.rb', line 31

def errors
  @errors
end

Class Method Details

.[](name) ⇒ Object



10
11
12
# File 'lib/capybara/selector/selector.rb', line 10

def [](name)
  all.fetch(name.to_sym) { |sel_type| raise ArgumentError, "Unknown selector type (:#{sel_type})" }
end

.add(name, **options, &block) ⇒ Object



14
15
16
# File 'lib/capybara/selector/selector.rb', line 14

def add(name, **options, &block)
  all[name.to_sym] = Definition.new(name.to_sym, **options, &block)
end

.allObject



6
7
8
# File 'lib/capybara/selector/selector.rb', line 6

def all
  @definitions ||= {} # rubocop:disable Naming/MemoizedInstanceVariableName
end

.for(locator) ⇒ Object



26
27
28
# File 'lib/capybara/selector/selector.rb', line 26

def for(locator)
  all.values.find { |sel| sel.match?(locator) }
end

.remove(name) ⇒ Object



22
23
24
# File 'lib/capybara/selector/selector.rb', line 22

def remove(name)
  all.delete(name.to_sym)
end

.update(name, &block) ⇒ Object



18
19
20
# File 'lib/capybara/selector/selector.rb', line 18

def update(name, &block)
  self[name].instance_eval(&block)
end

Instance Method Details

#add_error(error_msg) ⇒ Object



77
78
79
# File 'lib/capybara/selector/selector.rb', line 77

def add_error(error_msg)
  errors << error_msg
end

#builder(expr = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



95
96
97
98
99
100
101
102
103
104
# File 'lib/capybara/selector/selector.rb', line 95

def builder(expr = nil)
  case format
  when :css
    Capybara::Selector::CSSBuilder
  when :xpath
    Capybara::Selector::XPathBuilder
  else
    raise NotImplementedError, "No builder exists for selector of type #{default_format}"
  end.new(expr)
end

#call(locator, **options) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/capybara/selector/selector.rb', line 59

def call(locator, **options)
  if format
    raise ArgumentError, "Selector #{@name} does not support #{format}" unless expressions.key?(format)

    instance_exec(locator, **options, &expressions[format])
  else
    warn 'Selector has no format'
  end
ensure
  unless locator_valid?(locator)
    Capybara::Helpers.warn(
      "Locator #{locator.class}:#{locator.inspect} for selector #{name.inspect} must #{locator_description}. " \
      'This will raise an error in a future version of Capybara. ' \
      "Called from: #{Capybara::Helpers.filter_backtrace(caller)}"
    )
  end
end

#enable_aria_labelObject



47
48
49
# File 'lib/capybara/selector/selector.rb', line 47

def enable_aria_label
  @config[:enable_aria_label]
end

#enable_aria_roleObject



51
52
53
# File 'lib/capybara/selector/selector.rb', line 51

def enable_aria_role
  @config[:enable_aria_role]
end

#expression_for(name, locator, config: @config, format: current_format, **options) ⇒ Object



81
82
83
# File 'lib/capybara/selector/selector.rb', line 81

def expression_for(name, locator, config: @config, format: current_format, **options)
  Selector.new(name, config: config, format: format).call(locator, **options)
end

#formatObject Also known as: current_format



42
43
44
# File 'lib/capybara/selector/selector.rb', line 42

def format
  @format || @definition.default_format
end

#test_idObject



55
56
57
# File 'lib/capybara/selector/selector.rb', line 55

def test_id
  @config[:test_id]
end

#with_filter_errors(errors) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

API:

  • private



86
87
88
89
90
91
92
# File 'lib/capybara/selector/selector.rb', line 86

def with_filter_errors(errors)
  old_errors = @errors
  @errors = errors
  yield
ensure
  @errors = old_errors
end