Class: Watir::Element

Inherits:
Object
  • Object
show all
Extended by:
AttributeHelper
Includes:
Adjacent, Container, Exception, JSExecution, Locators::ClassHelpers, Scrolling, SearchContext, 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 SearchContext

#check_condition, #element_call, #exists?, #unknown_exception, #wait_for_exists

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_while

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, #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)

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

def initialize(query_scope, selector)
  @query_scope = query_scope

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

  selector[:index] = 0 if selector.empty?
  @element = selector.delete(:element)

  selector = {} if @element && !(selector.keys - [:tag_name]).empty?

  @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)


790
791
792
793
794
795
796
797
798
799
800
801
# File 'lib/watir/elements/element.rb', line 790

def method_missing(meth, *args, &blk)
  method = meth.to_s
  if Locators::Element::SelectorBuilder::WILDCARD_ATTRIBUTE.match?(method)
    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.


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

def keyword
  @keyword
end

#selectorObject (readonly)

Returns the value of attribute selector.


21
22
23
# File 'lib/watir/elements/element.rb', line 21

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

79
80
81
# File 'lib/watir/elements/element.rb', line 79

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)

370
371
372
# File 'lib/watir/elements/element.rb', line 370

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)

331
332
333
334
# File 'lib/watir/elements/element.rb', line 331

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)

348
349
350
351
352
353
354
355
356
# File 'lib/watir/elements/element.rb', line 348

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:


606
607
608
# File 'lib/watir/elements/element.rb', line 606

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.


652
653
654
# File 'lib/watir/elements/element.rb', line 652

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.


674
675
676
# File 'lib/watir/elements/element.rb', line 674

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)

458
459
460
461
462
463
# File 'lib/watir/elements/element.rb', line 458

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


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

attribute String, :class_name, :className

#classesArray

Returns list of class values.

Returns:

  • (Array)

316
317
318
# File 'lib/watir/elements/element.rb', line 316

def classes
  class_name.split
end

#click(*modifiers, scroll_to: :center) ⇒ 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.


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/watir/elements/element.rb', line 125

def click(*modifiers, scroll_to: :center)
  element_call(:wait_for_enabled) do
    if modifiers.any?
      scroll.to(scroll_to) if scroll_to
      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!

170
171
172
173
# File 'lib/watir/elements/element.rb', line 170

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

#double_click(scroll_to: :center) ⇒ Object

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

Examples:

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

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

def double_click(scroll_to: :center)
  element_call(:wait_for_present) do
    scroll.to(scroll_to) if scroll_to
    driver.action.double_click(@element).perform
  end
  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, scroll_to: :center) ⇒ 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
browser.div(id: "draggable").drag_and_drop_by 100, 25, scroll_to: :center

Parameters:

  • right_by (Integer)
  • down_by (Integer)
  • scroll_to (Symbol) (defaults to: :center)

301
302
303
304
305
306
307
308
# File 'lib/watir/elements/element.rb', line 301

def drag_and_drop_by(right_by, down_by, scroll_to: :center)
  element_call(:wait_for_present) do
    scroll.to(scroll_to) if scroll_to
    driver.action
          .drag_and_drop_by(@element, right_by, down_by)
          .perform
  end
end

#drag_and_drop_on(other, scroll_to: :center) ⇒ 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
a.drag_and_drop_on b, scroll_to: :center

273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/watir/elements/element.rb', line 273

def drag_and_drop_on(other, scroll_to: :center)
  assert_is_element other

  value = element_call(:wait_for_present) do
    scroll.to(scroll_to) if scroll_to
    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.


470
471
472
# File 'lib/watir/elements/element.rb', line 470

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

#focused?Boolean

Returns true if this element is focused.

Returns:

  • (Boolean)

393
394
395
# File 'lib/watir/elements/element.rb', line 393

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

#hashObject


84
85
86
# File 'lib/watir/elements/element.rb', line 84

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)

432
433
434
# File 'lib/watir/elements/element.rb', line 432

def height
  size['height']
end

#hover(scroll_to: :center) ⇒ Object

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

Examples:

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

255
256
257
258
259
260
# File 'lib/watir/elements/element.rb', line 255

def hover(scroll_to: :center)
  element_call(:wait_for_present) do
    scroll.to(scroll_to) if scroll_to
    driver.action.move_to(@element).perform
  end
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:


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

