Class: Watir::Element

Inherits:
Object
  • Object
show all
Extended by:
AttributeHelper
Includes:
Adjacent, Container, EventuallyPresent, Exception, JSExecution, Locators::ClassHelpers, Scrolling, Waitable
Defined in:
lib/watir/elements/element.rb

Overview

Base class for HTML elements.

Direct Known Subclasses

HTMLElement

Constant Summary collapse

CASE_INSENSITIVE_ATTRIBUTES =
%i[accept accept_charset align alink axis
bgcolor charset checked clear codetype
color compact declare defer dir direction
disabled enctype face frame hreflang
http_equiv lang language link media
method multiple nohref noresize noshade
nowrap readonly rel rev rules scope
scrolling selected shape target text
type valign valuetype vlink].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from AttributeHelper

define_attribute, define_boolean_attribute, define_float_attribute, define_int_attribute, define_string_attribute, inherit_attributes_from, method, typed_attributes

Methods included from Scrolling

#scroll

Methods included from Locators::ClassHelpers

#class_from_string, #element_class_name, #element_matcher_class, #locator, #locator_class, #selector_builder, #selector_builder_class

Methods included from JSExecution

#execute_script, #fire_event, #flash, #focus, #inner_html, #inner_text, #outer_html, #select_text, #selected_text, #text_content

Methods included from Adjacent

#child, #children, #following_sibling, #following_siblings, #parent, #preceding_sibling, #preceding_siblings, #siblings

Methods included from Waitable

#wait_until, #wait_until_present, #wait_while, #wait_while_present

Methods included from EventuallyPresent

#when_enabled, #when_present

Methods included from Container

#a, #abbr, #abbrs, #address, #addresses, #area, #areas, #article, #articles, #as, #aside, #asides, #audio, #audios, #b, #base, #bases, #bdi, #bdis, #bdo, #bdos, #blockquote, #blockquotes, #body, #bodys, #br, #brs, #bs, #button, #buttons, #canvas, #canvases, #caption, #captions, #checkbox, #checkboxes, #circle, #circles, #cite, #cites, #code, #codes, #col, #colgroup, #colgroups, #cols, #data, #datalist, #datalists, #datas, #date_field, #date_fields, #date_time_field, #date_time_fields, #dd, #dds, #defs, #defss, #del, #dels, #desc, #descs, #details, #detailses, #dfn, #dfns, #dialog, #dialogs, #div, #divs, #dl, #dls, #dt, #dts, #element, #elements, #ellipse, #ellipses, #em, #embed, #embeds, #ems, #extract_selector, #field_set, #field_sets, #fieldset, #fieldsets, #figcaption, #figcaptions, #figure, #figures, #file_field, #file_fields, #font, #fonts, #footer, #footers, #foreign_object, #foreign_objects, #form, #forms, #frame, #frames, #frameset, #framesets, #g, #gs, #h1, #h1s, #h2, #h2s, #h3, #h3s, #h4, #h4s, #h5, #h5s, #h6, #h6s, #head, #header, #headers, #heads, #hidden, #hiddens, #hr, #hrs, #html, #htmls, #i, #iframe, #iframes, #image, #images, #img, #imgs, #input, #inputs, #ins, #inses, #is, #kbd, #kbds, #label, #labels, #legend, #legends, #li, #line, #linear_gradient, #linear_gradients, #lines, #link, #links, #lis, #main, #mains, #map, #maps, #mark, #marker, #markers, #marks, #meta, #metadata, #metadatas, #metas, #meter, #meters, #nav, #navs, #noscript, #noscripts, #object, #objects, #ol, #ols, #optgroup, #optgroups, #option, #options, #output, #outputs, #p, #param, #params, #path, #paths, #pattern, #patterns, #picture, #pictures, #polygon, #polygons, #polyline, #polylines, #pre, #pres, #progress, #progresses, #ps, #q, #qs, #radial_gradient, #radial_gradients, #radio, #radio_set, #radios, #rb, #rbs, #rect, #rects, #rp, #rps, #rt, #rtc, #rtcs, #rts, #rubies, #ruby, #s, #samp, #samps, #script, #scripts, #section, #sections, #select, #select_list, #select_lists, #selects, #small, #smalls, #source, #sources, #span, #spans, #ss, #stop, #stops, #strong, #strongs, #styles, #sub, #subs, #summaries, #summary, #sup, #sups, #svg, #svgs, #switch, #switches, #symbol, #symbols, #table, #tables, #tbody, #tbodys, #td, #tds, #template, #templates, #text_field, #text_fields, #text_path, #text_paths, #textarea, #textareas, #tfoot, #tfoots, #th, #thead, #theads, #ths, #time, #times, #title, #titles, #tr, #track, #tracks, #trs, #tspan, #tspans, #u, #ul, #uls, #us, #use, #uses, #var, #vars, #video, #videos, #view, #views, #wbr, #wbrs

