rwebspec-webdriver 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/Rakefile +11 -12
  2. data/lib/rwebspec-webdriver/assert.rb +445 -0
  3. data/lib/{rwebspec → rwebspec-webdriver}/clickJSDialog.rb +0 -0
  4. data/lib/{rwebspec → rwebspec-webdriver}/context.rb +13 -11
  5. data/lib/rwebspec-webdriver/database_checker.rb +76 -0
  6. data/lib/rwebspec-webdriver/driver.rb +1011 -0
  7. data/lib/rwebspec-webdriver/element_locator.rb +89 -0
  8. data/lib/rwebspec-webdriver/load_test_helper.rb +174 -0
  9. data/lib/{rwebspec → rwebspec-webdriver}/matchers/contains_text.rb +0 -0
  10. data/lib/rwebspec-webdriver/popup.rb +149 -0
  11. data/lib/rwebspec-webdriver/rspec_helper.rb +101 -0
  12. data/lib/rwebspec-webdriver/test_script.rb +10 -0
  13. data/lib/rwebspec-webdriver/test_utils.rb +219 -0
  14. data/lib/rwebspec-webdriver/testwise_plugin.rb +85 -0
  15. data/lib/rwebspec-webdriver/using_pages.rb +51 -0
  16. data/lib/rwebspec-webdriver/web_browser.rb +744 -0
  17. data/lib/rwebspec-webdriver/web_page.rb +110 -0
  18. data/lib/rwebspec-webdriver/web_testcase.rb +40 -0
  19. data/lib/rwebspec-webdriver.rb +12 -12
  20. metadata +22 -22
  21. data/lib/rwebspec/assert.rb +0 -443
  22. data/lib/rwebspec/database_checker.rb +0 -74
  23. data/lib/rwebspec/driver.rb +0 -1009
  24. data/lib/rwebspec/element_locator.rb +0 -87
  25. data/lib/rwebspec/load_test_helper.rb +0 -172
  26. data/lib/rwebspec/popup.rb +0 -147
  27. data/lib/rwebspec/rspec_helper.rb +0 -99
  28. data/lib/rwebspec/test_script.rb +0 -8
  29. data/lib/rwebspec/test_utils.rb +0 -217
  30. data/lib/rwebspec/testwise_plugin.rb +0 -83
  31. data/lib/rwebspec/using_pages.rb +0 -49
  32. data/lib/rwebspec/web_browser.rb +0 -742
  33. data/lib/rwebspec/web_page.rb +0 -108
  34. data/lib/rwebspec/web_testcase.rb +0 -38
