Module: RuboCop::Cop::RSpec::CssSelector

Defined in:
lib/rubocop/cop/rspec/mixin/css_selector.rb

Overview

Helps parsing css selector.

Constant Summary collapse

COMMON_OPTIONS =
%w[
  above below left_of right_of near count minimum maximum between text
  id class style visible obscured exact exact_text normalize_ws match
  wait filter_set focused
].freeze
SPECIFIC_OPTIONS =
{
  'button' => (
    COMMON_OPTIONS + %w[disabled name value title type]
  ).freeze,
  'link' => (
    COMMON_OPTIONS + %w[href alt title download]
  ).freeze,
  'table' => (
    COMMON_OPTIONS + %w[
      caption with_cols cols with_rows rows
    ]
  ).freeze,
  'select' => (
    COMMON_OPTIONS + %w[
      disabled name placeholder options enabled_options
      disabled_options selected with_selected multiple with_options
    ]
  ).freeze,
  'field' => (
    COMMON_OPTIONS + %w[
      checked unchecked disabled valid name placeholder
      validation_message readonly with type multiple
    ]
  ).freeze
}.freeze
SPECIFIC_PSEUDO_CLASSES =
%w[
  not() disabled enabled checked unchecked
].freeze

Class Method Summary collapse

Class Method Details

.attribute?(selector) ⇒ Boolean

Examples:

attribute?('[attribute]') # => true
attribute?('attribute') # => false

Parameters:

  • selector (String)

Returns:

  • (Boolean)


77
78
79
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 77

def attribute?(selector)
  selector.start_with?('[')
end

.attributes(selector) ⇒ Array<String>

Examples:

attributes('a[foo-bar_baz]') # => {"foo-bar_baz=>true}
attributes('button[foo][bar]') # => {"foo"=>true, "bar"=>true}
attributes('table[foo=bar]') # => {"foo"=>"'bar'"}

Parameters:

  • selector (String)

Returns:

  • (Array<String>)


87
88
89
90
91
92
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 87

def attributes(selector)
  selector.scan(/\[(.*?)\]/).flatten.to_h do |attr|
    key, value = attr.split('=')
    [key, normalize_value(value)]
  end
end

.common_attributes?(selector) ⇒ Boolean

Examples:

common_attributes?('a[focused]') # => true
common_attributes?('button[focused][visible]') # => true
common_attributes?('table[id=some-id]') # => true
common_attributes?('h1[invalid]') # => false

Parameters:

  • selector (String)

Returns:

  • (Boolean)


101
102
103
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 101

def common_attributes?(selector)
  attributes(selector).keys.difference(COMMON_OPTIONS).none?
end

.id?(selector) ⇒ Boolean

Examples:

id?('#some-id') # => true
id?('.some-class') # => false

Parameters:

  • selector (String)

Returns:

  • (Boolean)


68
69
70
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 68

def id?(selector)
  selector.start_with?('#')
end

.multiple_selectors?(selector) ⇒ Boolean

Examples:

multiple_selectors?('a.cls b#id') # => true
multiple_selectors?('a.cls') # => false

Parameters:

  • selector (String)

Returns:

  • (Boolean)


124
125
126
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 124

def multiple_selectors?(selector)
  selector.match?(/[ >,+~]/)
end

.normalize_value(value) ⇒ Boolean, String

Examples:

normalize_value('true') # => true
normalize_value('false') # => false
normalize_value(nil) # => false
normalize_value("foo") # => "'foo'"

Parameters:

  • value (String)

Returns:

  • (Boolean, String)


135
136
137
138
139
140
141
142
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 135

def normalize_value(value)
  case value
  when 'true' then true
  when 'false' then false
  when nil then true
  else "'#{value}'"
  end
end

.pseudo_classes(selector) ⇒ Array<String>

Examples:

pseudo_classes('button:not([disabled])') # => ['not()']
pseudo_classes('a:enabled:not([valid])') # => ['enabled', 'not()']

Parameters:

  • selector (String)

Returns:

  • (Array<String>)


110
111
112
113
114
115
116
117
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 110

def pseudo_classes(selector)
  # Attributes must be excluded or else the colon in the `href`s URL
  # will also be picked up as pseudo classes.
  # "a:not([href='http://example.com']):enabled" => "a:not():enabled"
  ignored_attribute = selector.gsub(/\[.*?\]/, '')
  # "a:not():enabled" => ["not()", "enabled"]
  ignored_attribute.scan(/:([^:]*)/).flatten
end

.specific_options?(element, attribute) ⇒ Boolean

Examples:

specific_pesudo_classes?('button', 'name') # => true
specific_pesudo_classes?('link', 'invalid') # => false

Parameters:

  • element (String)
  • attribute (String)

Returns:

  • (Boolean)


50
51
52
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 50

def specific_options?(element, attribute)
  SPECIFIC_OPTIONS.fetch(element, []).include?(attribute)
end

.specific_pesudo_classes?(pseudo_class) ⇒ Boolean

Examples:

specific_pesudo_classes?('disabled') # => true
specific_pesudo_classes?('first-of-type') # => false

Parameters:

  • pseudo_class (String)

Returns:

  • (Boolean)


59
60
61
# File 'lib/rubocop/cop/rspec/mixin/css_selector.rb', line 59

def specific_pesudo_classes?(pseudo_class)
  SPECIFIC_PSEUDO_CLASSES.include?(pseudo_class)
end