Methods included from JSSnippets

#execute_js

Constructor Details

#initialize(query_scope, selector) ⇒ Element

Returns a new instance of Element.

Raises:

  • (ArgumentError)

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/watir/elements/element.rb', line 43

def initialize(query_scope, selector)
  @query_scope = query_scope

  raise ArgumentError, "invalid argument: #{selector.inspect}" unless selector.is_a? Hash

  @element = selector.delete(:element)

  if @element && !(selector.keys - %i[tag_name]).empty?
    Watir.logger.deprecate(':element locator to initialize a relocatable Element', '#cache=', ids: [:element_cache])
  end

  @selector = selector

  build unless @element
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &blk) ⇒ Object (private)


848
849
850
851
852
853
854
855
856
857
858
859
# File 'lib/watir/elements/element.rb', line 848

def method_missing(meth, *args, &blk)
  method = meth.to_s
  if method =~ Locators::Element::SelectorBuilder::WILDCARD_ATTRIBUTE
    attribute_value(meth, *args)
  elsif UserEditable.instance_methods(false).include?(meth) && content_editable?
    @content_editable = true
    extend UserEditable
    send(meth, *args, &blk)
  else
    super
  end
end

Instance Attribute Details

#keywordObject

Returns the value of attribute keyword


18
19
20
# File 'lib/watir/elements/element.rb', line 18

def keyword
  @keyword
end

#selectorObject (readonly)

Returns the value of attribute selector


19
20
21
# File 'lib/watir/elements/element.rb', line 19

def selector
  @selector
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Returns true if two elements are equal.

TODO: Address how this is affected by stale elements TODO: Address how this is affected by HTMLElement vs subclass TODO: Address how this is affected by a non-located element

Examples:

browser.text_field(name: "new_user_first_name") == browser.text_field(name: "new_user_first_name")
#=> true

105
106
107
# File 'lib/watir/elements/element.rb', line 105

def ==(other)
  other.is_a?(self.class) && wd == other.wd
end

#attribute_listArray

Returns list of all attributes. Attributes with special characters are returned as String, rest are returned as a Symbol.

Examples:

browser.pre(id: 'rspec').attribute_list
#=> [:class, :id]

Returns:

  • (Array)

352
353
354
# File 'lib/watir/elements/element.rb', line 352

def attribute_list
  attribute_values.keys
end

#attribute_value(attribute_name) ⇒ String? Also known as: attribute

Returns given attribute value of element.

Examples:

browser.a(id: "link_2").attribute_value "title"
#=> "link_title_2"

Parameters:

  • attribute_name (String, ::Symbol)

Returns:

  • (String, nil)

313
314
315
316
# File 'lib/watir/elements/element.rb', line 313

def attribute_value(attribute_name)
  attribute_name = attribute_name.to_s.tr('_', '-') if attribute_name.is_a?(::Symbol)
  element_call { @element.attribute attribute_name }
end

#attribute_valuesHash Also known as: attributes

Returns all attribute values. Attributes with special characters are returned as String, rest are returned as a Symbol.

Examples:

browser.pre(id: 'rspec').attribute_values
#=> {class:'ruby', id: 'rspec' }

Returns:

  • (Hash)

330
331
332
333
334
335
336
337
338
# File 'lib/watir/elements/element.rb', line 330

def attribute_values
  result = element_call { execute_js(:attributeValues, @element) }
  result.keys.each do |key|
    next unless key == key[/[a-zA-Z\-]*/]

    result[key.tr('-', '_').to_sym] = result.delete(key)
  end
  result
end

#browserWatir::Browser

Returns browser.

Returns:


591
592
593
# File 'lib/watir/elements/element.rb', line 591

def browser
  @query_scope.browser
end

#buildObject

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.


634
635
636
# File 'lib/watir/elements/element.rb', line 634

def build
  selector_builder.build(@selector.dup)
end

#cache=(element) ⇒ 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.

Set the cached element. For use when element can be relocated with the provided selector.


