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, 'content'
  • :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.



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.



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