attribute String, :id, :id

#in_viewport?Boolean

Returns true if the top of the element is visible in the viewport.

Returns:

  • (Boolean)

547
548
549
# File 'lib/watir/elements/element.rb', line 547

def in_viewport?
  element_call { execute_js(:isElementInViewport, @element) }
end

#inspectObject


60
61
62
63
64
65
# File 'lib/watir/elements/element.rb', line 60

def inspect
  keyword_string = keyword ? "keyword: #{keyword} " : ''
  located = "located: #{located?}; "
  element_string = @selector.empty? ? '{element: (selenium element)}' : selector_string
  "#<#{self.class}: #{keyword_string}#{located}#{element_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.

Raises:


639
640
641
642
643
644
645
646
# File 'lib/watir/elements/element.rb', line 639

def locate
  msg = 'Can not relocate a Watir element initialized by a Selenium element'
  raise LocatorException, msg if @selector.empty?

  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)

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

def located?
  !!@element
end

#locationSelenium::WebDriver::Point

location of element (x, y)

Examples:

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

Returns:

  • (Selenium::WebDriver::Point)

406
407
408
# File 'lib/watir/elements/element.rb', line 406

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)

532
533
534
535
536
537
538
539
# File 'lib/watir/elements/element.rb', line 532

def obscured?
  element_call do
    return true unless present?

    scroll.to :bottom unless in_viewport?
    execute_js(:elementObscured, self)
  end
end

#present?Boolean Also known as: visible?

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
520
521
522
523
# File 'lib/watir/elements/element.rb', line 515

def present?
  assert_exists
  @element.displayed?
rescue UnknownObjectException, UnknownFrameException
  false
rescue Selenium::WebDriver::Error::StaleElementReferenceError
  reset!
  retry
end

#reset!Object


631
632
633
# File 'lib/watir/elements/element.rb', line 631

def reset!
  @element = nil
end

#right_click(*modifiers, scroll_to: :center) ⇒ 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.

modifiers to press while right clicking and scroll position.

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)

Click an element with several modifier keys pressed and scroll position

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

Parameters:

  • (:shift, :alt, :control, :command, :meta, scroll_to: :center)

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/watir/elements/element.rb', line 227

def right_click(*modifiers, scroll_to: :center)
  element_call(:wait_for_present) do
    scroll.to(scroll_to) if scroll_to
    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

#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.


682
683
684
685
686
# File 'lib/watir/elements/element.rb', line 682

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:


383
384
385
# File 'lib/watir/elements/element.rb', line 383

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

#set(*args) ⇒ Object

Determines the correct action based on subtype and takes it. Default is to click element


148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/watir/elements/element.rb', line 148

def set(*args)
  subtype = to_subtype
  if subtype.is_a?(Radio) && [String, Regexp].include?(args.first.class)
    RadioSet.new(@query_scope, selector).set(*args)
  elsif subtype.class.included_modules.include?(UserEditable) || subtype.public_methods(false).include?(:set)
    subtype.set(*args)
  elsif @content_editable || content_editable?
    @content_editable = true
    extend UserEditable
    set(*args)
  elsif args.empty? || args.first
    click(*args)
  end
end

#shadow_rootWatir::ShadowRoot

Returns shadow root of element

Returns:


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

def shadow_root
  ShadowRoot.new(self)
end

#sizeSelenium::WebDriver::Dimension

size of element (width, height)

Examples:

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

Returns:

  • (Selenium::WebDriver::Dimension)

419
420
421
# File 'lib/watir/elements/element.rb', line 419

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:


617
618
619
620
621
622
# File 'lib/watir/elements/element.rb', line 617

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)

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

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)

562
563
564
565
566
567
568
# File 'lib/watir/elements/element.rb', line 562

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)

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

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

#textString

Returns the text of the element.

Returns:

  • (String)

94
95
96
# File 'lib/watir/elements/element.rb', line 94

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>

578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/watir/elements/element.rb', line 578

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

#wdSelenium::WebDriver::Element Also known as: we

Returns underlying Selenium object of the Watir Element

Returns:

  • (Selenium::WebDriver::Element)

480
481
482
483
# File 'lib/watir/elements/element.rb', line 480

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)

445
446
447
# File 'lib/watir/elements/element.rb', line 445

def width
  size['width']
end