656
657
658
# File 'lib/watir/elements/element.rb', line 656

def cache=(element)
  @element = element
end

#centerSelenium::WebDriver::Point Also known as: centre

Get centre coordinates of element

Examples:

browser.button(name: "new_user_button").centre

Returns:

  • (Selenium::WebDriver::Point)

455
456
457
458
459
460
# File 'lib/watir/elements/element.rb', line 455

def center
  point = location
  dimensions = size
  Selenium::WebDriver::Point.new(point.x + (dimensions['width'] / 2),
                                 point.y + (dimensions['height'] / 2))
end

#class_nameString

Returns value of className property.

Returns:

  • (String)

    value of className property


41
# File 'lib/watir/elements/element.rb', line 41

attribute String, :class_name, :className

#classesArray

Returns list of class values.

Returns:

  • (Array)

298
299
300
# File 'lib/watir/elements/element.rb', line 298

def classes
  class_name.split
end

#click(*modifiers) ⇒ Object

Clicks the element, optionally while pressing the given modifier keys. Note that support for holding a modifier key is currently experimental, and may not work at all.

Examples:

Click an element

browser.element(name: "new_user_button").click

Click an element with shift key pressed

browser.element(name: "new_user_button").click(:shift)

Click an element with several modifier keys pressed

browser.element(name: "new_user_button").click(:shift, :control)

Parameters:

  • modifiers (:shift, :alt, :control, :command, :meta)

    to press while clicking.


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/watir/elements/element.rb', line 151

def click(*modifiers)
  # TODO: Should wait_for_enabled be default, or `Button` specific behavior?
  element_call(:wait_for_enabled) do
    if modifiers.any?
      action = driver.action
      modifiers.each { |mod| action.key_down mod }
      action.click @element
      modifiers.each { |mod| action.key_up mod }

      action.perform
    else
      @element.click
    end
  end

  browser.after_hooks.run
end

#click!Object

Simulates JavaScript click event on element.

Examples:

Click an element

browser.element(name: "new_user_button").click!

176
177
178
179
# File 'lib/watir/elements/element.rb', line 176

def click!
  fire_event :click
  browser.after_hooks.run
end

#double_clickObject

Double clicks the element. Note that browser support may vary.

Examples:

browser.element(name: "new_user_button").double_click

189
190
191
192
# File 'lib/watir/elements/element.rb', line 189

def double_click
  element_call(:wait_for_present) { driver.action.double_click(@element).perform }
  browser.after_hooks.run
end

#double_click!Object

Simulates JavaScript double click event on element.

Examples:

browser.element(name: "new_user_button").double_click!

201
202
203
204
# File 'lib/watir/elements/element.rb', line 201

def double_click!
  fire_event :dblclick
  browser.after_hooks.run
end

#drag_and_drop_by(right_by, down_by) ⇒ Object

Drag and drop this element by the given offsets. Note that browser support may vary.

Examples:

browser.div(id: "draggable").drag_and_drop_by 100, 25

Parameters:

  • right_by (Integer)
  • down_by (Integer)

284
285
286
287
288
289
290
# File 'lib/watir/elements/element.rb', line 284

def drag_and_drop_by(right_by, down_by)
  element_call(:wait_for_present) do
    driver.action
          .drag_and_drop_by(@element, right_by, down_by)
          .perform
  end
end

#drag_and_drop_on(other) ⇒ Object

Drag and drop this element on to another element instance. Note that browser support may vary.

Examples:

a = browser.div(id: "draggable")
b = browser.div(id: "droppable")
a.drag_and_drop_on b

261
262
263
264
265
266
267
268
269
270
271
# File 'lib/watir/elements/element.rb', line 261

def drag_and_drop_on(other)
  assert_is_element other

  value = element_call(:wait_for_present) do
    driver.action
          .drag_and_drop(@element, other.wd)
          .perform
  end
  browser.after_hooks.run
  value
end

#driverObject

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.


467
468
469
# File 'lib/watir/elements/element.rb', line 467

def driver
  @query_scope.driver
end

#enabled?Boolean

Returns true if this element is present and enabled on the page.

Returns:

  • (Boolean)

See Also:


503
504
505
# File 'lib/watir/elements/element.rb', line 503

def enabled?
  element_call(:assert_exists) { @element.enabled? }
end

#exists?Boolean Also known as: exist?

Returns true if element exists. Checking for staleness is deprecated

Returns:

  • (Boolean)

