Class: Element

Inherits:
Object
  • Object
show all
Defined in:
lib/element.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, by, locator) ⇒ Element

Returns a new instance of Element.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/element.rb', line 9

def initialize(name, by, locator)
  @name = name
  @by = by
  @locator = locator
  @element_screenshot = nil #used to store the path of element screenshots for comparison

  # wrapped driver
  @driver = Driver.driver

  # selenium web element
  @element = nil

  #how long to wait between clearing an input and sending keys to it
  @text_padding_time = 0.15
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_sym, *arguments, &block) ⇒ Object



335
336
337
338
339
340
341
342
# File 'lib/element.rb', line 335

def method_missing(method_sym, *arguments, &block)
  Log.debug("called #{method_sym} on element #{@locator} by #{@by_type}")
  if @element.respond_to?(method_sym)
    @element.method(method_sym).call(*arguments, &block)
  else
    super
  end
end

Instance Attribute Details

#byObject (readonly)

Returns the value of attribute by.



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

def by
  @by
end

#locatorObject (readonly)

Returns the value of attribute locator.



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

def locator
  @locator
end

#nameObject (readonly)

Returns the value of attribute name.



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

def name
  @name
end

Instance Method Details

#append_keys(*args) ⇒ Object

add to what’s already in the text field for cases when you don’t want to stomp what’s already in the text field



136
137
138
139
140
141
142
143
144
145
# File 'lib/element.rb', line 136

def append_keys(*args)
  ElementExtensions.highlight(self) if Gridium.config.highlight_verifications
  $verification_passes += 1
  unless element.enabled?
    raise "Browser Error: tried to enter #{args} but the input is disabled"
  end
  element.send_keys(*args)
  sleep @text_padding_time
  # when it's possible to validate for more than non-empty outcomes, do that here
end

#attribute(name) ⇒ Object



89
90
91
# File 'lib/element.rb', line 89

def attribute(name)
  element.attribute(name)
end

#clearObject



111
112
113
114
# File 'lib/element.rb', line 111

def clear
  element.clear
  sleep @text_padding_time
end

#clickObject



120
121
122
123
124
125
126
127
128
129
# File 'lib/element.rb', line 120

def click
  Log.debug("Clicking on #{self}")
  if element.enabled?
    ElementExtensions.highlight(self) if Gridium.config.highlight_verifications
    $verification_passes += 1
    element.click
  else
    Log.error('Cannot click on element.  Element is not present.')
  end
end

#compare_element_screenshot(base_image_path) ⇒ Object



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/element.rb', line 296

def compare_element_screenshot(base_image_path)
  #Returns TRUE if there are no differences, FALSE if there are
  begin
    Log.debug("Loading Images for Comparison...")
    images = [
        ChunkyPNG::Image.from_file(base_image_path),
        ChunkyPNG::Image.from_file(@element_screenshot)
    ]
    #used to store image x,y diff
    diff = []
    Log.debug("Comparing Images...")
    images.first.height.times do |y|
      images.first.row(y).each_with_index do |pixel, x|
        diff << [x,y] unless pixel == images.last[x,y]
      end
    end

    Log.debug("Pixels total:    #{images.first.pixels.length}")
    Log.debug("Pixels changed:  #{diff.length}")
    Log.debug("Pixels changed:  #{(diff.length.to_f / images.first.pixels.length) * 100}%")

    x, y = diff.map{|xy| xy[0]}, diff.map{|xy| xy[1]}

    if x.any? && y.any?
      Log.debug("Differences Detected! Writing Diff Image...")
      name = self.name.gsub(' ', '_')
      #timestamp = Time.now.strftime("%Y_%m_%d__%H_%M_%S")
      element_screenshot_path = File.join($current_run_dir, "#{name}__diff_.png")
      images.last.rect(x.min, y.min, x.max, y.max, ChunkyPNG::Color(0,255,0))
      images.last.save(element_screenshot_path)
      return false
    else
      return true
    end
  rescue Exception => e
    Log.error("There was a problem comparing element images. #{e.to_s}")
  end
