Module: RWebUnit::Driver

Includes:
ITestPlugin, Popup
Included in:
AbstractWebPage, RSpecHelper, TestScript, WebTestCase
Defined in:
lib/rwebunit/driver.rb

Constant Summary collapse

@@default_polling_interval =

second

1
@@default_timeout =

seconds

30

Instance Method Summary collapse

Methods included from Popup

#check_for_popups, #check_for_security_alerts, #click_button_in_javascript_popup, #click_button_in_popup_after, #click_button_in_security_alert_popup, #click_button_in_security_information_popup, #click_popup_window, #ie_popup_clicker, #prepare_to_click_button_in_popup, #start_checking_js_dialog, #verify_alert

Methods included from ITestPlugin

#connect_to_itest, #debug, #dump_caller_stack, #operation_delay

Instance Method Details

#absolutify_url(src, base_url, parent_url) ⇒ Object

change

<script type="text/javascript" src="/javascripts/prototype.js"></script>

to

<script type="text/javascript" src="http://itest2.com/javascripts/prototype.js"></script>


422
423
424
425
426
427
428
429
430
# File 'lib/rwebunit/driver.rb', line 422

def absolutify_url(src, base_url, parent_url)
  if src.nil? || src.empty? || src == "//:" || src =~ /\s*http:\/\//i
    return src
  end
  
  return "#{base_url}#{src}" if src =~ /^\s*\//
  return "#{parent_url}#{src}" if parent_url
  return src
end

#absolutize_page(content, base_url, current_url_parent) ⇒ Object

<link rel=“stylesheet” type=“text/css” href=“/stylesheets/default.css” /> ‘<script type=“text/javascript” src=“www.jeroenwijering.com/embed/swfobject.js”></script>’ <script type=“text/javascript” src=“/javascripts/prototype.js”></script> <script type=“text/javascript” src=“/javascripts/scriptaculous.js?load=effects,builder”></script> <script type=“text/javascript” src=“/javascripts/extensions/gallery/lightbox.js”></script> <link href=“/stylesheets/extensions/gallery/lightbox.css” rel=“stylesheet” type=“text/css” /> <img src=“images/mission_48.png” />



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/rwebunit/driver.rb', line 382