@@ -1,74 +0,0 @@
1
- require 'active_record' # change rwebspec/database
2
-
3
- module RWebSpec
4
- module DatabaseChecker
5
-
6
- # Example
7
- # connect_to_database mysql_db(:host => "localhost", :database => "lavabuild_local", :user => "root", :password => ""), true
8
- def mysql_db(settings)
9
- options = {:adapter => "mysql"}
10
- options.merge!(settings)
11
- end
12
-
13
- # connect_to_database sqlite3_db(:database => File.join(File.dirname(__FILE__), "testdata", "sample.sqlite3")), true
14
- def sqlite3_db(settings)
15
- options = {:adapter => "sqlite3"}
16
- options.merge!(settings)
17
- end
18
-
19
- def sqlserver_db(settings)
20
- options = {:adapter => "sqlserver"}
21
- options[:username] ||= settings[:user]
22
- options.merge!(settings)
23
- end
24
-
25
- def sqlserver_db_dbi(options)
26
- options[:user] ||= options[:username]
27
- options[:username] ||= options[:user]
28
- conn_str = "DBI:ADO:Provider=SQLOLEDB;Data Source=#{options[:host]};Initial Catalog=#{options[:database]};User ID=\"#{options[:user]}\";password=\"#{options[:password]}\" "
29
- dbh = DBI.connect(conn_str)
30
- end
31
-
32
- def clear_database_connection
33
- begin
34
- ActiveRecord::Base.remove_connection
35
- rescue => e
36
- puts "failed o clear database connection: #{e}"
37
- end
38
- end
39
-
40
- # Connect to databse, example
41
- # mysql_db(:host => "localhost", :database => "lavabuild_local", :user => "root", :password => "")
42
- def connect_to_database(db_settings, force = false)
43
- # only setup database connection once
44
- if force
45
- ActiveRecord::Base.establish_connection(db_settings)
46
- else
47
- begin
48
- ActiveRecord::Base.connection
49
- rescue => e
50
- require 'pp'
51
- pp db_settings
52
- puts "failed to connect: #{e}"
53
- ActiveRecord::Base.establish_connection(db_settings)
54
- end
55
- end
56
- end
57
-
58
- def load_table(table_name)
59
- begin
60
- ActiveRecord::Base.connection
61
- rescue =>e
62
- raise "No database connection setup yet, use connect_to_database() method"
63
- end
64
- class_name = table_name.classify
65
- # define the class, so can use ActiveRecord in
66
- # such as
67
- # Perosn.count.should == 2
68
- def_class = "class ::#{class_name} < ActiveRecord::Base; end"
69
- eval def_class
70
- return def_class
71
- end
72
-
73
- end
74
- end
@@ -1,1009 +0,0 @@
1
- # convenient methods to drive the browser.
2
- # convenient methods to drive the browser.
3
- #
4
- # Instead of
5
- # browser.click_button("submit")
6
- # You can just use
7
- # click_button("submit")
8
- #
9
- require File.join(File.dirname(__FILE__), 'testwise_plugin')
10
- require File.join(File.dirname(__FILE__), 'popup')
11
- require File.join(File.dirname(__FILE__), 'matchers', "contains_text.rb")
12
-
13
- require 'timeout'
14
- require 'uri'
15
-
16
- module RWebSpec
17
- module Driver
18
- include RWebSpec::TestWisePlugin
19
- include RWebSpec::Popup
20
-
21
- @@default_polling_interval = 1 # second
22
- @@default_timeout = 30 # seconds
23
-
24
- # open a browser, and set base_url via hash, but does not acually
25
- #
26
- # example:
27
- # open_browser :base_url => http://localhost:8080
28
- #
29
- # There are 3 ways to set base url
30
- # 1. pass as first argument
31
- # 2. If running using TestWise, used as confiured
32
- # 3. Use default value set
33
- #
34
- #
35
- # New Options:
36
- # :browser => :ie | :firefox | :chrome
37
- def open_browser(base_url = nil, options = {})
38
- puts "[DEBUG] [SeleniumDriver] Callling open_browser #{base_url}"
39
- begin
40
- support_unicode
41
- rescue => e
42
- puts "Unicode may not work in IE, #{e}"
43
- end
44
-
45
- base_url ||= $ITEST2_PROJECT_BASE_URL
46
- base_url ||= $BASE_URL
47
- raise "base_url must be set" if base_url.nil?
48
-
49
- default_options = {:speed => "fast",
50
- :visible => true,
51
- :highlight_colour => 'yellow',
52
- :close_others => true,
53
- :start_new => true, # start a new browser always
54
- :go => true}
55
-
56
- options = default_options.merge options
57
-
58
- if $ITEST2_BROWSER
59
- options[:browser] = $ITEST2_BROWSER.downcase
60
- end
61
- if options[:firefox] && options[:browser].nil? then
62
- options[:browser] = "firefox" # legacy
63
- end
64
-
65
- if base_url =~ /^file:/
66
- uri_base = base_url
67
- else
68
- uri = URI.parse(base_url)
69
- uri_base = "#{uri.scheme}://#{uri.host}:#{uri.port}"
70
- end
71
-
72
- if options[:start_new] || $celerity_loaded
73
- puts "[DEBUG] [SeleniumBrowser] creating a new browser"
74
- @web_browser = WebBrowser.new(uri_base, nil, options)
75
- puts "[DEBUG] [SeleniumBrowser] browser: #{@web_browser.inspect}"
76
- else
77
- @web_browser = WebBrowser.reuse(uri_base, options) # Reuse existing browser
78
- end
79
-
80
- if base_url =~ /^file:/
81
- goto_url(base_url) # for files, no base url
82
- else
83
- (uri.path.length == 0) ? begin_at(base_url) : begin_at(uri.path) if options[:go]
84
- end
85
-
86
- return @web_browser
87
- end
88
-
89
- alias open_browser_with open_browser
90
-
91
- # return the underlying RWebSpec::Browser object
92
- def browser
93
- @web_browser
94
- end
95
-
96
-
97
- def quit
98
- @web_browser.quit
99
- end
100
-
101
- def find_element(how, what)
102
- @web_browser.find_element(how, what)
103
- end
104
-
105
- def find_elements(how, what)
106
- @web_browser.find_elements(how, what)
107
- end
108
-
109
- # Close the current browser window (started by the script). If no browser started, then close
110
- # all browser windows.
111
- #
112
- def close_browser
113
- if @web_browser
114
- # Old TestWise version
115
- # @web_browser.close_browser unless $ITEST2_LEAVE_BROWSER_OPEN_AFTER_RUN
116
- @web_browser.close_browser
117
- else
118
- WebBrowser.close_all_browsers
119
- end
120
- end
121
- alias close_ie close_browser
122
-
123
-
124
- # Close all opening browser windows
125
- #
126
- def close_all_browsers
127
- #TODO
128
- end
129
-
130
- # Verify the next page following an operation.
131
- #
132
- # Typical usage:
133
- # login_page.click_login
134
- # expect_page HomePage
135
- def expect_page(page_clazz, argument = nil)
136
- if argument
137
- @web_browser.expect_page(page_clazz, argument)
138
- else
139
- @web_browser.expect_page(page_clazz)
140
- end
141
- end
142
-
143
- def context
144
- @web_browser.context
145
- end
146
-
147
- # Starting browser with a URL
148
- #
149
- # Example:
150
- # begin_at("http://www.itest2.com")
151
- def begin_at(url)
152
- puts "[DEBUG] [SeleniumBrowser] begin_at #{url}"
153
- dump_caller_stack
154
- @web_browser.begin_at(url)
155
- end
156
-
157
- # Return the Watir::IE instance
158
- #
159
- def ie
160
- @web_browser.ie
161
- end
162
-
163
- # Return the FireWatir::Firefox instance
164
- #
165
- def firefox
166
- @web_browser.firefox
167
- end
168
-
169
- def is_firefox?
170
- @web_browser.is_firefox? if @web_browser
171
- end
172
-
173
- def is_ie?
174
- @web_browser.is_ie? if @web_browser
175
- end
176
-
177
- def is_htmlunit?
178
- RUBY_PLATFORM =~ /java/ && @web_browser
179
- end
180
-
181
- # Go to another page on the testing site.
182
- #
183
- # open_browser("http://www.itest2.com")
184
- # goto_page("/demo") # visit page http://www.itest2.com/demo
185
- #
186
- def goto_page(page)
187
- perform_operation {
188
- @web_browser.goto_page(page) if @web_browser
189
- }
190
- end
191
- alias visit goto_page
192
-
193
- # Go to another web site, normally different site being tested on
194
- #
195
- # open_browser("http://www.itest2.com")
196
- # goto_url("http://myorganized.info")
197
- def goto_url(url)
198
- puts "Calling web_browser goto: #{@web_browser.inspect}"
199
- @web_browser.goto_url url
200
- end
201
-
202
- # Attach to existinb browser window
203
- #
204
- # attach_browser(:title, )
205
- def attach_browser(how, what, options = {})
206
- #TODO
207
- options.merge!(:browser => is_firefox? ? "Firefox" : "IE") unless options[:browser]
208
- begin
209
- options.merge!(:base_url => browser.context.base_url)
210
- rescue => e
211
- puts "failed to set base_url, ignore : #{e}"
212
- end
213
- WebBrowser.attach_browser(how, what, options)
214
- end
215
-
216
- # Reuse current an opened browser window instead of opening a new one
217
- # example:
218
- # use_current_browser(:title, /.*/) # use what ever browser window
219
- # use_current_browser(:title, "TestWise") # use browser window with title "TestWise"
220
- def use_current_browser(how = :title, what = /.*/)
221
- @web_browser = WebBrowser.attach_browser(how, what)
222
- end
223
-
224
- [:back, :forward, :refresh].each do |method|
225
- define_method(method) do
226
- perform_operation { @web_browser.send(method) if @web_browser }
227
- end
228
- end
229
- alias refresh_page refresh
230
- alias go_back back
231
- alias go_forward forward
232
-
233
- ##
234
- # Delegate to WebTester
235
- #
236
- # Note:
237
- # label(:id, "abc") # OK
238
- # label(:id, :abc) # Error
239
- #
240
- # Depends on which object type, you can use following attribute
241
- # More details: http://wiki.openqa.org/display/WTR/Methods+supported+by+Element
242
- #
243
- # :id Used to find an element that has an "id=" attribute. Since each id should be unique, according to the XHTML specification, this is recommended as the most reliable method to find an object. *
244
- # :name Used to find an element that has a "name=" attribute. This is useful for older versions of HTML, but "name" is deprecated in XHTML. *
245
- # :value Used to find a text field with a given default value, or a button with a given caption, or a text field
246
- # :text Used for links, spans, divs and other element that contain text.
247
- # :index Used to find the nth element of the specified type on a page. For example, button(:index, 2) finds the second button. Current versions of WATIR use 1-based indexing, but future versions will use 0-based indexing.
248
- # :class Used for an element that has a "class=" attribute.
249
- # :title Used for an element that has a "title=" attribute.
250
- # :xpath Finds the item using xpath query.
251
- # :method Used only for forms, the method attribute of a form is either GET or POST.
252
- # :action Used only for form elements, specifies the URL where the form is to be submitted.
253
- # :href Used to identify a link by its "href=" attribute.
254
- # :src Used to identify an image by its URL.
255
- #
256
-
257
- # area <area> tags
258
- # button <input> tags with type=button, submit, image or reset
259
- # check_box <input> tags with type=checkbox
260
- # div <div> tags
261
- # form <form> tags
262
- # frame frames, including both the <frame> elements and the corresponding pages
263
- # h1 - h6 <h1>, <h2>, <h3>, <h4>, <h5>, <h6> tags
264
- # hidden <input> tags with type=hidden
265
- # image <img> tags
266
- # label <label> tags (including "for" attribute)
267
- # li <li> tags
268
- # link <a> (anchor) tags
269
- # map <map> tags
270
- # radio <input> tags with the type=radio; known as radio buttons
271
- # select_list <select> tags, known as drop-downs or drop-down lists
272
- # span <span> tags
273
- # table <table> tags, including row and cell methods for accessing nested elements
274
- # text_field <input> tags with the type=text (single-line), type=textarea (multi-line), and type=password
275
- # p <p> (paragraph) tags, because
276
- [: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|
277
- define_method method do |* args|
278
- perform_operation { @web_browser.send(method, * args) if @web_browser }
279
- end
280
- end
281
- alias td cell
282
- alias check_box checkbox # seems watir doc is wrong, checkbox not check_box
283
- alias tr row
284
-
285
-
286
- [:images, :links, :buttons, :select_lists, :checkboxes, :radios, :text_fields].each do |method|
287
- define_method method do
288
- perform_operation { @web_browser.send(method) if @web_browser }
289
- end
290
- end
291
-
292
- # Check one or more checkboxes with same name, can accept a string or an array of string as values checkbox, pass array as values will try to set mulitple checkboxes.
293
- #
294
- # page.check_checkbox('bad_ones', 'Chicken Little')
295
- # page.check_checkbox('good_ones', ['Cars', 'Toy Story'])
296
- #
297
- [: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, :check_checkbox, :uncheck_checkbox, :select_option].each do |method|
298
- define_method method do |* args|
299
- perform_operation { @web_browser.send(method, * args) if @web_browser }
300
- end
301
- end
302
-
303
- alias enter_text set_form_element
304
- alias set_hidden_field set_form_element
305
- alias click_link click_link_with_text
306
- alias click_button_with_text click_button_with_caption
307
- alias click_button click_button_with_caption
308
- alias click_radio_button click_radio_option
309
- alias clear_radio_button clear_radio_option
310
-
311
- # for text field can be easier to be identified by attribute "id" instead of "name", not recommended though
312
- def enter_text_with_id(textfield_id, value)
313
- perform_operation {
314
- elements = find_elements(:id, textfield_id)
315
- if elements.size == 1 then
316
- elements[0].send_keys(value)
317
- else
318
- smaller_set = elements.select {|x| x.tag_name == "textarea" || (x.tag_name == "input" && x.attribute("text")) }
319
- smaller_set[0].send_keys(value)
320
- end
321
- }
322
- end
323
-
324
- def perform_operation(& block)
325
- begin
326
- dump_caller_stack
327
- operation_delay
328
- yield
329
- rescue RuntimeError => re
330
- puts "[DEBUG] operation error: #{re}"
331
- raise re
332
- # ensure
333
- # puts "[DEBUG] ensure #{perform_ok}" unless perform_ok
334
- end
335
- end
336
-
337
- def contains_text(text)
338
- @web_browser.contains_text(text)
339
- end
340
-
341
- # In pages, can't use include, text.should include("abc") won't work
342
- # Instead,
343
- # text.should contains("abc"
344
- def contains(str)
345
- ContainsText.new(str)
346
- end
347
-
348
- alias contain contains
349
-
350
- # Click image buttion with image source name
351
- #
352
- # For an image submit button <input name="submit" type="image" src="/images/search_button.gif">
353
- # click_button_with_image("search_button.gif")
354
- def click_button_with_image_src_contains(image_filename)
355
- perform_operation {
356
- @web_browser.click_button_with_image_src_contains(image_filename)
357
- }
358
- end
359
-
360
- alias click_button_with_image click_button_with_image_src_contains
361
-
362
- def new_popup_window(options)
363
- @web_browser.new_popup_window(options)
364
- end
365
-
366
-
367
- # Warning: this does not work well with Firefox yet.
368
- def element_text(elem_id)
369
- @web_browser.element_value(elem_id)
370
- end
371
-
372
- # Identify DOM element by ID
373
- # Warning: it is only supported on IE
374
- def element_by_id(elem_id)
375
- @web_browser.element_by_id(elem_id)
376
- end
377
-
378
- # ---
379
- # For debugging
380
- # ---
381
- def dump_response(stream = nil)
382
- @web_browser.dump_response(stream)
383
- end
384
-
385
- def default_dump_dir
386
- if $ITEST2_RUNNING_SPEC_ID && $ITEST2_WORKING_DIR
387
-
388
- $ITEST2_DUMP_DIR = File.join($ITEST2_WORKING_DIR, "dump")
389
- FileUtils.mkdir($ITEST2_DUMP_DIR) unless File.exists?($ITEST2_DUMP_DIR)
390
-
391
- spec_run_id = $ITEST2_RUNNING_SPEC_ID
392
- spec_run_dir_name = spec_run_id.to_s.rjust(4, "0") unless spec_run_id == "unknown"
393
- to_dir = File.join($ITEST2_DUMP_DIR, spec_run_dir_name)
394
- else
395
- to_dir = ENV['TEMP_DIR'] || (is_windows? ? "C:\\temp" : "/tmp")
396
- end
397
- end
398
-
399
- # For current page souce to a file in specified folder for inspection
400
- #
401
- # save_current_page(:dir => "C:\\mysite", filename => "abc", :replacement => true)
402
- def save_current_page(options = {})
403
- default_options = {:replacement => true}
404
- options = default_options.merge(options)
405
- to_dir = options[:dir] || default_dump_dir
406
-
407
- if options[:filename]
408
- file_name = options[:filename]
409
- else
410
- file_name = Time.now.strftime("%m%d%H%M%S") + ".html"
411
- end
412
-
413
- Dir.mkdir(to_dir) unless File.exists?(to_dir)
414
- file = File.join(to_dir, file_name)
415
-
416
- content = page_source
417
- base_url = @web_browser.context.base_url
418
- current_url = @web_browser.url
419
- current_url =~ /(.*\/).*$/
420
- current_url_parent = $1
421
- if options[:replacement] && base_url =~ /^http:/
422
- File.new(file, "w").puts absolutize_page_hpricot(content, base_url, current_url_parent)
423
- else
424
- File.new(file, "w").puts content
425
- end
426
-
427
- end
428
-
429
-
430
- # <link rel="stylesheet" type="text/css" href="/stylesheets/default.css" />
431
- # '<script type="text/javascript" src="http://www.jeroenwijering.com/embed/swfobject.js"></script>'
432
- # <script type="text/javascript" src="/javascripts/prototype.js"></script>
433
- # <script type="text/javascript" src="/javascripts/scriptaculous.js?load=effects,builder"></script>
434
- # <script type="text/javascript" src="/javascripts/extensions/gallery/lightbox.js"></script>
435
- # <link href="/stylesheets/extensions/gallery/lightbox.css" rel="stylesheet" type="text/css" />
436
- # <img src="images/mission_48.png" />
437
- def absolutize_page(content, base_url, current_url_parent)
438
- modified_content = ""
439
- content.each_line do |line|
440
- if line =~ /<script\s+.*src=["'']?(.*)["'].*/i then
441
- script_src = $1
442
- substitute_relative_path_in_src_line(line, script_src, base_url, current_url_parent)
443
- elsif line =~ /<link\s+.*href=["'']?(.*)["'].*/i then
444
- link_href = $1
445
- substitute_relative_path_in_src_line(line, link_href, base_url, current_url_parent)
446
- elsif line =~ /<img\s+.*src=["'']?(.*)["'].*/i then
447
- img_src = $1
448
- substitute_relative_path_in_src_line(line, img_src, base_url, current_url_parent)
449
- end
450
-
451
- modified_content += line
452
- end
453
- return modified_content
454
- end
455
-
456
- # absolutize_page referencs using hpricot
457
- #
458
- def absolutize_page_hpricot(content, base_url, parent_url)
459
- return absolutize_page(content, base_url, parent_url) if RUBY_PLATFORM == 'java'
460
- begin
461
- require 'nokogiri'
462
- doc = Nokogiri::HTML(content)
463
- base_url.slice!(-1) if ends_with?(base_url, "/")
464
- (doc/'link').each { |e| e['href'] = absolutify_url(e['href'], base_url, parent_url) || "" }
465
- (doc/'img').each { |e| e['src'] = absolutify_url(e['src'], base_url, parent_url) || "" }
466
- (doc/'script').each { |e| e['src'] = absolutify_url(e['src'], base_url, parent_url) || "" }
467
- return doc.to_html
468
- rescue => e
469
- absolutize_page(content, base_url, parent_url)
470
- end
471
- end
472
-
473
- ##
474
- # change
475
- # <script type="text/javascript" src="/javascripts/prototype.js"></script>
476
- # to
477
- # <script type="text/javascript" src="http://itest2.com/javascripts/prototype.js"></script>
478
- def absolutify_url(src, base_url, parent_url)
479
- if src.nil? || src.empty? || src == "//:" || src =~ /\s*http:\/\//i
480
- return src
481
- end
482
-
483
- return "#{base_url}#{src}" if src =~ /^\s*\//
484
- return "#{parent_url}#{src}" if parent_url
485
- return src
486
- end
487
-
488
- # substut
489
- def substitute_relative_path_in_src_line(line, script_src, host_url, page_parent_url)
490
- unless script_src =~ /^["']?http:/
491
- host_url.slice!(-1) if ends_with?(host_url, "/")
492
- if script_src =~ /^\s*\// # absolute_path
493
- line.gsub!(script_src, "#{host_url}#{script_src}")
494
- else #relative_path
495
- line.gsub!(script_src, "#{page_parent_url}#{script_src}")
496
- end
497
- end
498
- end
499
-
500
- def ends_with?(str, suffix)
501
- suffix = suffix.to_s
502
- str[-suffix.length, suffix.length] == suffix
503
- end
504
-
505
- # current web page title
506
- def page_title
507
- @web_browser.page_title
508
- end
509
-
510
- # current page source (in HTML)
511
- def page_source
512
- @web_browser.page_source
513
- end
514
-
515
- # return plain text view of page
516
- def page_text
517
- @web_browser.text
518
- end
519
-
520
- # return the text of specific (identified by attribute "id") label tag
521
- # For page containing
522
- # <label id="preferred_ide">TestWise</label>
523
- # label_with_id("preferred_ids") # => TestWise
524
- # label_with_id("preferred_ids", :index => 2) # => TestWise
525
- def label_with_id(label_id, options = {})
526
- if options && options[:index] then
527
- elements = find_elements(:id, label_id.to_s)
528
- elements[options[:index].to_i - 1].text
529
- # label(:id => label_id.to_s, :index => options[:index]).text
530
- else
531
- find_element(:id, label_id.to_s).text
532
- end
533
- end
534
-
535
- # return the text of specific (identified by attribute "id") span tag
536
- # For page containing
537
- # <span id="preferred_recorder">iTest2/Watir Recorder</span>
538
- # span_with_id("preferred_recorder") # => iTest2/Watir Recorder
539
- def span_with_id(span_id, options = {})
540
- if options && options[:index] then
541
- elements = find_elements(:id, span_id.to_s)
542
- elements[options[:index].to_i - 1].text
543
- else
544
- find_element(:id, span_id.to_s).text
545
- end
546
- end
547
-
548
- # return the text of specific (identified by attribute "id") ta tag
549
- # For page containing
550
- # <td id="preferred_recorder">iTest2/Watir Recorder</span>
551
- # td_with_id("preferred_recorder") # => iTest2/Watir Recorder
552
- def cell_with_id(cell_id, options = {})
553
- if options && options[:index] then
554
- elements = find_elements(:id, cell_id.to_s)
555
- elements[options[:index].to_i - 1].text
556
- else
557
- find_element(:id, cell_id.to_s).text
558
- end
559
- end
560
- alias table_data_with_id cell_with_id
561
-
562
-
563
- def is_mac?
564
- RUBY_PLATFORM.downcase.include?("darwin")
565
- end
566
-
567
- def is_windows?
568
- RUBY_PLATFORM.downcase.include?("mswin") or RUBY_PLATFORM.downcase.include?("mingw")
569
- end
570
-
571
- def is_linux?
572
- RUBY_PLATFORM.downcase.include?("linux")
573
- end
574
-
575
- # Support browser (IE) operations using unicode
576
- # Example:
577
- # click_button("Google 搜索")
578
- # Reference: http://jira.openqa.org/browse/WTR-219
579
- def support_utf8
580
- if is_windows?
581
- require 'win32ole'
582
- WIN32OLE.codepage = WIN32OLE::CP_UTF8
583
- end
584
- end
585
-
586
- alias support_unicode support_utf8
587
-
588
- #= Convenient functions
589
- #
590
-
591
- # Using Ruby block syntax to create interesting domain specific language,
592
- # may be appeal to someone.
593
-
594
- # Example:
595
- # on @page do |i|
596
- # i.enter_text('btn1')
597
- # i.click_button('btn1')
598
- # end
599
- def on(page, & block)
600
- yield page
601
- end
602
-
603
- # fail the test if user can perform the operation
604
- #
605
- # Example:
606
- # shall_not_allow { 1/0 }
607
- def shall_not_allow(& block)
608
- operation_performed_ok = false
609
- begin
610
- yield
611
- operation_performed_ok = true
612
- rescue
613
- end
614
- raise "Operation shall not be allowed" if operation_performed_ok
615
- end
616
-
617
- alias do_not_allow shall_not_allow
618
-
619
- # Does not provide real function, other than make enhancing test syntax
620
- #
621
- # Example:
622
- # allow { click_button('Register') }
623
- def allow(& block)
624
- yield
625
- end
626
-
627
- alias shall_allow allow
628
- alias allowing allow
629
-
630
- # try operation, ignore if errors occur
631
- #
632
- # Example:
633
- # failsafe { click_link("Logout") } # try logout, but it still OK if not being able to (already logout))
634
- def failsafe(& block)
635
- begin
636
- yield
637
- rescue =>e
638
- end
639
- end
640
-
641
- alias fail_safe failsafe
642
-
643
-
644
- # Execute the provided block until either (1) it returns true, or
645
- # (2) the timeout (in seconds) has been reached. If the timeout is reached,
646
- # a TimeOutException will be raised. The block will always
647
- # execute at least once.
648
- #
649
- # This does not handle error, if the given block raise error, the statement finish with error
650
- # Examples:
651
- # wait_until {puts 'hello'}
652
- # wait_until { div(:id, :receipt_date).exists? }
653
- #
654
- def wait_until(timeout = @@default_timeout || 30, polling_interval = @@default_polling_interval || 1, & block)
655
- end_time = ::Time.now + timeout
656
-
657
- until ::Time.now > end_time
658
- result = nil
659
- begin
660
- result = yield(self)
661
- return result if result
662
- rescue => e
663
- end
664
- sleep polling_interval
665
- end
666
-
667
- raise TimeoutError, "timed out after #{timeout} seconds"
668
- end
669
-
670
- # Wait for specific seconds for an Ajax update finish.
671
- # Trick: In your Rails application,
672
- # :loading => "Element.show('search_indicator');
673
- # :complete => "Element.hide('search_indicator');
674
- #
675
- # <%= image_tag("indicator.gif", :id => 'search_indicator', :style => 'display:none') %>
676
- #
677
- # Typical usage:
678
- # ajax_wait_for_element("search_indicator", 30)
679
- # ajax_wait_for_element("search_indicator", 30, "show")
680
- # ajax_wait_for_element("search_indicator", 30, "hide")
681
- # ajax_wait_for_element("search_indicator", 30, "show", 5) # check every 5 seconds
682
- #
683
- # Warning: this method has not been fully tested, if you are not using Rails, change your parameter accordingly.
684
- #
685
- def ajax_wait_for_element(element_id, seconds, status='show', check_interval = @@default_polling_interval)
686
- count = 0
687
- check_interval = 1 if check_interval < 1 or check_interval > seconds
688
- while count < (seconds / check_interval) do
689
- search_indicator = @web_browser.element_by_id(element_id)
690
- search_indicator_outer_html = search_indicator.outerHtml if search_indicator
691
- if status == 'hide'
692
- return true if search_indicator_outer_html and !search_indicator_outer_html.include?('style="DISPLAY: none"')
693
- else
694
- return true if search_indicator_outer_html and search_indicator_outer_html.include?('style="DISPLAY: none"')
695
- end
696
- sleep check_interval if check_interval > 0 and check_interval < 5 * 60 # wait max 5 minutes
697
- count += 1
698
- end
699
- return false
700
- end
701
-
702
- #Wait the element with given id to be present in web page
703
- #
704
- # Warning: this not working in Firefox, try use wait_util or try instead
705
- def wait_for_element(element_id, timeout = @@default_timeout, interval = @@default_polling_interval)
706
- start_time = Time.now
707
- #TODO might not work with Firefox
708
- until @web_browser.element_by_id(element_id) do
709
- sleep(interval)
710
- if (Time.now - start_time) > timeout
711
- raise RuntimeError, "failed to find element: #{element_id} for max #{timeout}"
712
- end
713
- end
714
- end
715
-
716
- =begin
717
-
718
- # TODO: Firewatir does not suport retrieving style or outerHtml
719
- # http://jira.openqa.org/browse/WTR-260
720
- # http://code.google.com/p/firewatir/issues/detail?id=76
721
- #
722
- # Max timeout value is 10 minutes
723
- #
724
- def ajax_call_complete_after_element_hidden(elem_id, check_start = 0.5, timeout = 5, interval = 0.5, &block)
725
- yield
726
- sleep check_start # the time allowed to perform the coomplete
727
- timeout = 10 * 60 if timeout > 10 * 600 or timeout <= 0
728
- begin
729
- Timeout::timeout(timeout) {
730
- begin
731
- elem = element_by_id(elem_id)
732
- while elem do
733
- puts "outer=>#{elem.outerHtml}|"
734
- puts "style =>#{elem.attribute_value('style')}|"
735
- sleep interval
736
- elem = element_by_id(elem_id)
737
- end
738
- rescue => e
739
- puts e
740
- end
741
- }
742
- rescue Timeout::Error
743
- # Too slow!!
744
- raise "Too slow, wait max #{timeout} seconds, the element #{elem_id} still there"
745
- end
746
- end
747
-
748
- =end
749
-
750
- # Try the operation up to specified times, and sleep given interval (in seconds)
751
- # Error will be ignored until timeout
752
- # Example
753
- # repeat_try(3, 2) { click_button('Search' } # 3 times, 6 seconds in total
754
- # repeat_try { click_button('Search' } # using default 5 tries, 2 second interval
755
- def repeat_try(num_tries = @@default_timeout || 30, interval = @@default_polling_interval || 1, & block)
756
- num_tries ||= 1
757
- (num_tries - 1).times do |num|
758
- begin
759
- yield
760
- return
761
- rescue => e
762
- # puts "debug: #{num} failed: #{e}"
763
- sleep interval
764
- end
765
- end
766
-
767
- # last try, throw error if still fails
768
- begin
769
- yield
770
- rescue => e
771
- raise e.to_s + " after trying #{num_tries} times every #{interval} seconds"
772
- end
773
- yield
774
- end
775
-
776
- # TODO: syntax
777
-
778
- # Try the operation up to specified timeout (in seconds), and sleep given interval (in seconds).
779
- # Error will be ignored until timeout
780
- # Example
781
- # try { click_link('waiting')}
782
- # try(10, 2) { click_button('Search' } # try to click the 'Search' button upto 10 seconds, try every 2 seconds
783
- # try { click_button('Search' }
784
- def try(timeout = @@default_timeout, polling_interval = @@default_polling_interval || 1, & block)
785
- start_time = Time.now
786
-
787
- last_error = nil
788
- until (duration = Time.now - start_time) > timeout
789
- begin
790
- return if yield
791
- last_error = nil
792
- rescue => e
793
- last_error = e
794
- end
795
- sleep polling_interval
796
- end
797
-
798
- raise "Timeout after #{duration.to_i} seconds with error: #{last_error}." if last_error
799
- raise "Timeout after #{duration.to_i} seconds."
800
- end
801
-
802
- alias try_upto try
803
-
804
- ##
805
- # Convert :first to 1, :second to 2, and so on...
806
- def symbol_to_sequence(symb)
807
- value = {:zero => 0,
808
- :first => 1,
809
- :second => 2,
810
- :third => 3,
811
- :fourth => 4,
812
- :fifth => 5,
813
- :sixth => 6,
814
- :seventh => 7,
815
- :eighth => 8,
816
- :ninth => 9,
817
- :tenth => 10}[symb]
818
- return value || symb.to_i
819
- end
820
-
821
- # Clear popup windows such as 'Security Alert' or 'Security Information' popup window,
822
- #
823
- # Screenshot see http://kb2.adobe.com/cps/165/tn_16588.html
824
- #
825
- # You can also by pass security alerts by change IE setting, http://kb.iu.edu/data/amuj.html
826
- #
827
- # Example
828
- # clear_popup("Security Information", 5, true) # check for Security Information for 5 seconds, click Yes
829
- def clear_popup(popup_win_title, seconds = 10, yes = true)
830
- # commonly "Security Alert", "Security Information"
831
- if is_windows?
832
- sleep 1
833
- autoit = WIN32OLE.new('AutoItX3.Control')
834
- # Look for window with given title. Give up after 1 second.
835
- ret = autoit.WinWait(popup_win_title, '', seconds)
836
- #
837
- # If window found, send appropriate keystroke (e.g. {enter}, {Y}, {N}).
838
- if ret == 1 then
839
- puts "about to send click Yes" if debugging?
840
- button_id = yes ? "Button1" : "Button2" # Yes or No
841
- autoit.ControlClick(popup_win_title, '', button_id)
842
- end
843
- sleep(0.5)
844
- else
845
- raise "Currently supported only on Windows"
846
- end
847
- end
848
-
849
- def select_file_for_upload(file_field_name, file_path)
850
- =begin
851
- if is_windows?
852
- normalized_file_path = file_path.gsub("/", "\\")
853
- if $support_ie8 && check_ie_version && @ie_version >= 8
854
- # puts "IE8"
855
- file_field(:name, file_field).set(normalized_file_path)
856
- # choose_file_dialog(normalized_file_path)
857
- else
858
- file_field(:name, file_field).set(normalized_file_path)
859
- end
860
- else
861
- # for firefox, just call file_field, it may fail
862
- file_field(:name, file_field).set(normalized_file_path)
863
- end
864
- =end
865
- elem = find_element(:name, file_field_name)
866
- elem.send_keys(file_path)
867
- end
868
-
869
- def choose_file_dialog(file_path)
870
- Watir.autoit.WinWaitActive("Choose File to Upload", '', 10)
871
- Watir.autoit.ControlSetText("Choose File to Upload", "", 1148, file_path)
872
- Watir.autoit.ControlClick("Choose File to Upload", "", "&Open")
873
- end
874
-
875
- def check_ie_version
876
- if is_windows? && @ie_version.nil?
877
- begin
878
- cmd = 'reg query "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v Version';
879
- result = `#{cmd}`
880
- version_line = nil
881
- result.each do |line|
882
- if (line =~ /Version\s+REG_SZ\s+([\d\.]+)/)
883
- version_line = $1
884
- end
885
- end
886
-
887
- if version_line =~ /^\s*(\d+)\./
888
- @ie_version = $1.to_i
889
- end
890
- rescue => e
891
- end
892
- end
893
- end
894
-
895
- # Use AutoIT3 to send password
896
- # title starts with "Connect to ..."
897
- def basic_authentication_ie(title, username, password, options = {})
898
- default_options = {:textctrl_username => "Edit2",
899
- :textctrl_password => "Edit3",
900
- :button_ok => 'Button1'
901
- }
902
-
903
- options = default_options.merge(options)
904
-
905
- title ||= ""
906
- if title =~ /^Connect\sto/
907
- full_title = title
908
- else
909
- full_title = "Connect to #{title}"
910
- end
911
- require 'rformspec'
912
- login_win = RFormSpec::Window.new(full_title)
913
- login_win.send_control_text(options[:textctrl_username], username)
914
- login_win.send_control_text(options[:textctrl_password], password)
915
- login_win.click_button("OK")
916
- end
917
-
918
- # Use JSSH to pass authentication
919
- # Window title "Authentication required"
920
- def basic_authentication_firefox(username, password, wait = 3)
921
- jssh_command = "
922
- var length = getWindows().length;
923
- var win;
924
- var found = false;
925
- for (var i = 0; i < length; i++) {
926
- win = getWindows()[i];
927
- if(win.document.title == \"Authentication Required\") {
928
- found = true;
929
- break;
930
- }
931
- }
932
- if (found) {
933
- var jsdocument = win.document;
934
- var dialog = jsdocument.getElementsByTagName(\"dialog\")[0];
935
- jsdocument.getElementsByTagName(\"textbox\")[0].value = \"#{username}\";
936
- jsdocument.getElementsByTagName(\"textbox\")[1].value = \"#{password}\";
937
- dialog.getButton(\"accept\").click();
938
- }
939
- \n"
940
- sleep(wait)
941
- $jssh_socket.send(jssh_command, 0)
942
- # read_socket()
943
- end
944
-
945
- def basic_authentication_celerity(username, password)
946
- @web_browser.celerity.credentials = "#{username}:#{password}"
947
- end
948
-
949
- def basic_authentication(username, password, options = {})
950
- if is_celerity?
951
- basic_authentication_celerity(username, password)
952
- elsif is_firefox?
953
- basic_authentication_firefox(username, password)
954
- else
955
- basic_authentication_ie(options[:title], username, password, options)
956
- end
957
- end
958
-
959
- # take_screenshot to save the current active window
960
- # TODO can't move mouse
961
- def take_screenshot_old
962
- if is_windows? && $ITEST2_DUMP_PAGE
963
- begin
964
- puts "[DEBUG] Capturing screenshots..."
965
- screenshot_image_filename = "rwebspec_" + Time.now.strftime("%m%d%H%M%S") + ".jpg"
966
- the_dump_dir = default_dump_dir
967
- FileUtils.mkdir_p(the_dump_dir) unless File.exists?(the_dump_dir)
968
- screenshot_image_filepath = File.join(the_dump_dir, screenshot_image_filename)
969
-
970
- screenshot_image_filepath.gsub!("/", "\\") if is_windows?
971
- screen_capture(screenshot_image_filepath, true)
972
-
973
- notify_screenshot_location(screenshot_image_filepath)
974
- rescue
975
- puts "error: #{Failed to capture screen}"
976
- end
977
- end
978
- end
979
-
980
-
981
- # use win32screenshot library to save curernt active window, which shall be IE
982
- #
983
- def take_screenshot
984
- if $testwise_screenshot_supported && is_windows?
985
- begin
986
- screenshot_image_filename = "screenshot_" + Time.now.strftime("%m%d%H%M%S") + ".jpg"
987
- the_dump_dir = default_dump_dir
988
- FileUtils.mkdir_p(the_dump_dir) unless File.exists?(the_dump_dir)
989
- screenshot_image_filepath = File.join(the_dump_dir, screenshot_image_filename)
990
- screenshot_image_filepath.gsub!("/", "\\") if is_windows?
991
-
992
- FileUtils.rm_f(screenshot_image_filepath) if File.exist?(screenshot_image_filepath)
993
-
994
- case @web_browser.underlying_browser.browser
995
- when :internet_explorer
996
- Win32::Screenshot::Take.of(:window, :title => /internet\sexplorer/i).write(screenshot_image_filepath)
997
- else
998
- Win32::Screenshot::Take.of(:foreground).write(screenshot_image_filepath)
999
- end
1000
- notify_screenshot_location(screenshot_image_filepath)
1001
- rescue => e
1002
- puts "error on taking screenshot: #{e}"
1003
- end
1004
- end
1005
- end
1006
-
1007
- end
1008
-
1009
- end