end

#displayed?Boolean

Returns:

  • (Boolean)


100
101
102
103
104
105
# File 'lib/element.rb', line 100

def displayed?
  return element.displayed?
rescue StandardError => error
  Log.debug("element.displayed? is false because this error was rescued: #{error}")
  return false
end

#displayed_elementObject



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/element.rb', line 46

def displayed_element
  found_element = nil
  #Found an issue where the element would go stale after it's found
  begin
    elements = @driver.find_elements(@by, @locator)
    elements.each do |element|
      if element.displayed? #removed check for element.enabled
        found_element = element; #this will always return the last displayed element
      end
    end
    if found_element.nil?
      Log.debug "found #{elements.length} element(s) via #{@by} and #{@locator} and 0 are displayed"
    end
  rescue StandardError => error
    Log.debug("element.displayed_element rescued: #{error}")
    if found_element
      Log.warn("An element was found, but it was not displayed on the page. Gridium.config.visible_elements_only set to: #{Gridium.config.visible_elements_only} Element: #{self.to_s}")
    else
      Log.warn("Could not find Element: #{self.to_s}")
    end
  end

  found_element
end

#elementObject



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/element.rb', line 29

def element
  if stale?
    wait = Selenium::WebDriver::Wait.new :timeout => Gridium.config.element_timeout, :interval => 1
    if Gridium.config.visible_elements_only
      wait.until { @element = displayed_element }
    else
      wait.until { @element = @driver.find_element(@by, @locator); Log.debug("Finding element #{self}..."); @element.enabled? }
    end

  end
  @element
end

#element=(e) ⇒ Object



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

def element=(e)
  @element = e
end

#enabled?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/element.rb', line 107

def enabled?
  element.enabled?
end

#find_element(by, locator) ⇒ Element

Search for an element within this element

Parameters:

  • by (Symbol)

    (:css or :xpath)

  • locator (String)

Returns:



255
256
257
258
# File 'lib/element.rb', line 255

def find_element(by, locator)
  Log.debug('Finding element...')
  element.find_element(by, locator)
end

#find_elements(by, locator) ⇒ Array

Search for an elements within this element

Parameters:

  • by (Symbol)

    (:css or :xpath)

  • locator (String)

Returns:

  • (Array)

    elements



268
269
270
# File 'lib/element.rb', line 268

def find_elements(by, locator)
  element.find_elements(by, locator)
end

#hover_awayObject



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

def hover_away
  Log.debug("Hovering away from element (#{self.to_s})...")
  if element.enabled?
    $verification_passes += 1
    ElementExtensions.hover_away(self) # Javascript workaround to above issue
  else
    Log.error('Cannot hover away from element.  Element is not present.')
  end
end

#hover_overObject



173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/element.rb', line 173

def hover_over
  Log.debug("Hovering over element (#{self.to_s})...")
  # @driver.mouse.move_to(element)            # Note: Doesn't work with Selenium 2.42 bindings for Firefox v31
  # @driver.action.move_to(element).perform
  # @driver.mouse_over(@locator)
  if element.enabled?
    $verification_passes += 1
    ElementExtensions.hover_over(self) # Javascript workaround to above issue
  else
    Log.error('Cannot hover over element.  Element is not present.')
  end
end

#locationObject



169
170
171
# File 'lib/element.rb', line 169

def location
  element.location
end

#mouse_overObject

Raw webdriver mouse over



197
198
199
200
201
202
203
204
205
# File 'lib/element.rb', line 197

def mouse_over
  Log.debug("Triggering mouse over for (#{self.to_s})...")
  if element.enabled?
    $verification_passes += 1
    ElementExtensions.mouse_over(self)
  else
    Log.error('Cannot mouse over.  Element is not present.')
  end
end

#present?Boolean

Returns:

  • (Boolean)


93
94
95
96
97
98
# File 'lib/element.rb', line 93

def present?
  return element.enabled?
