firewatir 1.1.1

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.
Files changed (95) hide show
  1. data/MozillaBaseElement.rb +1778 -0
  2. data/container.rb +889 -0
  3. data/firewatir/exceptions.rb +44 -0
  4. data/firewatir/testUnitAddons.rb +8 -0
  5. data/firewatir.rb +1130 -0
  6. data/htmlelements.rb +2277 -0
  7. data/unittests/attach_to_new_window_test.rb +34 -0
  8. data/unittests/bug_fixes_test.rb +188 -0
  9. data/unittests/buttons_test.rb +215 -0
  10. data/unittests/buttons_xpath_test.rb +87 -0
  11. data/unittests/checkbox_test.rb +154 -0
  12. data/unittests/checkbox_xpath_test.rb +107 -0
  13. data/unittests/div_test.rb +274 -0
  14. data/unittests/filefield_test.rb +45 -0
  15. data/unittests/filefield_xpath_test.rb +35 -0
  16. data/unittests/form_test.rb +307 -0
  17. data/unittests/frame_test.rb +151 -0
  18. data/unittests/hidden_test.rb +85 -0
  19. data/unittests/hidden_xpath_test.rb +72 -0
  20. data/unittests/html/JavascriptClick.html +42 -0
  21. data/unittests/html/blankpage.html +12 -0
  22. data/unittests/html/buttons1.html +61 -0
  23. data/unittests/html/checkboxes1.html +71 -0
  24. data/unittests/html/complex_table.html +36 -0
  25. data/unittests/html/cssTest.html +42 -0
  26. data/unittests/html/div.html +72 -0
  27. data/unittests/html/div_xml.html +21 -0
  28. data/unittests/html/fileupload.html +45 -0
  29. data/unittests/html/formTest1.html +39 -0
  30. data/unittests/html/forms2.html +45 -0
  31. data/unittests/html/forms3.html +132 -0
  32. data/unittests/html/forms4.html +27 -0
  33. data/unittests/html/frame_buttons.html +4 -0
  34. data/unittests/html/frame_links.html +4 -0
  35. data/unittests/html/frame_multi.html +5 -0
  36. data/unittests/html/iframeTest.html +15 -0
  37. data/unittests/html/iframeTest1.html +14 -0
  38. data/unittests/html/iframeTest2.html +6 -0
  39. data/unittests/html/images/1.gif +0 -0
  40. data/unittests/html/images/2.GIF +0 -0
  41. data/unittests/html/images/3.GIF +0 -0
  42. data/unittests/html/images/button.jpg +0 -0
  43. data/unittests/html/images/circle.jpg +0 -0
  44. data/unittests/html/images/minus.GIF +0 -0
  45. data/unittests/html/images/originaltriangle.jpg +0 -0
  46. data/unittests/html/images/plus.gif +0 -0
  47. data/unittests/html/images/square.jpg +0 -0
  48. data/unittests/html/images/triangle.jpg +0 -0
  49. data/unittests/html/images1.html +67 -0
  50. data/unittests/html/javascriptevents.html +35 -0
  51. data/unittests/html/link_pass.html +11 -0
  52. data/unittests/html/links1.html +42 -0
  53. data/unittests/html/links2.html +11 -0
  54. data/unittests/html/modal_dialog.html +8 -0
  55. data/unittests/html/modal_dialog_launcher.html +12 -0
  56. data/unittests/html/nestedFrames.html +6 -0
  57. data/unittests/html/new_browser.html +17 -0
  58. data/unittests/html/pass.html +10 -0
  59. data/unittests/html/popups1.html +60 -0
  60. data/unittests/html/pre.html +28 -0
  61. data/unittests/html/radioButtons1.html +71 -0
  62. data/unittests/html/redirect.html +10 -0
  63. data/unittests/html/redirect1.html +9 -0
  64. data/unittests/html/redirect2.html +9 -0
  65. data/unittests/html/redirect3.html +9 -0
  66. data/unittests/html/select_tealeaf.html +54 -0
  67. data/unittests/html/selectboxes1.html +55 -0
  68. data/unittests/html/simple_table.html +26 -0
  69. data/unittests/html/simple_table_buttons.html +104 -0
  70. data/unittests/html/simple_table_columns.html +74 -0
  71. data/unittests/html/table1.html +165 -0
  72. data/unittests/html/tableCell_using_xpath.html +19 -0
  73. data/unittests/html/textarea.html +30 -0
  74. data/unittests/html/textfields1.html +62 -0
  75. data/unittests/html/textsearch.html +44 -0
  76. data/unittests/images_test.rb +204 -0
  77. data/unittests/images_xpath_test.rb +118 -0
  78. data/unittests/iostring.rb +30 -0
  79. data/unittests/iostring_test.rb +48 -0
  80. data/unittests/javascript_test.rb +71 -0
  81. data/unittests/links_test.rb +230 -0
  82. data/unittests/links_xpath_test.rb +79 -0
  83. data/unittests/mozilla_all_tests.rb +18 -0
  84. data/unittests/pre_test.rb +74 -0
  85. data/unittests/radios_test.rb +166 -0
  86. data/unittests/radios_xpath_test.rb +101 -0
  87. data/unittests/redirect_test.rb +40 -0
  88. data/unittests/selectbox_test.rb +141 -0
  89. data/unittests/selectbox_xpath_test.rb +127 -0
  90. data/unittests/setup.rb +35 -0
  91. data/unittests/table_test.rb +372 -0
  92. data/unittests/table_xpath_test.rb +184 -0
  93. data/unittests/textfields_test.rb +230 -0
  94. data/unittests/textfields_xpath_test.rb +112 -0
  95. metadata +144 -0
