rwebunit 1.0.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|