rwebunit 1.0.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +68 -4
- data/README +32 -32
- data/Rakefile +38 -26
- data/lib/rspec_extensions.rb +22 -86
- data/lib/rwebunit/assert.rb +241 -130
- data/lib/rwebunit/context.rb +1 -1
- data/lib/rwebunit/driver.rb +436 -271
- data/lib/rwebunit/itest_plugin.rb +23 -2
- data/lib/rwebunit/popup.rb +147 -0
- data/lib/rwebunit/rspec_helper.rb +12 -56
- data/lib/rwebunit/test_script.rb +8 -0
- data/lib/rwebunit/test_utils.rb +96 -23
- data/lib/rwebunit/using_pages.rb +49 -0
- data/lib/rwebunit/web_browser.rb +27 -5
- data/lib/rwebunit/web_page.rb +13 -17
- data/lib/rwebunit.rb +4 -4
- metadata +17 -12
- data/docs/html/index.html +0 -129
- data/test/mock_page.rb +0 -8
- data/test/setup.rb +0 -10
- data/test/test.html +0 -129
- data/test/test_assert.rb +0 -64
- data/test/test_driver.rb +0 -57
- data/test/test_test_utils.rb +0 -76
data/lib/rwebunit/driver.rb
CHANGED
@@ -6,113 +6,163 @@
|
|
6
6
|
# click_button("submit")
|
7
7
|
#
|
8
8
|
require File.join(File.dirname(__FILE__), 'itest_plugin')
|
9
|
+
require File.join(File.dirname(__FILE__), 'popup')
|
9
10
|
require 'timeout'
|
11
|
+
require 'uri'
|
10
12
|
|
11
13
|
module RWebUnit
|
12
14
|
module Driver
|
13
15
|
include RWebUnit::ITestPlugin
|
16
|
+
include RWebUnit::Popup
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
+
@@default_polling_interval = 1 # second
|
19
|
+
@@default_timeout = 30 # seconds
|
18
20
|
|
19
|
-
#
|
21
|
+
# open a browser, and set base_url via hash, but does not acually
|
20
22
|
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
# example:
|
24
|
+
# open_browser :base_url => http://localhost:8080
|
25
|
+
#
|
26
|
+
# There are 3 ways to set base url
|
27
|
+
# 1. pass as first argument
|
28
|
+
# 2. If running using iTest2, used as confiured
|
29
|
+
# 3. Use default value set
|
30
|
+
def open_browser(base_url = nil, options = {})
|
31
|
+
base_url ||= $ITEST2_PROJECT_BASE_URL
|
32
|
+
base_url ||= $BASE_URL
|
33
|
+
raise "base_url must be set" if base_url.nil?
|
34
|
+
|
35
|
+
default_options = {:speed => "fast",
|
36
|
+
:visible => true,
|
37
|
+
:highlight_colour => 'yellow',
|
38
|
+
:close_others => true,
|
39
|
+
:start_new => false, # start a new browser always
|
40
|
+
:go => true}
|
41
|
+
|
42
|
+
options = default_options.merge options
|
43
|
+
options[:firefox] = true if "Firefox" == $ITEST2_BROWSER || "Firefox" == $BROWSER
|
44
|
+
($ITEST2_HIDE_BROWSER) ? $HIDE_IE = true : $HIDE_IE = false
|
45
|
+
|
46
|
+
if base_url =~ /^file:/
|
47
|
+
uri_base = base_url
|
27
48
|
else
|
28
|
-
|
49
|
+
uri = URI.parse(base_url)
|
50
|
+
uri_base = "#{uri.scheme}://#{uri.host}:#{uri.port}"
|
29
51
|
end
|
30
|
-
end
|
31
52
|
|
32
|
-
|
33
|
-
|
53
|
+
if options[:start_new]
|
54
|
+
@web_browser = WebBrowser.new(uri_base, nil, options)
|
55
|
+
else
|
56
|
+
@web_browser = WebBrowser.reuse(uri_base, options) # Reuse existing browser
|
57
|
+
end
|
34
58
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
59
|
+
if base_url =~ /^file:/
|
60
|
+
goto_url(base_url) # for files, no base url
|
61
|
+
else
|
62
|
+
(uri.path.length == 0) ? begin_at("/") : begin_at(uri.path) if options[:go]
|
63
|
+
end
|
64
|
+
|
65
|
+
return @web_browser
|
42
66
|
end
|
67
|
+
alias open_browser_with open_browser
|
43
68
|
|
44
|
-
#
|
69
|
+
# return the underlying RWebUnit::Browser object
|
70
|
+
def browser
|
71
|
+
@web_browser
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Close the current browser window (started by the script). If no browser started, then close
|
76
|
+
# all browser windows.
|
45
77
|
#
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
rescue
|
78
|
+
def close_browser
|
79
|
+
if @web_browser
|
80
|
+
# Old iTest2 version
|
81
|
+
# @web_browser.close_browser unless $ITEST2_LEAVE_BROWSER_OPEN_AFTER_RUN
|
82
|
+
@web_browser.close_browser
|
83
|
+
else
|
84
|
+
WebBrowser.close_all_browsers
|
54
85
|
end
|
55
|
-
raise "Operation shall not be allowed" if operation_performed_ok
|
56
86
|
end
|
57
|
-
alias
|
87
|
+
alias close_ie close_browser
|
58
88
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
89
|
+
|
90
|
+
# Close all opening browser windows
|
91
|
+
#
|
92
|
+
def close_all_browsers
|
93
|
+
if is_firefox?
|
94
|
+
FireWatir::Firefox.close_all
|
95
|
+
else
|
96
|
+
Watir::IE.close_all
|
65
97
|
end
|
66
|
-
operation_performed_ok
|
67
98
|
end
|
68
99
|
|
69
|
-
#
|
100
|
+
# Verify the next page following an operation.
|
70
101
|
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
102
|
+
# Typical usage:
|
103
|
+
# login_page.click_login
|
104
|
+
# expect_page HomePage
|
105
|
+
def expect_page(page_clazz, argument = nil)
|
106
|
+
if argument
|
107
|
+
page_clazz.new(@web_browser, argument)
|
108
|
+
else
|
109
|
+
page_clazz.new(@web_browser)
|
77
110
|
end
|
78
111
|
end
|
79
|
-
alias fail_safe failsafe
|
80
112
|
|
81
113
|
def context
|
82
114
|
@web_browser.context
|
83
115
|
end
|
84
116
|
|
117
|
+
# Starting browser with a URL
|
118
|
+
#
|
119
|
+
# Example:
|
120
|
+
# begin_at("http://www.itest2.com")
|
85
121
|
def begin_at(url)
|
86
122
|
dump_caller_stack
|
87
123
|
@web_browser.begin_at(url)
|
88
124
|
end
|
89
125
|
|
126
|
+
# Return the Watir::IE instance
|
127
|
+
#
|
90
128
|
def ie
|
91
129
|
@web_browser.ie
|
92
130
|
end
|
93
131
|
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
|
132
|
+
# Return the FireWatir::Firefox instance
|
133
|
+
#
|
98
134
|
def firefox
|
99
135
|
@web_browser.firefox
|
100
136
|
end
|
101
137
|
|
102
|
-
def
|
103
|
-
|
104
|
-
@web_browser.close_browser unless $ITEST2_LEAVE_BROWSER_OPEN_AFTER_RUN
|
138
|
+
def is_firefox?
|
139
|
+
@web_browser.is_firefox? if @web_browser
|
105
140
|
end
|
106
|
-
alias close_ie close_browser
|
107
141
|
|
108
142
|
|
143
|
+
# Go to another page on the testing site.
|
144
|
+
#
|
145
|
+
# open_browser("http://www.itest2.com")
|
146
|
+
# goto_page("/demo") # visit page http://www.itest2.com/demo
|
147
|
+
#
|
109
148
|
def goto_page(page)
|
110
149
|
operation_delay
|
111
150
|
dump_caller_stack
|
112
|
-
@web_browser.goto_page(page)
|
151
|
+
@web_browser.goto_page(page) if @web_browser
|
113
152
|
end
|
114
153
|
alias visit goto_page
|
115
154
|
|
155
|
+
# Go to another web site, normally different site being tested on
|
156
|
+
#
|
157
|
+
# open_browser("http://www.itest2.com")
|
158
|
+
# goto_url("http://myorganized.info")
|
159
|
+
def goto_url(url)
|
160
|
+
@web_browser.goto_url url
|
161
|
+
end
|
162
|
+
|
163
|
+
# Attach to existinb browser window
|
164
|
+
#
|
165
|
+
# attach_browser(:title, )
|
116
166
|
def attach_browser(how, what, options = {})
|
117
167
|
options.merge!(:browser => is_firefox? ? "Firefox" : "IE")
|
118
168
|
begin
|
@@ -123,10 +173,21 @@ module RWebUnit
|
|
123
173
|
WebBrowser.attach_browser(how, what, options)
|
124
174
|
end
|
125
175
|
|
176
|
+
# Reuse current an opened browser window instead of opening a new one
|
177
|
+
# example:
|
178
|
+
# use_current_browser(:title, /.*/) # use what ever browser window
|
179
|
+
# use_current_browser(:title, "iTest2") # use browser window with title "iTest2"
|
180
|
+
def use_current_browser(how = :title, what = /.*/)
|
181
|
+
@web_browser = WebBrowser.attach_browser(how, what)
|
182
|
+
end
|
183
|
+
|
126
184
|
##
|
127
185
|
# Delegate to WebTester
|
128
186
|
#
|
129
|
-
|
187
|
+
# Note:
|
188
|
+
# label(:id, "abc") # OK
|
189
|
+
# label(:id, :abc) # Error
|
190
|
+
#
|
130
191
|
# Depends on which object type, you can use following attribute
|
131
192
|
# More details: http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
|
132
193
|
#
|
@@ -166,7 +227,8 @@ module RWebUnit
|
|
166
227
|
[:area, :button, :cell, :checkbox, :div, :form, :frame, :h1, :h2, :h3, :h4, :h5, :h6, :hidden, :image, :li, :link, :map, :pre, :row, :radio, :select_list, :span, :table, :text_field, :paragraph, :file_field, :label].each do |method|
|
167
228
|
define_method method do |*args|
|
168
229
|
dump_caller_stack
|
169
|
-
@web_browser
|
230
|
+
# add check for @web_browser, in case the moudule included without init browser
|
231
|
+
@web_browser.send(method, *args) if @web_browser
|
170
232
|
end
|
171
233
|
end
|
172
234
|
alias td cell
|
@@ -176,7 +238,8 @@ module RWebUnit
|
|
176
238
|
[:back, :forward, :refresh].each do |method|
|
177
239
|
define_method(method) do
|
178
240
|
dump_caller_stack
|
179
|
-
|
241
|
+
operation_delay
|
242
|
+
@web_browser.send(method) if @web_browser
|
180
243
|
end
|
181
244
|
end
|
182
245
|
alias refresh_page refresh
|
@@ -186,7 +249,7 @@ module RWebUnit
|
|
186
249
|
[:images, :links, :buttons, :select_lists, :checkboxes, :radios, :text_fields].each do |method|
|
187
250
|
define_method method do
|
188
251
|
dump_caller_stack
|
189
|
-
@web_browser.send(method)
|
252
|
+
@web_browser.send(method) if @web_browser
|
190
253
|
end
|
191
254
|
end
|
192
255
|
|
@@ -195,15 +258,16 @@ module RWebUnit
|
|
195
258
|
# page.check_checkbox('bad_ones', 'Chicken Little')
|
196
259
|
# page.check_checkbox('good_ones', ['Cars', 'Toy Story'])
|
197
260
|
#
|
198
|
-
[:set_form_element, :click_link_with_text, :click_link_with_id, :submit, :click_button_with_id, :click_button_with_caption, :click_button_with_value, :click_radio_option, :clear_radio_option, :select_file_for_upload, :check_checkbox, :uncheck_checkbox, :select_option].each do |method|
|
261
|
+
[:set_form_element, :click_link_with_text, :click_link_with_id, :submit, :click_button_with_id, :click_button_with_name, :click_button_with_caption, :click_button_with_value, :click_radio_option, :clear_radio_option, :select_file_for_upload, :check_checkbox, :uncheck_checkbox, :select_option].each do |method|
|
199
262
|
define_method method do |*args|
|
200
263
|
dump_caller_stack
|
201
264
|
operation_delay
|
202
|
-
@web_browser.send(method, *args)
|
265
|
+
@web_browser.send(method, *args) if @web_browser
|
203
266
|
end
|
204
267
|
end
|
205
268
|
|
206
269
|
alias enter_text set_form_element
|
270
|
+
alias set_hidden_field set_form_element
|
207
271
|
alias click_link click_link_with_text
|
208
272
|
alias click_button_with_text click_button_with_caption
|
209
273
|
alias click_button click_button_with_caption
|
@@ -218,9 +282,13 @@ module RWebUnit
|
|
218
282
|
end
|
219
283
|
|
220
284
|
def contains_text(text)
|
221
|
-
@web_browser.contains_text(text)
|
285
|
+
@web_browser.contains_text(text)
|
222
286
|
end
|
223
287
|
|
288
|
+
# Click image buttion with image source name
|
289
|
+
#
|
290
|
+
# For an image submit button <input name="submit" type="image" src="/images/search_button.gif">
|
291
|
+
# click_button_with_image("search_button.gif")
|
224
292
|
def click_button_with_image_src_contains(image_filename)
|
225
293
|
dump_caller_stack
|
226
294
|
operation_delay
|
@@ -241,6 +309,251 @@ module RWebUnit
|
|
241
309
|
@web_browser.new_popup_window(options)
|
242
310
|
end
|
243
311
|
|
312
|
+
|
313
|
+
# Warning: this does not work well with Firefox yet.
|
314
|
+
def element_text(elem_id)
|
315
|
+
@web_browser.element_value(elem_id)
|
316
|
+
end
|
317
|
+
|
318
|
+
# Identify DOM element by ID
|
319
|
+
# Warning: it is only supported on IE
|
320
|
+
def element_by_id(elem_id)
|
321
|
+
@web_browser.element_by_id(elem_id)
|
322
|
+
end
|
323
|
+
|
324
|
+
# ---
|
325
|
+
# For debugging
|
326
|
+
# ---
|
327
|
+
def dump_response(stream = nil)
|
328
|
+
@web_browser.dump_response(stream)
|
329
|
+
end
|
330
|
+
|
331
|
+
# For current page souce to a file in specified folder for inspection
|
332
|
+
#
|
333
|
+
# save_current_page(:dir => "C:\\mysite", filename => "abc", :replacement => true)
|
334
|
+
def save_current_page(options = {})
|
335
|
+
default_options = {:replacement => true}
|
336
|
+
options = default_options.merge(options)
|
337
|
+
if options[:dir]
|
338
|
+
# already defined the dir
|
339
|
+
to_dir = options[:dir]
|
340
|
+
elsif $ITEST2_RUNNING_SPEC_ID
|
341
|
+
|
342
|
+
$ITEST2_DUMP_DIR = File.join($ITEST2_WORKING_DIR, "dump")
|
343
|
+
FileUtils.mkdir($ITEST2_DUMP_DIR) unless File.exists?($ITEST2_DUMP_DIR)
|
344
|
+
|
345
|
+
spec_run_id = $ITEST2_RUNNING_SPEC_ID
|
346
|
+
spec_run_dir_name = spec_run_id.to_s.rjust(4, "0") unless spec_run_id == "unknown"
|
347
|
+
to_dir = File.join($ITEST2_DUMP_DIR, spec_run_dir_name)
|
348
|
+
else
|
349
|
+
to_dir = ENV['TEMP_DIR'] || "C:\\temp"
|
350
|
+
end
|
351
|
+
|
352
|
+
if options[:filename]
|
353
|
+
file_name = options[:filename]
|
354
|
+
else
|
355
|
+
file_name = Time.now.strftime("%m%d%H%M%S") + ".html"
|
356
|
+
end
|
357
|
+
|
358
|
+
Dir.mkdir(to_dir) unless File.exists?(to_dir)
|
359
|
+
file = File.join(to_dir, file_name)
|
360
|
+
|
361
|
+
content = page_source
|
362
|
+
base_url = @web_browser.context.base_url
|
363
|
+
current_url = @web_browser.url
|
364
|
+
current_url =~ /(.*\/).*$/
|
365
|
+
current_url_parent = $1
|
366
|
+
if options[:replacement] && base_url =~ /^http:/
|
367
|
+
|
368
|
+
# <link rel="stylesheet" type="text/css" href="/stylesheets/default.css" />
|
369
|
+
# '<script type="text/javascript" src="http://www.jeroenwijering.com/embed/swfobject.js"></script>'
|
370
|
+
# <script type="text/javascript" src="/javascripts/prototype.js"></script>
|
371
|
+
# <script type="text/javascript" src="/javascripts/scriptaculous.js?load=effects,builder"></script>
|
372
|
+
# <script type="text/javascript" src="/javascripts/extensions/gallery/lightbox.js"></script>
|
373
|
+
# <link href="/stylesheets/extensions/gallery/lightbox.css" rel="stylesheet" type="text/css" />
|
374
|
+
# <img src="images/mission_48.png" />
|
375
|
+
|
376
|
+
modified_content = ""
|
377
|
+
|
378
|
+
content.each_line do |line|
|
379
|
+
if line =~ /<script\s+.*src=["'']?(.*)["'].*/i then
|
380
|
+
script_src = $1
|
381
|
+
substitute_relative_path_in_src_line(line, script_src, base_url, current_url_parent)
|
382
|
+
elsif line =~ /<link\s+.*href=["'']?(.*)["'].*/i then
|
383
|
+
link_href = $1
|
384
|
+
substitute_relative_path_in_src_line(line, link_href, base_url, current_url_parent)
|
385
|
+
elsif line =~ /<img\s+.*src=["'']?(.*)["'].*/i then
|
386
|
+
img_src = $1
|
387
|
+
substitute_relative_path_in_src_line(line, img_src, base_url, current_url_parent)
|
388
|
+
end
|
389
|
+
|
390
|
+
modified_content += line
|
391
|
+
end
|
392
|
+
|
393
|
+
File.new(file, "w").puts modified_content
|
394
|
+
else
|
395
|
+
File.new(file, "w").puts content
|
396
|
+
|
397
|
+
end
|
398
|
+
|
399
|
+
|
400
|
+
end
|
401
|
+
|
402
|
+
# substut
|
403
|
+
def substitute_relative_path_in_src_line(line, script_src, host_url, page_parent_url)
|
404
|
+
unless script_src =~ /^["']?http:/
|
405
|
+
host_url.slice!(-1) if ends_with?(host_url, "/")
|
406
|
+
if script_src =~ /^\s*\// # absolute_path
|
407
|
+
line.gsub!(script_src, "#{host_url}#{script_src}")
|
408
|
+
else #relative_path
|
409
|
+
line.gsub!(script_src, "#{page_parent_url}#{script_src}")
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def ends_with?(str, suffix)
|
415
|
+
suffix = suffix.to_s
|
416
|
+
str[-suffix.length, suffix.length] == suffix
|
417
|
+
end
|
418
|
+
|
419
|
+
# current web page title
|
420
|
+
def page_title
|
421
|
+
@web_browser.page_title
|
422
|
+
end
|
423
|
+
|
424
|
+
# current page source (in HTML)
|
425
|
+
def page_source
|
426
|
+
@web_browser.page_source
|
427
|
+
end
|
428
|
+
|
429
|
+
# return plain text view of page
|
430
|
+
def page_text
|
431
|
+
@web_browser.text
|
432
|
+
end
|
433
|
+
|
434
|
+
# return the text of specific (identified by attribute "id") label tag
|
435
|
+
# For page containing
|
436
|
+
# <label id="preferred_ide">iTest2</label>
|
437
|
+
# label_with_id("preferred_ids") # => iTest2
|
438
|
+
def label_with_id(label_id)
|
439
|
+
label(:id, label_id.to_s).text
|
440
|
+
end
|
441
|
+
|
442
|
+
# return the text of specific (identified by attribute "id") span tag
|
443
|
+
# For page containing
|
444
|
+
# <span id="preferred_recorder">iTest2/Watir Recorder</span>
|
445
|
+
# span_with_id("preferred_recorder") # => iTest2/Watir Recorder
|
446
|
+
def span_with_id(span_id)
|
447
|
+
span(:id, span_id).text
|
448
|
+
end
|
449
|
+
|
450
|
+
# return the text of specific (identified by attribute "id") ta tag
|
451
|
+
# For page containing
|
452
|
+
# <td id="preferred_recorder">iTest2/Watir Recorder</span>
|
453
|
+
# td_with_id("preferred_recorder") # => iTest2/Watir Recorder
|
454
|
+
def cell_with_id(cell_id)
|
455
|
+
cell(:id, cell_id).text
|
456
|
+
end
|
457
|
+
alias table_data_with_id cell_with_id
|
458
|
+
|
459
|
+
|
460
|
+
def is_mac?
|
461
|
+
RUBY_PLATFORM.downcase.include?("darwin")
|
462
|
+
end
|
463
|
+
|
464
|
+
def is_windows?
|
465
|
+
RUBY_PLATFORM.downcase.include?("mswin") or RUBY_PLATFORM.downcase.include?("mingw32")
|
466
|
+
end
|
467
|
+
|
468
|
+
# Support browser (IE) operations using unicode
|
469
|
+
# Example:
|
470
|
+
# click_button("Google 搜索")
|
471
|
+
def support_utf8
|
472
|
+
if is_windows?
|
473
|
+
require 'win32ole'
|
474
|
+
WIN32OLE.codepage = WIN32OLE::CP_UTF8
|
475
|
+
end
|
476
|
+
end
|
477
|
+
alias support_unicode support_utf8
|
478
|
+
|
479
|
+
def is_linux?
|
480
|
+
RUBY_PLATFORM.downcase.include?("linux")
|
481
|
+
end
|
482
|
+
|
483
|
+
#= Convenient functions
|
484
|
+
#
|
485
|
+
|
486
|
+
# Using Ruby block syntax to create interesting domain specific language,
|
487
|
+
# may be appeal to someone.
|
488
|
+
|
489
|
+
# Example:
|
490
|
+
# on @page do |i|
|
491
|
+
# i.enter_text('btn1')
|
492
|
+
# i.click_button('btn1')
|
493
|
+
# end
|
494
|
+
def on(page, &block)
|
495
|
+
yield page
|
496
|
+
end
|
497
|
+
|
498
|
+
# fail the test if user can perform the operation
|
499
|
+
#
|
500
|
+
# Example:
|
501
|
+
# shall_not_allow { 1/0 }
|
502
|
+
def shall_not_allow(&block)
|
503
|
+
operation_performed_ok = false
|
504
|
+
begin
|
505
|
+
yield
|
506
|
+
operation_performed_ok = true
|
507
|
+
rescue
|
508
|
+
end
|
509
|
+
raise "Operation shall not be allowed" if operation_performed_ok
|
510
|
+
end
|
511
|
+
alias do_not_allow shall_not_allow
|
512
|
+
|
513
|
+
# Does not provide real function, other than make enhancing test syntax
|
514
|
+
#
|
515
|
+
# Example:
|
516
|
+
# allow { click_button('Register') }
|
517
|
+
def allow(&block)
|
518
|
+
operation_performed_ok = false
|
519
|
+
begin
|
520
|
+
yield
|
521
|
+
operation_performed_ok = true
|
522
|
+
rescue
|
523
|
+
end
|
524
|
+
operation_performed_ok
|
525
|
+
end
|
526
|
+
alias shall_allow allow
|
527
|
+
alias allowing allow
|
528
|
+
|
529
|
+
# try operation, ignore if errors occur
|
530
|
+
#
|
531
|
+
# Example:
|
532
|
+
# failsafe { click_link("Logout") } # try logout, but it still OK if not being able to (already logout))
|
533
|
+
def failsafe(&block)
|
534
|
+
begin
|
535
|
+
yield
|
536
|
+
rescue =>e
|
537
|
+
end
|
538
|
+
end
|
539
|
+
alias fail_safe failsafe
|
540
|
+
|
541
|
+
|
542
|
+
# Execute the provided block until either (1) it returns true, or
|
543
|
+
# (2) the timeout (in seconds) has been reached. If the timeout is reached,
|
544
|
+
# a TimeOutException will be raised. The block will always
|
545
|
+
# execute at least once.
|
546
|
+
#
|
547
|
+
# This does not handle error, if the given block raise error, the statement finish with error
|
548
|
+
# Examples:
|
549
|
+
# wait_until {puts 'hello'}
|
550
|
+
# wait_until { div(:id, :receipt_date).exists? }
|
551
|
+
#
|
552
|
+
def wait_until(timeout = @@default_timeout || 30, polling_interval = @@default_polling_interval || 1, &block)
|
553
|
+
waiter = Watir::Waiter.new(timeout, polling_interval)
|
554
|
+
waiter.wait_until { yield }
|
555
|
+
end
|
556
|
+
|
244
557
|
# Wait for specific seconds for an Ajax update finish.
|
245
558
|
# Trick: In your Rails application,
|
246
559
|
# :loading => "Element.show('search_indicator');
|
@@ -256,7 +569,7 @@ module RWebUnit
|
|
256
569
|
#
|
257
570
|
# Warning: this method has not been fully tested, if you are not using Rails, change your parameter accordingly.
|
258
571
|
#
|
259
|
-
def ajax_wait_for_element(element_id, seconds, status='show', check_interval=
|
572
|
+
def ajax_wait_for_element(element_id, seconds, status='show', check_interval = @@default_polling_interval)
|
260
573
|
count = 0
|
261
574
|
check_interval = 1 if check_interval < 1 or check_interval > seconds
|
262
575
|
while count < (seconds / check_interval) do
|
@@ -273,8 +586,12 @@ module RWebUnit
|
|
273
586
|
return false
|
274
587
|
end
|
275
588
|
|
276
|
-
|
589
|
+
#Wait the element with given id to be present in web page
|
590
|
+
#
|
591
|
+
# Warning: this not working in Firefox, try use wait_util or try instead
|
592
|
+
def wait_for_element(element_id, timeout = @@default_timeout, interval = @@default_polling_interval)
|
277
593
|
start_time = Time.now
|
594
|
+
#TODO might not work with Firefox
|
278
595
|
until @web_browser.element_by_id(element_id) do
|
279
596
|
sleep(interval)
|
280
597
|
if (Time.now - start_time) > timeout
|
@@ -282,6 +599,7 @@ module RWebUnit
|
|
282
599
|
end
|
283
600
|
end
|
284
601
|
end
|
602
|
+
=begin
|
285
603
|
|
286
604
|
# TODO: Firewatir does not suport retrieving style or outerHtml
|
287
605
|
# http://jira.openqa.org/browse/WTR-260
|
@@ -313,231 +631,78 @@ module RWebUnit
|
|
313
631
|
end
|
314
632
|
end
|
315
633
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
Dir.mkdir(to_dir) unless File.exists?(to_dir)
|
334
|
-
file_name = Time.now.strftime("%m%d%H%M%S") + ".html"
|
335
|
-
file = File.join(to_dir, file_name)
|
336
|
-
File.new(file, "w").puts page_source
|
337
|
-
end
|
338
|
-
|
339
|
-
def click_popup_window(button, wait_time= 9, user_input=nil )
|
340
|
-
@web_browser.start_clicker(button, wait_time, user_input)
|
341
|
-
sleep 0.5
|
342
|
-
end
|
343
|
-
|
344
|
-
# return plain text view of page
|
345
|
-
def page_text
|
346
|
-
Hpricot(page_source).to_plain_text
|
347
|
-
end
|
348
|
-
|
349
|
-
def label_with_id(label_id)
|
350
|
-
label(:id, label_id).text
|
351
|
-
end
|
352
|
-
|
353
|
-
def span_with_id(span_id)
|
354
|
-
span(:id, span_id).text
|
355
|
-
end
|
356
|
-
|
357
|
-
def cell_with_id(cell_id)
|
358
|
-
cell(:id, cell_id).text
|
359
|
-
end
|
360
|
-
alias table_data_with_id cell_with_id
|
361
|
-
|
362
|
-
# run a separate process waiting for the popup window to click
|
363
|
-
#
|
364
|
-
#
|
365
|
-
def prepare_to_click_button_in_popup(button = "OK", wait_time = 3)
|
366
|
-
# !@web_browser.is_firefox?
|
367
|
-
# TODO: firefox is OK
|
368
|
-
if RUBY_PLATFORM =~ /mswin/ then
|
369
|
-
start_checking_js_dialog(button, wait_time)
|
370
|
-
else
|
371
|
-
raise "this only support on Windows and on IE"
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
# Start a background process to click the button on a javascript popup window
|
376
|
-
def start_checking_js_dialog(button = "OK", wait_time = 3)
|
377
|
-
w = WinClicker.new
|
378
|
-
longName = File.expand_path(File.dirname(__FILE__)).gsub("/", "\\" )
|
379
|
-
shortName = w.getShortFileName(longName)
|
380
|
-
c = "start ruby #{shortName}\\clickJSDialog.rb #{button} #{wait_time} "
|
381
|
-
w.winsystem(c)
|
382
|
-
w = nil
|
383
|
-
end
|
384
|
-
|
385
|
-
# Click the button in javascript popup dialog
|
386
|
-
# Usage:
|
387
|
-
# click_button_in_popup_after { click_link('Cancel')}
|
388
|
-
# click_button_in_popup_after("OK") { click_link('Cancel')}
|
389
|
-
#
|
390
|
-
def click_button_in_popup_after(options = {:button => "OK", :wait_time => 3}, &block)
|
391
|
-
if RUBY_PLATFORM =~ /mswin/ then
|
392
|
-
start_checking_js_dialog(options[:button], options[:wait_time])
|
393
|
-
yield
|
394
|
-
else
|
395
|
-
raise "this only support on Windows and on IE"
|
634
|
+
=end
|
635
|
+
|
636
|
+
# Try the operation up to specified times, and sleep given interval (in seconds)
|
637
|
+
# Error will be ignored until timeout
|
638
|
+
# Example
|
639
|
+
# repeat_try(3, 2) { click_button('Search' } # 3 times, 6 seconds in total
|
640
|
+
# repeat_try { click_button('Search' } # using default 5 tries, 2 second interval
|
641
|
+
def repeat_try(num_tries = @@default_timeout || 30, interval = @@default_polling_interval || 1, &block)
|
642
|
+
num_tries ||= 1
|
643
|
+
(num_tries - 1).times do |num|
|
644
|
+
begin
|
645
|
+
yield
|
646
|
+
return
|
647
|
+
rescue => e
|
648
|
+
# puts "debug: #{num} failed: #{e}"
|
649
|
+
sleep interval
|
650
|
+
end
|
396
651
|
end
|
397
|
-
end
|
398
652
|
|
399
|
-
|
400
|
-
# Support of iTest to ajust the intervals between keystroke/mouse operations
|
401
|
-
def operation_delay
|
653
|
+
# last try, throw error if still fails
|
402
654
|
begin
|
403
|
-
|
404
|
-
$ITEST2_OPERATION_DELAY && $ITEST2_OPERATION_DELAY < 30000 then # max 30 seconds
|
405
|
-
sleep($ITEST2_OPERATION_DELAY / 1000)
|
406
|
-
end
|
407
|
-
|
408
|
-
while $ITEST2_PAUSE
|
409
|
-
debug("Paused, waiting ...")
|
410
|
-
sleep 1
|
411
|
-
end
|
655
|
+
yield
|
412
656
|
rescue => e
|
413
|
-
|
414
|
-
# ignore
|
657
|
+
raise e.to_s + " after trying #{num_tries} times every #{interval} seconds"
|
415
658
|
end
|
659
|
+
yield
|
416
660
|
end
|
417
661
|
|
662
|
+
# TODO: syntax
|
418
663
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
def is_windows?
|
428
|
-
RUBY_PLATFORM.downcase.include?("mswin")
|
429
|
-
end
|
430
|
-
|
431
|
-
def is_linux?
|
432
|
-
RUBY_PLATFORM.downcase.include?("linux")
|
433
|
-
end
|
434
|
-
|
435
|
-
# Start background thread to click popup windows
|
436
|
-
# Warning:
|
437
|
-
# Make browser window active
|
438
|
-
# Don't mouse your mouse to focus other window during test execution
|
439
|
-
def check_for_popups
|
440
|
-
autoit = WIN32OLE.new('AutoItX3.Control')
|
441
|
-
#
|
442
|
-
# Do forever - assumes popups could occur anywhere/anytime in your
|
443
|
-
# application.
|
444
|
-
loop do
|
445
|
-
# Look for window with given title. Give up after 1 second.
|
446
|
-
ret = autoit.WinWait('Windows Internet Explorer', '', 1)
|
447
|
-
#
|
448
|
-
# If window found, send appropriate keystroke (e.g. {enter}, {Y}, {N}).
|
449
|
-
if (ret==1) then
|
450
|
-
autoit.Send('{enter}')
|
451
|
-
end
|
452
|
-
#
|
453
|
-
# Take a rest to avoid chewing up cycles and give another thread a go.
|
454
|
-
# Then resume the loop.
|
455
|
-
sleep(3)
|
456
|
-
end
|
457
|
-
end
|
664
|
+
# Try the operation up to specified timeout (in seconds), and sleep given interval (in seconds).
|
665
|
+
# Error will be ignored until timeout
|
666
|
+
# Example
|
667
|
+
# try { click_link('waiting')}
|
668
|
+
# try(10, 2) { click_button('Search' } # try to click the 'Search' button upto 10 seconds, try every 2 seconds
|
669
|
+
# try { click_button('Search' }
|
670
|
+
def try(timeout = @@default_timeout, polling_interval = @@default_polling_interval || 1, &block)
|
671
|
+
start_time = Time.now
|
458
672
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
# open_in_browser
|
467
|
-
# ...
|
468
|
-
# end
|
469
|
-
#
|
470
|
-
# after(:all) do
|
471
|
-
# close_browser
|
472
|
-
# Thread.kill($popup)
|
473
|
-
# end
|
474
|
-
#
|
475
|
-
# or for all tests,
|
476
|
-
# $popup = Thread.new { check_for_alerts }
|
477
|
-
# at_exit{ Thread.kill($popup) }
|
478
|
-
def check_for_security_alerts
|
479
|
-
autoit = WIN32OLE.new('AutoItX3.Control')
|
480
|
-
loop do
|
481
|
-
["Security Alert", "Security Information"].each do |win_title|
|
482
|
-
ret = autoit.WinWait(win_title, '', 1)
|
483
|
-
if (ret==1) then
|
484
|
-
autoit.Send('{Y}')
|
485
|
-
end
|
673
|
+
last_error = nil
|
674
|
+
until (duration = Time.now - start_time) > timeout
|
675
|
+
begin
|
676
|
+
return if yield
|
677
|
+
last_error = nil
|
678
|
+
rescue => e
|
679
|
+
last_error = e
|
486
680
|
end
|
487
|
-
sleep
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
def verify_alert(title = "Microsoft Internet Explorer", button = "OK")
|
492
|
-
if is_windows? && !is_firefox?
|
493
|
-
WIN32OLE.new('AutoItX3.Control').ControlClick(title, '', button)
|
494
|
-
else
|
495
|
-
raise "This function only supports IE"
|
681
|
+
sleep polling_interval
|
496
682
|
end
|
497
|
-
end
|
498
|
-
|
499
|
-
def click_button_in_security_information_popup(button = "&Yes")
|
500
|
-
verify_alert("Security Information", "", button)
|
501
|
-
end
|
502
|
-
alias click_security_information_popup click_button_in_security_information_popup
|
503
|
-
|
504
|
-
def click_button_in_security_alert_popup(button = "&Yes")
|
505
|
-
verify_alert("Security Alert", "", button)
|
506
|
-
end
|
507
|
-
alias click_security_alert_popup click_button_in_security_alert_popup
|
508
683
|
|
509
|
-
|
510
|
-
|
511
|
-
end
|
512
|
-
alias click_javascript_popup click_button_in_javascript_popup
|
513
|
-
|
514
|
-
##
|
515
|
-
# This only works for IEs
|
516
|
-
# Cons:
|
517
|
-
# - Slow
|
518
|
-
# - only works in IE
|
519
|
-
# - does not work for security alert ?
|
520
|
-
def ie_popup_clicker(button_name = "OK", max_wait = 15)
|
521
|
-
require 'watir/contrib/enabled_popup'
|
522
|
-
require 'win32ole'
|
523
|
-
hwnd = ie.enabled_popup(15)
|
524
|
-
if (hwnd) #yeah! a popup
|
525
|
-
popup = WinClicker.new
|
526
|
-
popup.makeWindowActive(hwnd) #Activate the window.
|
527
|
-
popup.clickWindowsButton_hwnd(hwnd, button_name) #Click the button
|
528
|
-
#popup.clickWindowsButton(/Internet/,button_name,30)
|
529
|
-
popup = nil
|
530
|
-
end
|
684
|
+
raise "Timeout after #{duration.to_i} seconds with error: #{last_error}." if last_error
|
685
|
+
raise "Timeout after #{duration.to_i} seconds."
|
531
686
|
end
|
687
|
+
alias try_upto try
|
532
688
|
|
533
689
|
##
|
534
690
|
# Convert :first to 1, :second to 2, and so on...
|
535
691
|
def symbol_to_sequence(symb)
|
536
|
-
value = { :zero => 0,
|
537
|
-
:
|
538
|
-
:
|
692
|
+
value = { :zero => 0,
|
693
|
+
:first => 1,
|
694
|
+
:second => 2,
|
695
|
+
:third => 3,
|
696
|
+
:fourth => 4,
|
697
|
+
:fifth => 5,
|
698
|
+
:sixth => 6,
|
699
|
+
:seventh => 7,
|
700
|
+
:eighth => 8,
|
701
|
+
:ninth => 9,
|
702
|
+
:tenth => 10 }[symb]
|
539
703
|
return value || symb.to_i
|
540
704
|
end
|
541
705
|
|
542
706
|
end
|
707
|
+
|
543
708
|
end
|