66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/watir/elements/element.rb', line 66

def exists?
  if located? && stale?
    reset!
  elsif located?
    return true
  end

  assert_exists
  true
rescue UnknownObjectException, UnknownFrameException
  false
end

#focused?Boolean

Returns true if this element is focused.

Returns:

  • (Boolean)

375
376
377
# File 'lib/watir/elements/element.rb', line 375

def focused?
  element_call { @element == driver.switch_to.active_element }
end

#hashObject


110
111
112
# File 'lib/watir/elements/element.rb', line 110

def hash
  located? ? @element.hash : super
end

#heightSelenium::WebDriver::Dimension

Get height of element

Examples:

browser.button(name: "new_user_button").height

Returns:

  • (Selenium::WebDriver::Dimension)

429
430
431
# File 'lib/watir/elements/element.rb', line 429

def height
  size['height']
end

#hoverObject

Moves the mouse to the middle of this element. Note that browser support may vary.

Examples:

browser.element(name: "new_user_button").hover

247
248
249
# File 'lib/watir/elements/element.rb', line 247

def hover
  element_call(:wait_for_present) { driver.action.move_to(@element).perform }
end

#idString

temporarily add :id and :class_name manually since they're no longer specified in the HTML spec.

TODO: use IDL from DOM core - dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html

Returns:

  • (String)

    value of id property

See Also:


40
# File 'lib/watir/elements/element.rb', line 40

attribute String, :id, :id

#inspectObject


80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/watir/elements/element.rb', line 80

def inspect
  string = "#<#{self.class}: "
  string << "keyword: #{keyword} " if keyword
  string << "located: #{located?}; "
  string << if @selector.empty?
              '{element: (selenium element)}'
            else
              selector_string
            end
  string << '>'
  string
end

#locateObject

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.


624
625
626
627
628
# File 'lib/watir/elements/element.rb', line 624

def locate
  ensure_context
  locate_in_context
  self
end

#located?Boolean

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.

Returns true if element has been previously located.

Returns:

  • (Boolean)

646
647
648
# File 'lib/watir/elements/element.rb', line 646

def located?
  !!@element
end

#locationSelenium::WebDriver::Point

location of element (x, y)

Examples:

browser.button(name: "new_user_button").location

Returns:

  • (Selenium::WebDriver::Point)

403
404
405
# File 'lib/watir/elements/element.rb', line 403

def location
  element_call { @element.location }
end

#obscured?Boolean

Returns true if the element's center point is covered by a non-descendant element.

Returns:

  • (Boolean)

527
528
529
530
531
532
533
534
# File 'lib/watir/elements/element.rb', line 527

def obscured?
  element_call do
    return true unless present?

    scroll.to
    execute_js(:elementObscured, self)
  end
end

#present?Boolean

Returns true if the element exists and is visible on the page. Returns false if element does not exist or exists but is not visible

Returns:

  • (Boolean)

See Also:


515
516
517
518
519
# File 'lib/watir/elements/element.rb', line 515

def present?
  display_check
rescue UnknownObjectException, UnknownFrameException
  false
end

#reset!Object


616
617
618
# File 'lib/watir/elements/element.rb', line 616

def reset!
  @element = nil
end

#right_click(*modifiers) ⇒ Object

Right clicks the element, optionally while pressing the given modifier keys. Note that support for holding a modifier key is currently experimental, and may not work at all. Also, the browser support may vary.

Examples:

browser.element(name: "new_user_button").right_click

Right click an element with shift key pressed

browser.element(name: "new_user_button").right_click(:shift)

Click an element with several modifier keys pressed

browser.element(name: "new_user_button").right_click(:shift, :alt)

Parameters:

  • modifiers (:shift, :alt, :control, :command, :meta)

    to press while right clicking.


223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/watir/elements/element.rb', line 223

def right_click(*modifiers)
  element_call(:wait_for_present) do
    action = driver.action
    if modifiers.any?
      modifiers.each { |mod| action.key_down mod }
      action.context_click(@element)
      modifiers.each { |mod| action.key_up mod }
      action.perform
    else
      action.context_click(@element).perform
    end
  end

  browser.after_hooks.run
end

#scroll_into_viewSelenium::WebDriver::Point

Scroll until the element is in the view screen

Examples:

browser.button(name: "new_user_button").scroll_into_view

Returns:

  • (Selenium::WebDriver::Point)

388
389
390
391
392
# File 'lib/watir/elements/element.rb', line 388