data/firewatir.rb ADDED
@@ -0,0 +1,1130 @@
1
+ =begin
2
+ license
3
+ ---------------------------------------------------------------------------
4
+ Copyright (c) 2006-2007, Angrez Singh
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice,
10
+ this list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright
13
+ notice, this list of conditions and the following disclaimer in the
14
+ documentation and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the names Angrez Singh nor the names of contributors to
17
+ this software may be used to endorse or promote products derived from this
18
+ software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
21
+ IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
24
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ --------------------------------------------------------------------------
32
+ (based on BSD Open Source License)
33
+ =end
34
+
35
+ =begin rdoc
36
+ This is FireWatir, Web Application Testing In Ruby using Firefox browser
37
+ The home page for this project is http://code.google.com/p/firewatir
38
+
39
+ Typical usage:
40
+ # include the controller
41
+ require "firewatir"
42
+
43
+ # go to the page you want to test
44
+ ff = FireWatir::Firefox.start("http://myserver/mypage")
45
+
46
+ # enter "Angrez" into an input field named "username"
47
+ ff.text_field(:name, "username").set("Angrez")
48
+
49
+ # enter "Ruby Co" into input field with id "company_ID"
50
+ ff.text_field(:id, "company_ID").set("Ruby Co")
51
+
52
+ # click on a link that has "green" somewhere in the text that is displayed
53
+ # to the user, using a regular expression
54
+ ff.link(:text, /green/)
55
+
56
+ # click button that has a caption of "Cancel"
57
+ ff.button(:value, "Cancel").click
58
+
59
+ FireWatir allows your script to read and interact with HTML objects--HTML tags
60
+ and their attributes and contents. Types of objects that FireWatir can identify
61
+ include:
62
+
63
+ Type Description
64
+ =========== ===============================================================
65
+ button <input> tags, with the type="button" attribute
66
+ check_box <input> tags, with the type="checkbox" attribute
67
+ div <div> tags
68
+ form
69
+ frame
70
+ hidden hidden <input> tags
71
+ image <img> tags
72
+ label
73
+ link <a> (anchor) tags
74
+ p <p> (paragraph) tags
75
+ radio radio buttons; <input> tags, with the type="radio" attribute
76
+ select_list <select> tags, known informally as drop-down boxes
77
+ span <span> tags
78
+ table <table> tags
79
+ text_field <input> tags with the type="text" attribute (a single-line
80
+ text field), the type="text_area" attribute (a multi-line
81
+ text field), and the type="password" attribute (a
82
+ single-line field in which the input is replaced with asterisks)
83
+
84
+ In general, there are several ways to identify a specific object. FireWatir's
85
+ syntax is in the form (how, what), where "how" is a means of identifying
86
+ the object, and "what" is the specific string or regular expression
87
+ that FireWatir will seek, as shown in the examples above. Available "how"
88
+ options depend upon the type of object, but here are a few examples:
89
+
90
+ How Description
91
+ ============ ===============================================================
92
+ :id Used to find an object that has an "id=" attribute. Since each
93
+ id should be unique, according to the XHTML specification,
94
+ this is recommended as the most reliable method to find an
95
+ object.
96
+ :name Used to find an object that has a "name=" attribute. This is
97
+ useful for older versions of HTML, but "name" is deprecated
98
+ in XHTML.
99
+ :value Used to find a text field with a given default value, or a
100
+ button with a given caption
101
+ :index Used to find the nth object of the specified type on a page.
102
+ For example, button(:index, 2) finds the second button.
103
+ Current versions of FireWatir use 1-based indexing, but future
104
+ versions will use 0-based indexing.
105
+ :xpath The xpath expression for identifying the element.
106
+
107
+ Note that the XHTML specification requires that tags and their attributes be
108
+ in lower case. FireWatir doesn't enforce this; FireWatir will find tags and
109
+ attributes whether they're in upper, lower, or mixed case. This is either
110
+ a bug or a feature.
111
+
112
+ FireWatir uses JSSh for interacting with the browser. For further information on
113
+ Firefox and DOM go to the following Web page:
114
+
115
+ http://www.xulplanet.com/references/objref/
116
+
117
+ =end
118
+
119
+ require 'firewatir/exceptions'
120
+ require 'container'
121
+ require 'MozillaBaseElement.rb'
122
+ require 'htmlelements.rb'
123
+ require 'socket'
124
+
125
+ class String
126
+ def matches (x)
127
+ return self == x
128
+ end
129
+ end
130
+
131
+ class Regexp
132
+ def matches (x)
133
+ return self.match(x)
134
+ end
135
+ end
136
+
137
+ class Integer
138
+ def matches (x)
139
+ return self == x
140
+ end
141
+ end
142
+
143
+ module FireWatir
144
+ include FireWatir::Exception
145
+
146
+ class Firefox
147
+
148
+ include Container
149
+
150
+ # XPath Result type. Return only first node that matches the xpath expression.
151
+ # More details: "http://developer.mozilla.org/en/docs/DOM:document.evaluate"
152
+ FIRST_ORDERED_NODE_TYPE = 9
153
+
154
+ VERSION = '1.1.1'
155
+
156
+ # variable to check if firefox browser has been started or not. Currently this is
157
+ # used only while starting firefox on windows. For other platforms you need to start
158
+ # firefox manually.
159
+ #@@firefox_started = false
160
+
161
+ # Stack to hold windows.
162
+ @@window_stack = Array.new
163
+
164
+ # This allows us to identify the window uniquely and close them accordingly.
165
+ @window_title = nil
166
+ @window_url = nil
167
+
168
+
169
+ #
170
+ # Description:
171
+ # Starts the firefox browser. Currently this only works for Windows Platform.
172
+ # For others, you need to start Firefox manually using -jssh option.
173
+ # On windows this starts the first version listed in the registry.
174
+ #
175
+ # Input:
176
+ # options - Hash of any of the following options:
177
+ # :waitTime - Time to wait for Firefox to start. By default it waits for 2 seconds.
178
+ # This is done because if Firefox is not started and we try to connect
179
+ # to jssh on port 9997 an exception is thrown.
180
+ # :profile - The Firefox profile to use. If none is specified, Firefox will use
181
+ # the last used profile. Note that the :profile option only works if
182
+ # no other instances of Firefox are already running.
183
+
184
+ # TODO: Start the firefox version given by user. For example
185
+ # ff = FireWatir::Firefox.new("1.5.0.4")
186
+ #
187
+
188
+ def initialize(options = {})
189
+ if(options.kind_of?(Integer))
190
+ options = {:waitTime => options}
191
+ end
192
+
193
+ if(options[:profile])
194
+ profile_opt = "-P #{options[:profile]}"
195
+ else
196
+ profile_opt = ""
197
+ end
198
+
199
+ puts "PROFILE: #{profile_opt}"
200
+
201
+ waitTime = options[:waitTime] || 2
202
+
203
+ if(RUBY_PLATFORM =~ /.*mswin.*/)
204
+ #puts "plaftorm is windows"
205
+ # Get the path to Firefox.exe using Registry.
206
+ require 'win32/registry.rb'
207
+ path_to_exe = ""
208
+ Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Mozilla\Mozilla Firefox') do |reg|
209
+ keys = reg.keys
210
+ reg1 = Win32::Registry::HKEY_LOCAL_MACHINE.open("SOFTWARE\\Mozilla\\Mozilla Firefox\\#{keys[0]}\\Main")
211
+ reg1.each do |subkey, type, data|
212
+ if(subkey =~ /pathtoexe/i)
213
+ path_to_exe = data
214
+ end
215
+ end
216
+ end
217
+
218
+ puts "Starting Firefox using the executable : #{path_to_exe}"
219
+ puts "Waiting for #{waitTime} seconds for Firefox to get started."
220
+ @t = Thread.new { system("\"#{path_to_exe}\" -jssh #{profile_opt}") }
221
+ elsif(RUBY_PLATFORM =~ /linux/i)
222
+ puts RUBY_PLATFORM
223
+ path_to_bin = `which firefox`.strip
224
+ puts "#{path_to_bin} -jssh #{profile_opt}"
225
+ @t = Thread.new { `#{path_to_bin} -jssh #{profile_opt}` }
226
+ end
227
+
228
+ sleep waitTime
229
+
230
+ set_defaults()
231
+ get_window_number()
232
+ set_browser_document()
233
+ end
234
+
235
+ #
236
+ # Description:
237
+ # Creates a new instance of Firefox. Loads the URL and return the instance.
238
+ #
239
+ # Input:
240
+ # url - url of the page to be loaded.
241
+ #
242
+ # Output:
243
+ # New instance of firefox browser with the given url loaded.
244
+ #
245
+ def self.start(url)
246
+ ff = Firefox.new
247
+ ff.goto(url)
248
+ return ff
249
+ end
250
+
251
+ #
252
+ # Description:
253
+ # Gets the window number opened. Used internally by Firewatir.
254
+ #
255
+ def get_window_number()
256
+ $jssh_socket.send("getWindows().length;\n", 0)
257
+ @@current_window = read_socket().to_i - 1
258
+ # This will store the information about the window.
259
+ #@@window_stack.push(@@current_window)
260
+ #puts "here in get_window_number window number is #{@@current_window}"
261
+ return @@current_window
262
+ end
263
+ private :get_window_number
264
+
265
+ #
266
+ # Description:
267
+ # Loads the given url in the browser. Waits for the page to get loaded.
268
+ #
269
+ # Input:
270
+ # url - url to be loaded.
271
+ #
272
+ def goto(url)
273
+ #set_defaults()
274
+ get_window_number()
275
+ set_browser_document()
276
+ # Load the given url.
277
+ $jssh_socket.send("#{BROWSER_VAR}.loadURI(\"#{url}\");\n" , 0)
278
+ read_socket()
279
+
280
+ wait()
281
+ end
282
+
283
+ #
284
+ # Description:
285
+ # Loads the previous page (if there is any) in the browser. Waits for the page to get loaded.
286
+ #
287
+ def back()
288
+ #set_browser_document()
289
+ $jssh_socket.send("if(#{BROWSER_VAR}.canGoBack) #{BROWSER_VAR}.goBack();\n", 0)
290
+ read_socket();
291
+ wait()
292
+ end
293
+
294
+ #
295
+ # Description:
296
+ # Loads the next page (if there is any) in the browser. Waits for the page to get loaded.
297
+ #
298
+ def forward()
299
+ #set_browser_document()
300
+ $jssh_socket.send("if(#{BROWSER_VAR}.canGoForward) #{BROWSER_VAR}.goForward();\n", 0)
301
+ read_socket();
302
+ wait()
303
+ end
304
+
305
+ #
306
+ # Description:
307
+ # Reloads the current page in the browser. Waits for the page to get loaded.
308
+ #
309
+ def refresh()
310
+ #set_browser_document()
311
+ $jssh_socket.send("#{BROWSER_VAR}.reload();\n", 0)
312
+ read_socket();
313
+ wait()
314
+ end
315
+
316
+ #
317
+ # Description:
318
+ # This function creates a new socket at port 9997 and sets the default values for instance and class variables.
319
+ # Generatesi UnableToStartJSShException if cannot connect to jssh even after 3 tries.
320
+ #
321
+ def set_defaults(no_of_tries = 0)
322
+ # JSSH listens on port 9997. Create a new socket to connect to port 9997.
323
+ begin
324
+ $jssh_socket = TCPSocket::new(MACHINE_IP, "9997")
325
+ $jssh_socket.sync = true
326
+ read_socket()
327
+ rescue
328
+ no_of_tries += 1
329
+ retry if no_of_tries < 3
330
+ raise UnableToStartJSShException, "Unable to connect to machine : #{MACHINE_IP} on port 9997. Make sure that JSSh is properly installed and Firefox is running with '-jssh' option"
331
+ end
332
+ end
333
+ private :set_defaults
334
+
335
+ def set_slow_speed
336
+ @typingspeed = DEFAULT_TYPING_SPEED
337
+ @defaultSleepTime = DEFAULT_SLEEP_TIME
338
+ end
339
+ private :set_slow_speed
340
+
341
+ #
342
+ # Description:
343
+ # Sets the document, window and browser variables to point to correct object in JSSh.
344
+ #
345
+ def set_browser_document
346
+ # Get the window in variable WINDOW_VAR.
347
+ # Get the browser in variable BROWSER_VAR.
348
+ jssh_command = "var #{WINDOW_VAR} = getWindows()[#{@@current_window}];"
349
+ jssh_command += " var #{BROWSER_VAR} = #{WINDOW_VAR}.getBrowser();"
350
+ # Get the document and body in variable DOCUMENT_VAR and BODY_VAR respectively.
351
+ jssh_command += "var #{DOCUMENT_VAR} = #{BROWSER_VAR}.contentDocument;"
352
+ jssh_command += "var #{BODY_VAR} = #{DOCUMENT_VAR}.body;"
353
+
354
+ $jssh_socket.send("#{jssh_command}\n", 0)
355
+ read_socket()
356
+
357
+ # Get window and window's parent title and url
358
+ $jssh_socket.send("#{DOCUMENT_VAR}.title;\n", 0)
359
+ @window_title = read_socket()
360
+ $jssh_socket.send("#{DOCUMENT_VAR}.URL;\n", 0)
361
+ @window_url = read_socket()
362
+ end
363
+ private :set_browser_document
364
+
365
+ #
366
+ # Description:
367
+ # Closes the window.
368
+ #
369
+ def close()
370
+ #puts "current window number is : #{@@current_window}"
371
+ if @@current_window == 0
372
+ $jssh_socket.send(" getWindows()[0].close(); \n", 0)
373
+ @t.join if @t != nil
374
+ #sleep 5
375
+ else
376
+ # Check if window exists, because there may be the case that it has been closed by click event on some element.
377
+ # For e.g: Close Button, Close this Window link etc.
378
+ window_number = find_window("url", @window_url)
379
+
380
+ # If matching window found. Close the window.
381
+ if(window_number > 0)
382
+ $jssh_socket.send(" getWindows()[#{window_number}].close();\n", 0)
383
+ read_socket();
384
+ end
385
+
386
+ #Get the parent window url from the stack and return that window.
387
+ #@@current_window = @@window_stack.pop()
388
+ @window_url = @@window_stack.pop()
389
+ @window_title = @@window_stack.pop()
390
+ # Find window with this url.
391
+ window_number = find_window("url", @window_url)
392
+ @@current_window = window_number
393
+ set_browser_document()
394
+ end
395
+ end
396
+
397
+ #
398
+ # Description:
399
+ # Used for attaching pop up window to an existing Firefox window, either by url or title.
400
+ # ff.attach(:url, 'http://www.google.com')
401
+ # ff.attach(:title, 'Google')
402
+ #
403
+ # Output:
404
+ # Instance of newly attached window.
405
+ #
406
+ def attach(how, what)
407
+ window_number = find_window(how, what)
408
+
409
+ if(window_number == 0)
410
+ raise NoMatchingWindowFoundException.new("Unable to locate window, using #{how} and #{what}")
411
+ elsif(window_number > 0)
412
+ # Push the window_title and window_url of parent window. So that when we close the child window
413
+ # appropriate handle of parent window is returned back.
414
+ @@window_stack.push(@window_title)
415
+ @@window_stack.push(@window_url)
416
+
417
+ @@current_window = window_number.to_i
418
+ set_browser_document()
419
+ end
420
+ self
421
+ end
422
+
423
+ #
424
+ # Description:
425
+ # Finds a Firefox browser window with a given title or url.
426
+ #
427
+ def find_window(how, what)
428
+ jssh_command = "getWindows().length;";
429
+ $jssh_socket.send("#{jssh_command}\n", 0)
430
+ @@total_windows = read_socket()
431
+ #puts "total windows are : " + @@total_windows.to_s
432
+
433
+ jssh_command = "var windows = getWindows(); var window_number = 0;var found = false;
434
+ for(var i = 0; i < windows.length; i++)
435
+ {
436
+ var attribute = '';
437
+ if(\"#{how}\" == \"url\")
438
+ {
439
+ attribute = windows[i].getBrowser().contentDocument.URL;
440
+ }
441
+ if(\"#{how}\" == \"title\")
442
+ {
443
+ attribute = windows[i].getBrowser().contentDocument.title;
444
+ }"
445
+ if(what.class == Regexp)
446
+ # Construct the regular expression because we can't use it directly by converting it to string.
447
+ # If reg ex is /Google/i then its string conversion will be (?i-mx:Google) so we can't use it.
448
+ # Construct the regular expression again from the string conversion.
449
+ oldRegExp = what.to_s
450
+ newRegExp = "/" + what.source + "/"
451
+ flags = oldRegExp.slice(2, oldRegExp.index(':') - 2)
452
+
453
+ for i in 0..flags.length do
454
+ flag = flags[i, 1]
455
+ if(flag == '-')
456
+ break;
457
+ else
458
+ newRegExp << flag
459
+ end
460
+ end
461
+
462
+ jssh_command += "var regExp = new RegExp(#{newRegExp});
463
+ found = regExp.test(attribute);"
464
+ else
465
+ jssh_command += "found = (attribute == \"#{what}\");"
466
+ end
467
+
468
+ jssh_command += "if(found)
469
+ {
470
+ window_number = i;
471
+ break;
472
+ }
473
+ }
474
+ window_number;"
475
+
476
+ jssh_command.gsub!(/\n/, "")
477
+ #puts "jssh_command is : #{jssh_command}"
478
+ $jssh_socket.send("#{jssh_command}\n", 0)
479
+ window_number = read_socket()
480
+ #puts "window number is : " + window_number.to_s
481
+
482
+ return window_number.to_i
483
+ end
484
+ private :find_window
485
+
486
+ #
487
+ # Description:
488
+ # Matches the given text with the current text shown in the browser.
489
+ #
490
+ # Input:
491
+ # target - Text to match. Can be a string or regex
492
+ #
493
+ # Output:
494
+ # Returns the index if the specified text was found.
495
+ # Returns matchdata object if the specified regexp was found.
496
+ #
497
+ def contains_text(target)
498
+ #puts "Text to match is : #{match_text}"
499
+ #puts "Html is : #{self.text}"
500
+ if target.kind_of? Regexp
501
+ self.text.match(target)
502
+ elsif target.kind_of? String
503
+ self.text.index(target)
504
+ else
505
+ raise ArgumentError, "Argument #{target} should be a string or regexp."
506
+ end
507
+ end
508
+
509
+ #
510
+ # Description:
511
+ # Returns the url of the page currently loaded in the browser.
512
+ #
513
+ # Output:
514
+ # URL of the page.
515
+ #
516
+ def url()
517
+ @window_url
518
+ end
519
+
520
+ #
521
+ # Description:
522
+ # Returns the title of the page currently loaded in the browser.
523
+ #
524
+ # Output:
525
+ # Title of the page.
526
+ #
527
+ def title()
528
+ @window_title
529
+ end
530
+
531
+ #
532
+ # Description:
533
+ # Returns the html of the page currently loaded in the browser.
534
+ #
535
+ # Output:
536
+ # HTML shown on the page.
537
+ #
538
+ def html()
539
+ $jssh_socket.send("var htmlelem = #{DOCUMENT_VAR}.getElementsByTagName('html')[0]; htmlelem.innerHTML;\n", 0)
540
+ #$jssh_socket.send("#{BODY_VAR}.innerHTML;\n", 0)
541
+ result = read_socket()
542
+ return "<html>" + result + "</html>"
543
+ end
544
+
545
+ #
546
+ # Description:
547
+ # Returns the text of the page currently loaded in the browser.
548
+ #
549
+ # Output:
550
+ # Text shown on the page.
551
+ #
552
+ def text()
553
+ $jssh_socket.send("#{BODY_VAR}.textContent;\n", 0)
554
+ return read_socket().strip
555
+ end
556
+
557
+ #
558
+ # Description:
559
+ # Maximize the current browser window.
560
+ #
561
+ def maximize()
562
+ $jssh_socket.send("#{WINDOW_VAR}.maximize();\n", 0)
563
+ read_socket()
564
+ end
565
+
566
+ #
567
+ # Description:
568
+ # Minimize the current browser window.
569
+ #
570
+ def minimize()
571
+ $jssh_socket.send("#{WINDOW_VAR}.minimize();\n", 0)
572
+ read_socket()
573
+ end
574
+
575
+ #
576
+ # Description:
577
+ # Waits for the page to get loaded.
578
+ #
579
+ def wait()
580
+ #puts "In wait function "
581
+ isLoadingDocument = ""
582
+ while isLoadingDocument != "false"
583
+ $jssh_socket.send("#{BROWSER_VAR}=#{WINDOW_VAR}.getBrowser(); #{BROWSER_VAR}.webProgress.isLoadingDocument;\n" , 0)
584
+ isLoadingDocument = read_socket()
585
+ #puts "Is browser still loading page: #{isLoadingDocument}"
586
+ end
587
+
588
+ # Check for Javascript redirect. As we are connected to Firefox via JSSh. JSSh
589
+ # doesn't detect any javascript redirects so check it here.
590
+ # If page redirects to itself that this code will enter in infinite loop.
591
+ # So we currently don't wait for such a page.
592
+ # wait variable in JSSh tells if we should wait more for the page to get loaded
593
+ # or continue. -1 means page is not redirected. Anyother positive values means wait.
594
+ jssh_command = "var wait = -1; var meta = null; meta = #{BROWSER_VAR}.contentDocument.getElementsByTagName('meta');
595
+ if(meta != null)
596
+ {
597
+ var doc_url = #{BROWSER_VAR}.contentDocument.URL;
598
+ for(var i=0; i< meta.length;++i)
599
+ {
600
+ var content = meta[i].content;
601
+ var regex = new RegExp(\"^refresh$\", \"i\");
602
+ if(regex.test(meta[i].httpEquiv))
603
+ {
604
+ var arrContent = content.split(';');
605
+ var redirect_url = null;
606
+ if(arrContent.length > 0)
607
+ {
608
+ if(arrContent.length > 1)
609
+ redirect_url = arrContent[1];
610
+
611
+ if(redirect_url != null)
612
+ {
613
+ regex = new RegExp(\"^.*\" + redirect_url + \"$\");
614
+ if(!regex.test(doc_url))
615
+ {
616
+ wait = arrContent[0];
617
+ }
618
+ }
619
+ break;
620
+ }
621
+ }
622
+ }
623
+ }
624
+ wait;"
625
+ #puts "command in wait is : #{jssh_command}"
626
+ jssh_command = jssh_command.gsub(/\n/, "")
627
+ $jssh_socket.send("#{jssh_command}; \n", 0)
628
+ wait_time = read_socket();
629
+ #puts "wait time is : #{wait_time}"
630
+ begin
631
+ wait_time = wait_time.to_i
632
+ if(wait_time != -1)
633
+ sleep(wait_time)
634
+ # Call wait again. In case there are multiple redirects.
635
+ $jssh_socket.send("#{BROWSER_VAR} = #{WINDOW_VAR}.getBrowser(); \n",0)
636
+ read_socket()
637
+ wait()
638
+ end
639
+ rescue
640
+ end
641
+ set_browser_document()
642
+ end
643
+
644
+ #def jspopup_appeared(popupText = "", wait = 2)
645
+ # winHelper = WindowHelper.new()
646
+ # return winHelper.hasPopupAppeared(popupText, wait)
647
+ #end
648
+
649
+ #
650
+ # Description:
651
+ # Redefines the alert and confirm methods on the basis of button to be clicked.
652
+ # This is done so that JSSh doesn't get blocked. You should use click_no_wait method before calling this function.
653
+ #
654
+ # Typical Usage:
655
+ # ff.button(:id, "button").click_no_wait
656
+ # ff.click_jspopup_button("OK")
657
+ #
658
+ # Input:
659
+ # button - JavaScript button to be clicked. Values can be OK or Cancel
660
+ #
661
+ #def click_jspopup_button(button)
662
+ # button = button.downcase
663
+ # element = Element.new(nil)
664
+ # element.click_js_popup(button)
665
+ #end
666
+
667
+ #
668
+ # Description:
669
+ # Tells FireWatir to click javascript button in case one comes after performing some action on an element. Matches
670
+ # text of pop up with one if supplied as parameter. If text matches clicks the button else stop script execution until
671
+ # pop up is dismissed by manual intervention.
672
+ #
673
+ # Input:
674
+ # button - JavaScript button to be clicked. Values can be OK or Cancel
675
+ # waitTime - Time to wait for pop up to come. Not used just for compatibility with Watir.
676
+ # userInput - Not used just for compatibility with Watir
677
+ # text - Text that should appear on pop up.
678
+ #
679
+ def startClicker(button, waitTime = 1, userInput = nil, text = nil)
680
+ jssh_command = "var win = #{BROWSER_VAR}.contentWindow;"
681
+ if(button =~ /ok/i)
682
+ jssh_command += "var popuptext = '';
683
+ var old_alert = win.alert;
684
+ var old_confirm = win.confirm;
685
+ win.alert = function(param) {"
686
+ if(text != nil)
687
+ jssh_command += "if(param == \"#{text}\") {
688
+ popuptext = param;
689
+ return true;
690
+ }
691
+ else {
692
+ popuptext = param;
693
+ win.alert = old_alert;
694
+ win.alert(param);
695
+ }"
696
+ else
697
+ jssh_command += "popuptext = param; return true;"
698
+ end
699
+ jssh_command += "};
700
+ win.confirm = function(param) {"
701
+ if(text != nil)
702
+ jssh_command += "if(param == \"#{text}\") {
703
+ popuptext = param;
704
+ return true;
705
+ }
706
+ else {
707
+ win.confirm = old_confirm;
708
+ win.confirm(param);
709
+ }"
710
+ else
711
+ jssh_command += "popuptext = param; return true;"
712
+ end
713
+ jssh_command += "};"
714
+
715
+ elsif(button =~ /cancel/i)
716
+ jssh_command = "var old_confirm = win.confirm;
717
+ win.confirm = function(param) {"
718
+ if(text != nil)
719
+ jssh_command += "if(param == \"#{text}\") {
720
+ popuptext = param;
721
+ return false;
722
+ }
723
+ else {
724
+ win.confirm = old_confirm;
725
+ win.confirm(param);
726
+ }"
727
+ else
728
+ jssh_command += "popuptext = param; return false;"
729
+ end
730
+ jssh_command += "};"
731
+ end
732
+ jssh_command.gsub!(/\n/, "")
733
+ #puts "jssh command sent for js pop up is : #{jssh_command}"
734
+ $jssh_socket.send("#{jssh_command}\n", 0)
735
+ read_socket()
736
+ end
737
+
738
+ #
739
+ # Description:
740
+ # Returns text of javascript pop up in case it comes.
741
+ #
742
+ # Output:
743
+ # Text shown in javascript pop up.
744
+ #
745
+ def get_popup_text()
746
+ $jssh_socket.send("popuptext;\n", 0)
747
+ return_value = read_socket()
748
+ # reset the variable
749
+ $jssh_socket.send("popuptext = '';\n", 0)
750
+ read_socket()
751
+ return return_value
752
+ end
753
+
754
+ #
755
+ # Description:
756
+ # Returns the document element of the page currently loaded in the browser.
757
+ #
758
+ # Output:
759
+ # Document element.
760
+ #
761
+ def document
762
+ Document.new("#{DOCUMENT_VAR}")
763
+ end
764
+
765
+ #
766
+ # Description:
767
+ # Returns the first element that matches the xpath query.
768
+ #
769
+ # Input:
770
+ # Xpath expression or query.
771
+ #
772
+ # Output:
773
+ # Element matching the xpath query.
774
+ #
775
+ def element_by_xpath(xpath)
776
+ temp = Element.new(nil, self)
777
+ element_name = temp.element_by_xpath(self, xpath)
778
+ return element_factory(element_name)
779
+ end
780
+
781
+ #
782
+ # Description:
783
+ # Factory method to create object of correct Element class while using XPath to get the element.
784
+ #
785
+ def element_factory(element_name)
786
+ jssh_type = Element.new(element_name,self).element_type
787
+ #puts "jssh type is : #{jssh_type}" # DEBUG
788
+ candidate_class = jssh_type =~ /HTML(.*)Element/ ? $1 : ''
789
+ #puts candidate_class # DEBUG
790
+ if candidate_class == 'Input'
791
+ $jssh_socket.send("#{element_name}.type;\n", 0)
792
+ input_type = read_socket().downcase.strip
793
+ puts input_type # DEBUG
794
+ firewatir_class = input_class(input_type)
795
+ else
796
+ firewatir_class = jssh2firewatir(candidate_class)
797
+ end
798
+
799
+ #puts firewatir_class # DEBUG
800
+ klass = Kernel.const_get(firewatir_class)
801
+
802
+ if klass == Element
803
+ klass.new(element_name,self)
804
+ elsif klass == CheckBox
805
+ klass.new(self,:jssh_name,element_name,["checkbox"])
806
+ elsif klass == Radio
807
+ klass.new(self,:jssh_name,element_name,["radio"])
808
+ else
809
+ klass.new(self,:jssh_name,element_name)
810
+ end
811
+ end
812
+ private :element_factory
813
+
814
+ #
815
+ # Description:
816
+ # Get the class name for element of input type depending upon its type like checkbox, radio etc.
817
+ #
818
+ def input_class(input_type)
819
+ hash = {
820
+ 'select-one' => 'SelectList',
821
+ 'select-multiple' => 'SelectList',
822
+ 'text' => 'TextField',
823
+ 'password' => 'TextField',
824
+ 'textarea' => 'TextField',
825
+ # TODO when there's no type, it's a TextField
826
+ 'file' => 'FileField',
827
+ 'checkbox' => 'CheckBox',
828
+ 'radio' => 'Radio',
829
+ 'reset' => 'Button',
830
+ 'button' => 'Button',
831
+ 'submit' => 'Button',
832
+ 'image' => 'Button'
833
+ }
834
+ hash.default = 'Element'
835
+
836
+ hash[input_type]
837
+ end
838
+ private :input_class
839
+
840
+ #
841
+ # Description:
842
+ # Converts element type returned by JSSh like HTMLDivElement to its corresponding class in Firewatir.
843
+ #
844
+ def jssh2firewatir(candidate_class)
845
+ hash = {
846
+ 'Div' => 'Div',
847
+ 'Button' => 'Button',
848
+ 'Frame' => 'Frame',
849
+ 'Span' => 'Span',
850
+ 'Paragraph' => 'P',
851
+ 'Label' => 'Label',
852
+ 'Form' => 'Form',
853
+ 'Image' => 'Image',
854
+ 'Table' => 'Table',
855
+ 'TableCell' => 'TableCell',
856
+ 'TableRow' => 'TableRow',
857
+ 'Select' => 'SelectList',
858
+ 'Link' => 'Link',
859
+ 'Anchor' => 'Link' # FIXME is this right?
860
+ #'Option' => 'Option' #Option uses a different constructor
861
+ }
862
+ hash.default = 'Element'
863
+ hash[candidate_class]
864
+ end
865
+ private :jssh2firewatir
866
+
867
+ #
868
+ # Description:
869
+ # Returns the array of elements that matches the xpath query.
870
+ #
871
+ # Input:
872
+ # Xpath expression or query.
873
+ #
874
+ # Output:
875
+ # Array of elements matching xpath query.
876
+ #
877
+ def elements_by_xpath(xpath)
878
+ element = Element.new(nil, self)
879
+ elem_names = element.elements_by_xpath(self, xpath)
880
+ a = elem_names.inject([]) {|elements,name| elements << element_factory(name)}
881
+ end
882
+
883
+ #
884
+ # Description:
885
+ # Show all the forms available on the page.
886
+ #
887
+ # Output:
888
+ # Name, id, method and action of all the forms available on the page.
889
+ #
890
+ def show_forms
891
+ forms = Document.new(self).get_forms()
892
+ count = forms.length
893
+ puts "There are #{count} forms"
894
+ for i in 0..count - 1 do
895
+ puts "Form name: " + forms[i].name
896
+ puts " id: " + forms[i].id
897
+ puts " method: " + forms[i].attribute_value("method")
898
+ puts " action: " + forms[i].action
899
+ end
900
+ end
901
+ alias showForms show_forms
902
+
903
+ #
904
+ # Description:
905
+ # Show all the images available on the page.
906
+ #
907
+ # Output:
908
+ # Name, id, src and index of all the images available on the page.
909
+ #
910
+ def show_images
911
+ images = Document.new(self).get_images
912
+ puts "There are #{images.length} images"
913
+ index = 1
914
+ images.each do |l|
915
+ puts "image: name: #{l.name}"
916
+ puts " id: #{l.id}"
917
+ puts " src: #{l.src}"
918
+ puts " index: #{index}"
919
+ index += 1
920
+ end
921
+ end
922
+ alias showImages show_images
923
+
924
+ #
925
+ # Description:
926
+ # Show all the links available on the page.
927
+ #
928
+ # Output:
929
+ # Name, id, href and index of all the links available on the page.
930
+ #
931
+ def show_links
932
+ links = Document.new(self).get_links
933
+ puts "There are #{links.length} links"
934
+ index = 1
935
+ links.each do |l|
936
+ puts "link: name: #{l.name}"
937
+ puts " id: #{l.id}"
938
+ puts " href: #{l.href}"
939
+ puts " index: #{index}"
940
+ index += 1
941
+ end
942
+ end
943
+ alias showLinks show_links
944
+
945
+ #
946
+ # Description:
947
+ # Show all the divs available on the page.
948
+ #
949
+ # Output:
950
+ # Name, id, class and index of all the divs available on the page.
951
+ #
952
+ def show_divs
953
+ divs = Document.new(self).get_divs
954
+ puts "There are #{divs.length} divs"
955
+ index = 1
956
+ divs.each do |l|
957
+ puts "div: name: #{l.name}"
958
+ puts " id: #{l.id}"
959
+ puts " class: #{l.className}"
960
+ puts " index: #{index}"
961
+ index += 1
962
+ end
963
+ end
964
+ alias showDivs show_divs
965
+
966
+ #
967
+ # Description:
968
+ # Show all the tables available on the page.
969
+ #
970
+ # Output:
971
+ # Id, row count, column count (only first row) and index of all the tables available on the page.
972
+ #
973
+ def show_tables
974
+ tables = Document.new(self).get_tables
975
+ puts "There are #{tables.length} tables"
976
+ index = 1
977
+ tables.each do |l|
978
+ puts "table: id: #{l.id}"
979
+ puts " rows: #{l.row_count}"
980
+ puts " columns: #{l.column_count}"
981
+ puts " index: #{index}"
982
+ index += 1
983
+ end
984
+ end
985
+ alias showTables show_tables
986
+
987
+ #
988
+ # Description:
989
+ # Show all the pre elements available on the page.
990
+ #
991
+ # Output:
992
+ # Id, name and index of all the pre elements available on the page.
993
+ #
994
+ def show_pres
995
+ pres = Document.new(self).get_pres
996
+ puts "There are #{pres.length} pres"
997
+ index = 1
998
+ pres.each do |l|
999
+ puts "pre: id: #{l.id}"
1000
+ puts " name: #{l.name}"
1001
+ puts " index: #{index}"
1002
+ index += 1
1003
+ end
1004
+ end
1005
+ alias showPres show_pres
1006
+
1007
+ #
1008
+ # Description:
1009
+ # Show all the spans available on the page.
1010
+ #
1011
+ # Output:
1012
+ # Name, id, class and index of all the spans available on the page.
1013
+ #
1014
+ def show_spans
1015
+ spans = Document.new(self).get_spans
1016
+ puts "There are #{spans.length} spans"
1017
+ index = 1
1018
+ spans.each do |l|
1019
+ puts "span: name: #{l.name}"
1020
+ puts " id: #{l.id}"
1021
+ puts " class: #{l.className}"
1022
+ puts " index: #{index}"
1023
+ index += 1
1024
+ end
1025
+ end
1026
+ alias showSpans show_spans
1027
+
1028
+ #
1029
+ # Description:
1030
+ # Show all the labels available on the page.
1031
+ #
1032
+ # Output:
1033
+ # Name, id, for and index of all the labels available on the page.
1034
+ #
1035
+ def show_labels
1036
+ labels = Document.new(self).get_labels
1037
+ puts "There are #{labels.length} labels"
1038
+ index = 1
1039
+ labels.each do |l|
1040
+ puts "label: name: #{l.name}"
1041
+ puts " id: #{l.id}"
1042
+ puts " for: #{l.for}"
1043
+ puts " index: #{index}"
1044
+ index += 1
1045
+ end
1046
+ end
1047
+ alias showLabels show_labels
1048
+
1049
+ #
1050
+ # Description:
1051
+ # Show all the frames available on the page. Doesn't show nested frames.
1052
+ #
1053
+ # Output:
1054
+ # Name, and index of all the frames available on the page.
1055
+ #
1056
+ def show_frames
1057
+ jssh_command = "var frameset = #{WINDOW_VAR}.frames;
1058
+ var elements_frames = new Array();
1059
+ for(var i = 0; i < frameset.length; i++)
1060
+ {
1061
+ var frames = frameset[i].frames;
1062
+ for(var j = 0; j < frames.length; j++)
1063
+ {
1064
+ elements_frames.push(frames[j].frameElement);
1065
+ }
1066
+ }
1067
+ elements_frames.length;"
1068
+
1069
+ jssh_command.gsub!("\n", "")
1070
+ $jssh_socket.send("#{jssh_command};\n", 0)
1071
+ length = read_socket().to_i
1072
+
1073
+ puts "There are #{length} frames"
1074
+
1075
+ frames = Array.new(length)
1076
+ for i in 0..length - 1 do
1077
+ frames[i] = Frame.new(self, :jssh_name, "elements_frames[#{i}]")
1078
+ end
1079
+
1080
+ for i in 0..length - 1 do
1081
+ puts "frame: name: #{frames[i].name}"
1082
+ puts " index: #{i+1}"
1083
+ end
1084
+ end
1085
+ alias showFrames show_frames
1086
+
1087
+ end # Class Firefox
1088
+
1089
+ #
1090
+ # Module for handling the Javascript pop-ups. Not in use currently, will be available in future.
1091
+ # Use ff.startClicker() method for clicking javascript pop ups. Refer to unit tests on how to handle
1092
+ # javascript pop up (unittests/javascript_test.rb)
1093
+ #module Dialog
1094
+ # # Class for handling javascript popup. Not in use currently, will be available in future. See unit tests on how to handle
1095
+ # # javascript pop up (unittests/javascript_test.rb).
1096
+ # class JSPopUp
1097
+ # include Container
1098
+ #
1099
+ # def has_appeared(text)
1100
+ # require 'socket'
1101
+ # sleep 4
1102
+ # shell = TCPSocket.new("localhost", 9997)
1103
+ # read_socket(shell)
1104
+ # #jssh_command = "var url = #{DOCUMENT_VAR}.URL;"
1105
+ # jssh_command = "var length = getWindows().length; var win;length;\n"
1106
+ # #jssh_command += "for(var i = 0; i < length; i++)"
1107
+ # #jssh_command += "{"
1108
+ # #jssh_command += " win = getWindows()[i];"
1109
+ # #jssh_command += " if(win.opener != null && "
1110
+ # #jssh_command += " win.title == \"[JavaScript Application]\" &&"
1111
+ # #jssh_command += " win.opener.document.URL == url)"
1112
+ # #jssh_command += " {"
1113
+ # #jssh_command += " break;"
1114
+ # #jssh_command += " }"
1115
+ # #jssh_command += "}"
1116
+ #
1117
+ # #jssh_command += " win.title;\n";
1118
+ # #jssh_command += "var dialog = win.document.childNodes[0];"
1119
+ # #jssh_command += "vbox = dialog.childNodes[1].childNodes[1];"
1120
+ # #jssh_command += "vbox.childNodes[1].childNodes[0].childNodes[0].textContent;\n"
1121
+ # puts jssh_command
1122
+ # shell.send("#{jssh_command}", 0)
1123
+ # jstext = read_socket(shell)
1124
+ # puts jstext
1125
+ # return jstext == text
1126
+ # end
1127
+ # end
1128
+ #end
1129
+
1130
+ end