rescue StandardError => error
  Log.debug("element.present? is false because this error was rescued: #{error}")
  return false
end

#save_element_screenshotObject



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/element.rb', line 272

def save_element_screenshot
  Log.debug ("Capturing screenshot of element...")
  self.scroll_into_view

  timestamp = Time.now.strftime("%Y_%m_%d__%H_%M_%S")
  name = self.name.gsub(' ', '_')
  screenshot_path = File.join($current_run_dir, "#{name}__#{timestamp}.png")
  @driver.save_screenshot(screenshot_path)

  location_x = self.location.x
  location_y = self.location.y
  element_width = self.size.width
  element_height = self.size.height

  # ChunkyPNG commands tap into oily_png (performance-enhanced version of chunky_png)
  image = ChunkyPNG::Image.from_file(screenshot_path.to_s)
  image1 = image.crop(location_x, location_y, element_width, element_height)
  image2 = image1.to_image
  element_screenshot_path = File.join($current_run_dir, "#{name}__#{timestamp}.png")
  image2.save(element_screenshot_path)
  @element_screenshot = element_screenshot_path
  SpecData.screenshots_captured.push("#{name}__#{timestamp}.png")
end

#scroll_into_viewObject



207
208
209
210
211
212
213
214
# File 'lib/element.rb', line 207

def scroll_into_view
  if element.enabled?
    $verification_passes += 1
    ElementExtensions.scroll_to(self)
  else
    Log.error('Cannot scroll element into view.  Element is not present.')
  end
end

#selected?Boolean

Returns:

  • (Boolean)


230
231
232
# File 'lib/element.rb', line 230

def selected?
  element.selected?
end

#send_keys(*args) ⇒ Object Also known as: text=

overwrite to what’s already in the text field and validate afterward



152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/element.rb', line 152

def send_keys(*args)
  ElementExtensions.highlight(self) if Gridium.config.highlight_verifications
  $verification_passes += 1
  unless element.enabled?
    raise "Browser Error: tried to enter #{args} but the input is disabled"
  end
  if only_symbols? *args
    append_keys *args
  else
    _stomp_input_text *args
    field_empty_afterward? *args
  end
end

#sizeObject



226
227
228
# File 'lib/element.rb', line 226

def size
  element.size
end

#submitObject



238
239
240
# File 'lib/element.rb', line 238

def submit
  element.submit
end

#tag_nameObject



234
235
236
# File 'lib/element.rb', line 234

def tag_name
  element.tag_name
end

#textObject



242
243
244
245
# File 'lib/element.rb', line 242

def text
  #this is used for text based elements
  element.text
end

#to_sObject



25
26
27
# File 'lib/element.rb', line 25

def to_s
  "'#{@name}' (By:#{@by} => '#{@locator}')"
end

#trigger_onblurObject



216
217
218
219
220
221
222
223
224
# File 'lib/element.rb', line 216

def trigger_onblur
  Log.debug("Triggering onblur for (#{self.to_s})...")
  if element.enabled?
    $verification_passes += 1
    ElementExtensions.trigger_onblur(self)
  else
    Log.error('Cannot trigger onblur.  Element is not present.')
  end
end

#valueObject



116
117
118
# File 'lib/element.rb', line 116

def value
  element.attribute "value"
end

#verify(timeout: nil) ⇒ Object

soft failure, will not kill test immediately



76
77
78
79
80
# File 'lib/element.rb', line 76

def verify(timeout: nil)
  Log.debug('Verifying new element...')
  timeout = Gridium.config.element_timeout if timeout.nil?
  ElementVerification.new(self, timeout)
end

#wait_until(timeout: nil) ⇒ Object

hard failure, will kill test immediately



83
84
85
86
87
# File 'lib/element.rb', line 83

def wait_until(timeout: nil)
  Log.debug('Waiting for new element...')
  timeout = Gridium.config.element_timeout if timeout.nil?
  ElementVerification.new(self, timeout, fail_test: true)
end