def absolutize_page(content, base_url, current_url_parent)
  modified_content = ""
  content.each_line do |line|
    if line =~ /<script\s+.*src=["'']?(.*)["'].*/i then
      script_src = $1
      substitute_relative_path_in_src_line(line, script_src, base_url, current_url_parent)
    elsif line =~ /<link\s+.*href=["'']?(.*)["'].*/i then
      link_href = $1
      substitute_relative_path_in_src_line(line, link_href, base_url, current_url_parent)
    elsif line =~ /<img\s+.*src=["'']?(.*)["'].*/i then
      img_src = $1
      substitute_relative_path_in_src_line(line, img_src, base_url, current_url_parent)
    end

    modified_content += line
  end
  return modified_content
end

#absolutize_page_hpricot(content, base_url, parent_url) ⇒ Object

absolutize_page referencs using hpricot



403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/rwebunit/driver.rb', line 403

def absolutize_page_hpricot(content, base_url, parent_url)
  begin
    require 'hpricot'
    doc = Hpricot(content)
    base_url.slice!(-1) if ends_with?(base_url, "/")
    (doc/'link').each { |e| e['href'] = absolutify_url(e['href'], base_url, parent_url) || ""}
    (doc/'img').each { |e| e['src'] = absolutify_url(e['src'], base_url, parent_url) || ""}        
    (doc/'script').each { |e| e['src'] = absolutify_url(e['src'], base_url, parent_url) || ""}
    return doc.to_html
  rescue => e
    absolutize_page(content, base_url, parent_url)
  end
end

#ajax_wait_for_element(element_id, seconds, status = 'show', check_interval = @@default_polling_interval) ⇒ Object

Wait for specific seconds for an Ajax update finish. Trick: In your Rails application,

  :loading 	=> "Element.show('search_indicator');
  :complete	=> "Element.hide('search_indicator');

<%= image_tag("indicator.gif", :id => 'search_indicator', :style => 'display:none') %>

Typical usage:

ajax_wait_for_element("search_indicator", 30)
ajax_wait_for_element("search_indicator", 30, "show")
ajax_wait_for_element("search_indicator", 30, "hide")
ajax_wait_for_element("search_indicator", 30, "show", 5) # check every 5 seconds

Warning: this method has not been fully tested, if you are not using Rails, change your parameter accordingly.



596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
# File 'lib/rwebunit/driver.rb', line 596

def ajax_wait_for_element(element_id, seconds, status='show', check_interval = @@default_polling_interval)
  count = 0
  check_interval = 1 if check_interval < 1 or check_interval > seconds
  while count < (seconds / check_interval) do
    search_indicator = @web_browser.element_by_id(element_id)
    search_indicator_outer_html = search_indicator.outerHtml if search_indicator
    if status == 'hide'
      return true if search_indicator_outer_html and !search_indicator_outer_html.include?('style="DISPLAY: none"')
    else
      return true if search_indicator_outer_html and search_indicator_outer_html.include?('style="DISPLAY: none"')
    end
    sleep check_interval if check_interval > 0 and check_interval < 5 * 60 # wait max 5 minutes
    count += 1
  end
  return false
end

#allow(&block) ⇒ Object Also known as: shall_allow, allowing

Does not provide real function, other than make enhancing test syntax

Example:

allow { click_button('Register') }


547
548
549
# File 'lib/rwebunit/driver.rb', line 547

def allow(&block)
  yield
end

#attach_browser(how, what, options = {}) ⇒ Object

Attach to existinb browser window

attach_browser(:title,    )


166
167
168
169
170
171
172
173
174
# File 'lib/rwebunit/driver.rb', line 166

def attach_browser(how, what, options = {})
  options.merge!(:browser => is_firefox? ? "Firefox" : "IE")
  begin
    options.merge!(:base_url => browser.context.base_url)
  rescue => e
    puts "error to attach to browser: #{e}"
  end
  WebBrowser.attach_browser(how, what, options)
end

#begin_at(url) ⇒ Object

Starting browser with a URL

Example:

begin_at("http://www.itest2.com")


121
122
123
124
# File 'lib/rwebunit/driver.rb', line 121

def begin_at(url)
  dump_caller_stack
  @web_browser.begin_at(url)
end

#browserObject

return the underlying RWebUnit::Browser object



70
71
72
# File 'lib/rwebunit/driver.rb', line 70

def browser
  @web_browser
end

#cell_with_id(cell_id) ⇒ Object Also known as: table_data_with_id

return the text of specific (identified by attribute “id”) ta tag For page containing

<td id="preferred_recorder">iTest2/Watir Recorder</span>

td_with_id(“preferred_recorder”) # => iTest2/Watir Recorder



484
485
486
# File 'lib/rwebunit/driver.rb', line 484

def cell_with_id(cell_id)
  cell(:id, cell_id).text
end

#click_button_with_image_src_contains(image_filename) ⇒ Object Also known as: click_button_with_image

Click image buttion with image source name

For an image submit button <input name=“submit” type=“image” src=“/images/search_button.gif”>

click_button_with_image("search_button.gif")


292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/rwebunit/driver.rb', line 292

def click_button_with_image_src_contains(image_filename)
  dump_caller_stack
  operation_delay
  found = nil
  raise "no buttons in this page" if buttons.length <= 0
  buttons.each { |btn|
    if btn && btn.src  && btn.src.include?(image_filename) then
      found = btn
      break
    end
  }
  raise "not image button with src: #{image_filename} found" if found.nil?
  found.click
end

#close_all_browsersObject

Close all opening browser windows



92
93
94
95
96
97
98
# File 'lib/rwebunit/driver.rb', line 92

def close_all_browsers
  if is_firefox?
    FireWatir::Firefox.close_all
  else
    Watir::IE.close_all
  end
end

#close_browserObject Also known as: close_ie

Close the current browser window (started by the script). If no browser started, then close all browser windows.



78
79
80
81
82
83
84
85
86
# File 'lib/rwebunit/driver.rb', line 78

def close_browser
  if @web_browser
    # Old iTest2 version
    # @web_browser.close_browser unless $ITEST2_LEAVE_BROWSER_OPEN_AFTER_RUN
    @web_browser.close_browser
  else
    WebBrowser.close_all_browsers
  end
end

#contains_text(text) ⇒ Object



284
285
286
# File 'lib/rwebunit/driver.rb', line 284

def contains_text(text)
  @web_browser.contains_text(text)
end

#contextObject



113
114
115
# File 'lib/rwebunit/driver.rb', line 113

def context
  @web_browser.context
end

#dump_response(stream = nil) ⇒ Object


For debugging




327
328
329
# File 'lib/rwebunit/driver.rb', line 327

def dump_response(stream = nil)
  @web_browser.dump_response(stream)
end

#element_by_id(elem_id) ⇒ Object

Identify DOM element by ID Warning: it is only supported on IE



320
321
322
# File 'lib/rwebunit/driver.rb', line 320

def element_by_id(elem_id)
  @web_browser.element_by_id(elem_id)
end

#element_text(elem_id) ⇒ Object

Warning: this does not work well with Firefox yet.



314
315
316
# File 'lib/rwebunit/driver.rb', line 314

def element_text(elem_id)
  @web_browser.element_value(elem_id)
end

#ends_with?(str, suffix) ⇒ Boolean

Returns:

  • (Boolean)


444
445
446
447
# File 'lib/rwebunit/driver.rb', line 444

def ends_with?(str, suffix)
  suffix = suffix.to_s
  str[-suffix.length, suffix.length] == suffix
end

#enter_text_with_id(textfield_id, value) ⇒ Object

for text field can be easier to be identified by attribute “id” instead of “name”, not recommended though



278
279
280
281
282
# File 'lib/rwebunit/driver.rb', line 278

def enter_text_with_id(textfield_id, value)
  dump_caller_stack
  operation_delay
  text_field(:id, textfield_id).set(value)
end

#expect_page(page_clazz, argument = nil) ⇒ Object

Verify the next page following an operation.

Typical usage:

.
expect_page HomePage


105
106
107
108
109
110
111
# File 'lib/rwebunit/driver.rb', line 105

def expect_page(page_clazz, argument = nil)
  if argument
    page_clazz.new(@web_browser, argument)
  else
    page_clazz.new(@web_browser)
  end
end

#failsafe(&block) ⇒ Object Also known as: fail_safe

try operation, ignore if errors occur

Example:

failsafe { click_link("Logout") }  # try logout, but it still OK if not being able to (already logout))


557
558
559
560
561
562
# File 'lib/rwebunit/driver.rb', line 557

def failsafe(&block)
  begin
    yield
  rescue =>e
  end
end

#firefoxObject

Return the FireWatir::Firefox instance



134
135
136
# File 'lib/rwebunit/driver.rb', line 134

def firefox
  @web_browser.firefox
end

#goto_page(page) ⇒ Object Also known as: visit

Go to another page on the testing site.

open_browser("http://www.itest2.com")
goto_page("/demo")  # visit page http://www.itest2.com/demo


148
149
150
151
152
# File 'lib/rwebunit/driver.rb', line 148

def goto_page(page)
  operation_delay
  dump_caller_stack
  @web_browser.goto_page(page) if @web_browser
end

#goto_url(url) ⇒ Object

Go to another web site, normally different site being tested on

open_browser("http://www.itest2.com")
goto_url("http://myorganized.info")


159
160
161
# File 'lib/rwebunit/driver.rb', line 159

def goto_url(url)
  @web_browser.goto_url url
end

#ieObject

Return the Watir::IE instance



128
129
130
# File 'lib/rwebunit/driver.rb', line 128

def ie
  @web_browser.ie
end

#is_firefox?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/rwebunit/driver.rb', line 138

def is_firefox?
  @web_browser.is_firefox? if @web_browser
end

#is_linux?Boolean

Returns:

  • (Boolean)


498
499
500
# File 'lib/rwebunit/driver.rb', line 498

def is_linux?
  RUBY_PLATFORM.downcase.include?("linux")
end

#is_mac?Boolean

Returns:

  • (Boolean)


490
491
492
# File 'lib/rwebunit/driver.rb', line 490

def is_mac?
  RUBY_PLATFORM.downcase.include?("darwin")
end

#is_windows?Boolean

Returns:

  • (Boolean)


494
495
496
# File 'lib/rwebunit/driver.rb', line 494

def is_windows?
  RUBY_PLATFORM.downcase.include?("mswin") or RUBY_PLATFORM.downcase.include?("mingw32")
end

#label_with_id(label_id) ⇒ Object

return the text of specific (identified by attribute “id”) label tag For page containing

<label id="preferred_ide">iTest2</label>

label_with_id(“preferred_ids”) # => iTest2



468
469
470
# File 'lib/rwebunit/driver.rb', line 468

def label_with_id(label_id)
  label(:id, label_id.to_s).text
end

#new_popup_window(options) ⇒ Object



308
309
310
# File 'lib/rwebunit/driver.rb', line 308

def new_popup_window(options)
  @web_browser.new_popup_window(options)
end

#on(page) {|page| ... } ⇒ Object

Example:

on @page do |i|
  i.enter_text('btn1')
  i.click_button('btn1')
end

Yields:

  • (page)


524
525
526
# File 'lib/rwebunit/driver.rb', line 524

def on(page, &block)
  yield page
end

#open_browser(base_url = nil, options = {}) ⇒ Object Also known as: open_browser_with

open a browser, and set base_url via hash, but does not acually

example:

open_browser :base_url => http://localhost:8080

There are 3 ways to set base url

1. pass as first argument
2. If running using iTest2, used as confiured
3. Use default value set


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rwebunit/driver.rb', line 30

def open_browser(base_url = nil, options = {})
  base_url ||= $ITEST2_PROJECT_BASE_URL
  base_url ||= $BASE_URL
  raise "base_url must be set" if base_url.nil?

  default_options = {:speed => "fast",
    :visible => true,
    :highlight_colour => 'yellow',
    :close_others => true,
    :start_new => false, 	# start a new browser always
  :go => true}

  options = default_options.merge options
  options[:firefox] = true if "Firefox" == $ITEST2_BROWSER || "Firefox" == $BROWSER
  ($ITEST2_HIDE_BROWSER) ? $HIDE_IE = true : $HIDE_IE = false

  if base_url =~ /^file:/
    uri_base = base_url
  else
    uri = URI.parse(base_url)
    uri_base = "#{uri.scheme}://#{uri.host}:#{uri.port}"
  end

  if options[:start_new]
    @web_browser = WebBrowser.new(uri_base, nil, options)
  else
    @web_browser = WebBrowser.reuse(uri_base, options) # Reuse existing browser
  end

  if base_url =~ /^file:/
    goto_url(base_url) # for files, no base url
  else
    (uri.path.length == 0) ?  begin_at("/") :  begin_at(uri.path) if options[:go]
  end

  return @web_browser
end

#page_sourceObject

current page source (in HTML)



455
456
457
# File 'lib/rwebunit/driver.rb', line 455

def page_source
  @web_browser.page_source
end

#page_textObject

return plain text view of page



460
461
462
# File 'lib/rwebunit/driver.rb', line 460

def page_text
  @web_browser.text
end

#page_titleObject

current web page title



450
451
452
# File 'lib/rwebunit/driver.rb', line 450

def page_title
  @web_browser.page_title
end

#repeat_try(num_tries = @@default_timeout || 30, interval = @@default_polling_interval || 1, &block) ⇒ Object

Try the operation up to specified times, and sleep given interval (in seconds) Error will be ignored until timeout Example

repeat_try(3, 2) { click_button('Search' } # 3 times, 6 seconds in total
repeat_try { click_button('Search' } # using default 5 tries, 2 second interval


665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
# File 'lib/rwebunit/driver.rb', line 665

def repeat_try(num_tries = @@default_timeout || 30, interval = @@default_polling_interval || 1, &block)
  num_tries ||= 1
  (num_tries - 1).times do |num|
    begin
      yield
      return
    rescue => e
      # puts "debug: #{num} failed: #{e}"
      sleep interval
    end
  end

  # last try, throw error if still fails
  begin
    yield
  rescue => e
    raise e.to_s + " after trying #{num_tries} times every #{interval} seconds"
  end
  yield
end

#save_current_page(options = {}) ⇒ Object

For current page souce to a file in specified folder for inspection

save_current_page(:dir => "C:\\mysite", filename => "abc", :replacement => true)


334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/rwebunit/driver.rb', line 334

def save_current_page(options = {})
  default_options = {:replacement => true}
  options = default_options.merge(options)
  if options[:dir]
    # already defined the dir
    to_dir = options[:dir]
  elsif $ITEST2_RUNNING_SPEC_ID && $ITEST2_WORKING_DIR

    $ITEST2_DUMP_DIR = File.join($ITEST2_WORKING_DIR, "dump")
    FileUtils.mkdir($ITEST2_DUMP_DIR) unless File.exists?($ITEST2_DUMP_DIR)

    spec_run_id = $ITEST2_RUNNING_SPEC_ID
    spec_run_dir_name = spec_run_id.to_s.rjust(4, "0") unless spec_run_id == "unknown"
    to_dir = File.join($ITEST2_DUMP_DIR, spec_run_dir_name)
  else
    to_dir = ENV['TEMP_DIR'] || "C:\\temp"
  end

  if options[:filename]
    file_name = options[:filename]
  else
    file_name = Time.now.strftime("%m%d%H%M%S") + ".html"
  end

  Dir.mkdir(to_dir) unless File.exists?(to_dir)
  file = File.join(to_dir, file_name)

  content = page_source
  base_url = @web_browser.context.base_url
  current_url = @web_browser.url
  current_url =~ /(.*\/).*$/
  current_url_parent = $1
  if options[:replacement] && base_url =~ /^http:/
    File.new(file, "w").puts absolutize_page_hpricot(content, base_url, current_url_parent)
  else
    File.new(file, "w").puts content
  end

end

#shall_not_allow(&block) ⇒ Object Also known as: do_not_allow

fail the test if user can perform the operation

Example:

shall_not_allow { 1/0 }


532
533
534
535
536
537
538
539
540
# File 'lib/rwebunit/driver.rb', line 532

def shall_not_allow(&block)
  operation_performed_ok = false
  begin
    yield
    operation_performed_ok  = true
  rescue
  end
  raise "Operation shall not be allowed" if operation_performed_ok
end

#span_with_id(span_id) ⇒ Object

return the text of specific (identified by attribute “id”) span tag For page containing

<span id="preferred_recorder">iTest2/Watir Recorder</span>

span_with_id(“preferred_recorder”) # => iTest2/Watir Recorder



476
477
478
# File 'lib/rwebunit/driver.rb', line 476

def span_with_id(span_id)
  span(:id, span_id).text
end

#substitute_relative_path_in_src_line(line, script_src, host_url, page_parent_url) ⇒ Object

substut



433
434
435
436
437
438
439
440
441
442
# File 'lib/rwebunit/driver.rb', line 433

def substitute_relative_path_in_src_line(line, script_src, host_url, page_parent_url)
  unless script_src =~ /^["']?http:/
    host_url.slice!(-1) if ends_with?(host_url, "/")
    if script_src =~ /^\s*\// # absolute_path
      line.gsub!(script_src, "#{host_url}#{script_src}")
    else  #relative_path
      line.gsub!(script_src, "#{page_parent_url}#{script_src}")
    end
  end
end

#support_utf8Object Also known as: support_unicode

Support browser (IE) operations using unicode

Example:
 click_button("Google 搜索")


505
506
507
508
509
510
# File 'lib/rwebunit/driver.rb', line 505

def support_utf8
  if is_windows?
    require 'win32ole'
    WIN32OLE.codepage = WIN32OLE::CP_UTF8
  end
end

#symbol_to_sequence(symb) ⇒ Object

Convert :first to 1, :second to 2, and so on…



715
716
717
718
719
720
721
722
723
724
725
726
727
728
# File 'lib/rwebunit/driver.rb', line 715

def symbol_to_sequence(symb)
  value = { :zero => 0,
    :first => 1,
    :second => 2,
    :third => 3,
    :fourth => 4,
    :fifth => 5,
    :sixth => 6,
    :seventh => 7,
    :eighth => 8,
    :ninth => 9,
  :tenth => 10 }[symb]
  return value || symb.to_i
end

#try(timeout = @@default_timeout, polling_interval = @@default_polling_interval || 1, &block) ⇒ Object Also known as: try_upto

Try the operation up to specified timeout (in seconds), and sleep given interval (in seconds). Error will be ignored until timeout Example

try { click_link('waiting')}
try(10, 2) { click_button('Search' } # try to click the 'Search' button upto 10 seconds, try every 2 seconds
try { click_button('Search' }


694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
# File 'lib/rwebunit/driver.rb', line 694

def try(timeout = @@default_timeout, polling_interval = @@default_polling_interval || 1, &block)
  start_time = Time.now

  last_error = nil
  until (duration = Time.now - start_time) > timeout
    begin
      return if yield
      last_error = nil
    rescue => e
      last_error = e
    end
    sleep polling_interval
  end

  raise "Timeout after #{duration.to_i} seconds with error: #{last_error}." if last_error
  raise "Timeout after #{duration.to_i} seconds."
end

#use_current_browser(how = :title, what = /.*/) ⇒ Object

Reuse current an opened browser window instead of opening a new one example:

use_current_browser(:title, /.*/) # use what ever browser window
use_current_browser(:title, "iTest2") # use browser window with title "iTest2"


180
181
182
# File 'lib/rwebunit/driver.rb', line 180

def use_current_browser(how = :title, what = /.*/)
  @web_browser = WebBrowser.attach_browser(how, what)
end

#wait_for_element(element_id, timeout = @@default_timeout, interval = @@default_polling_interval) ⇒ Object

Wait the element with given id to be present in web page

Warning: this not working in Firefox, try use wait_util or try instead



616
617
618
619
620
621
622
623
624
625
# File 'lib/rwebunit/driver.rb', line 616

def wait_for_element(element_id, timeout = @@default_timeout, interval = @@default_polling_interval)
  start_time = Time.now
  #TODO might not work with Firefox
  until @web_browser.element_by_id(element_id) do
    sleep(interval)
    if (Time.now - start_time) > timeout
      raise RuntimeError, "failed to find element: #{element_id} for max #{timeout}"
    end
  end
end

#wait_until(timeout = @@default_timeout || 30, polling_interval = @@default_polling_interval || 1, &block) ⇒ Object

Execute the provided block until either (1) it returns true, or (2) the timeout (in seconds) has been reached. If the timeout is reached, a TimeOutException will be raised. The block will always execute at least once.

This does not handle error, if the given block raise error, the statement finish with error Examples:

wait_until {puts 'hello'}
wait_until { div(:id, :receipt_date).exists? }


576
577
578
579
# File 'lib/rwebunit/driver.rb', line 576

def wait_until(timeout = @@default_timeout || 30, polling_interval = @@default_polling_interval || 1, &block)
  waiter = Watir::Waiter.new(timeout, polling_interval)
  waiter.wait_until { yield }
end