def scroll_into_view
  Watir.logger.deprecate 'Element#scroll_into_view', 'Element#scroll methods', ids: [:scroll_into_view]

  element_call { @element.location_once_scrolled_into_view }
end

#selector_stringObject

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.


664
665
666
667
668
# File 'lib/watir/elements/element.rb', line 664

def selector_string
  return @selector.inspect if @query_scope.is_a?(Browser)

  "#{@query_scope.selector_string} --> #{@selector.inspect}"
end

#send_keys(*args) ⇒ Object

Sends sequence of keystrokes to element.

Examples:

browser.text_field(name: "new_user_first_name").send_keys "Watir", :return

Parameters:


365
366
367
# File 'lib/watir/elements/element.rb', line 365

def send_keys(*args)
  element_call(:wait_for_writable) { @element.send_keys(*args) }
end

#sizeSelenium::WebDriver::Dimension

size of element (width, height)

Examples:

browser.button(name: "new_user_button").size

Returns:

  • (Selenium::WebDriver::Dimension)

416
417
418
# File 'lib/watir/elements/element.rb', line 416

def size
  element_call { @element.size }
end

#stale?Boolean

Returns true if a previously located element is no longer attached to DOM.

Returns:

  • (Boolean)

Raises:

See Also:


602
603
604
605
606
607
# File 'lib/watir/elements/element.rb', line 602

def stale?
  raise Error, 'Can not check staleness of unused element' unless @element

  ensure_context
  stale_in_context?
end

#stale_in_context?Boolean

Returns:

  • (Boolean)

609
610
611
612
613
614
# File 'lib/watir/elements/element.rb', line 609

def stale_in_context?
  @element.css_value('staleness_check') # any wire call will check for staleness
  false
rescue Selenium::WebDriver::Error::StaleElementReferenceError
  true
end

#style(property = nil) ⇒ String

Returns given style property of this element.

Examples:

browser.button(value: "Delete").style           #=> "border: 4px solid red;"
browser.button(value: "Delete").style("border") #=> "4px solid rgb(255, 0, 0)"

Parameters:

  • property (String) (defaults to: nil)

Returns:

  • (String)

547
548
549
550
551
552
553
# File 'lib/watir/elements/element.rb', line 547

def style(property = nil)
  if property
    element_call { @element.style property }
  else
    attribute_value('style').to_s.strip
  end
end

#tag_nameString

Returns tag name of the element.

Returns:

  • (String)

130
131
132
# File 'lib/watir/elements/element.rb', line 130

def tag_name
  element_call { @element.tag_name.downcase }
end

#textString

Returns the text of the element.

Returns:

  • (String)

120
121
122
# File 'lib/watir/elements/element.rb', line 120

def text
  element_call { @element.text }
end

#to_subtypeObject

Cast this Element instance to a more specific subtype.

Examples:

browser.element(xpath: "//input[@type='submit']").to_subtype
#=> #<Watir::Button>

563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
# File 'lib/watir/elements/element.rb', line 563

def to_subtype
  tag = tag_name
  klass = if tag == 'input'
            case attribute_value(:type)
            when 'checkbox'
              CheckBox
            when 'radio'
              Radio
            when 'file'
              FileField
            when *Button::VALID_TYPES
              Button
            else
              TextField
            end
          else
            Watir.element_class_for(tag)
          end

  klass.new(@query_scope, @selector).tap { |el| el.cache = wd }
end

#visible?Boolean

Returns true if this element is visible on the page. Raises exception if element does not exist

Returns:

  • (Boolean)

489
490
491
492
493
494
# File 'lib/watir/elements/element.rb', line 489

def visible?
  msg = '#visible? behavior will be changing slightly, consider switching to #present? ' \
        '(more details: http://watir.com/element-existentialism/)'
  Watir.logger.warn msg, ids: [:visible_element]
  display_check
end

#wdSelenium::WebDriver::Element

Returns underlying Selenium object of the Watir Element

Returns:

  • (Selenium::WebDriver::Element)

477
478
479
480
# File 'lib/watir/elements/element.rb', line 477

def wd
  assert_exists
  @element
end

#widthSelenium::WebDriver::Dimension

Get width of element

Examples:

browser.button(name: "new_user_button").width

Returns:

  • (Selenium::WebDriver::Dimension)

442
443
444
# File 'lib/watir/elements/element.rb', line 442

def width
  size['width']
end